Compare commits

...

35 Commits

Author SHA1 Message Date
Chee Yee 0bd0a0f273 disable modal dialog mode 2024-02-16 02:19:45 -08:00
Chee Yee bf3f4330c0 add progress meter for file extraction and pkg install 2024-02-16 02:11:05 -08:00
Chee Yee f16850fed9 more bug fixes for install patch/dlc from remote 2024-02-16 01:19:27 -08:00
cy33hc a30a20f6db Update README.md 2024-02-15 21:47:57 -08:00
cy33hc 54b9a80410 Update README.md 2024-02-15 10:53:22 -08:00
Chee Yee fe55ddeb8a fix install of some patch/dlc pkg 2024-02-15 04:01:42 -08:00
Chee Yee a5a5f8d611 fix 2024-02-12 16:03:21 -08:00
Chee Yee 9854437c94 add support for realdebrid 2024-02-10 23:57:52 -08:00
Chee Yee 7a908ebf1b improve speed of installing from compress file by increase read buffer 2024-02-10 00:27:18 -08:00
Chee Yee f83629d107 add ability to install pkg in compress file on public shares like mediafire, gdrive, pixeldrain and alldebrid 2024-02-09 21:31:59 -08:00
Chee Yee f0c0213940 fix file list navigration jumping to top of list when last item is selected 2024-02-07 23:54:25 -08:00
Chee Yee 9baf6c18fa enable extracting compress files from http servers 2024-02-07 07:38:54 -08:00
Chee Yee 263822ef66 update to install all pkgs inside compress file 2024-02-07 02:28:44 -08:00
Chee Yee 487e288635 fix rclone filesize display 2024-02-06 23:40:17 -08:00
Chee Yee 267551c979 add ability to install pkg inside compress files 2024-02-03 18:58:42 -08:00
Chee Yee b761596fe3 set extract folder to current local directory on multi select 2024-01-31 02:16:54 -08:00
Chee Yee 99568b9990 update logic for selecting default extract folder 2024-01-31 02:13:32 -08:00
Chee Yee 414a8a4b50 add ability to extract files from remote server 2024-01-31 01:47:51 -08:00
Chee Yee 628312360c clear multi selection after uploading files 2024-01-24 23:19:55 -08:00
Chee Yee b4f6a8f763 add compatibility with PS5 etaHEN ftp server 2024-01-24 20:57:35 -08:00
cy33hc acfdd00f4f Update README.md 2024-01-24 08:10:55 -08:00
Chee Yee ac55a1e5a6 add 1 more compress format to webui 2024-01-24 07:48:33 -08:00
Chee Yee ffdfa6d04d add new compression formats to web ui 2024-01-24 07:45:08 -08:00
Chee Yee 7855c9a7f4 add option to change language 2024-01-23 22:19:59 -08:00
Chee Yee f4625bce73 increase max ftp filename length to 255 2024-01-23 18:06:57 -08:00
Chee Yee 6b0808e48f add Ukrainian lang 2024-01-23 18:06:11 -08:00
Chee Yee e8eb3fa9da rebuild with support for all password protected zip files 2024-01-15 17:34:21 -08:00
Chee Yee df6a068bd3 add support for more compress formats and password protected archive 2024-01-13 19:48:07 -08:00
Chee Yee c1307d4221 fix crash for invalid smb url 2024-01-08 18:06:09 -08:00
Chee Yee 832c60862b display title name instead of id during install 2023-11-16 23:22:57 -08:00
Chee Yee 529d88af06 remove old hash from map 2023-08-30 13:37:17 -07:00
Chee Yee d26baf817e update readme 2023-08-30 08:34:22 -07:00
Chee Yee 01f2f44942 add ability to install via alldebrid 2023-08-30 02:30:26 -07:00
Chee Yee e28e562a10 add ability to install shared URL from web interface 2023-08-06 17:53:27 -07:00
Chee Yee 83661c7fcb add rclone http server support 2023-08-01 22:11:05 -07:00
54 changed files with 3561 additions and 681 deletions
+16 -1
View File
@@ -40,6 +40,15 @@ add_executable(ezremote_client
source/clients/smbclient.cpp
source/clients/webdavclient.cpp
source/clients/sftpclient.cpp
source/clients/rclone.cpp
source/filehost/alldebrid.cpp
source/filehost/realdebrid.cpp
source/filehost/directhost.cpp
source/filehost/gdrive.cpp
source/filehost/filehost.cpp
source/filehost/1fichier.cpp
source/filehost/mediafire.cpp
source/filehost/pixeldrain.cpp
source/server/http_server.cpp
source/actions.cpp
source/config.cpp
@@ -58,11 +67,12 @@ add_executable(ezremote_client
source/textures.cpp
source/windows.cpp
source/zip_util.cpp
source/split_file.cpp
)
add_self(ezremote_client)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.10" 32 0)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.18" 32 0)
target_link_libraries(ezremote_client
c
@@ -85,6 +95,11 @@ target_link_libraries(ezremote_client
minizip
un7zip
unrar
bz2
b2
lzma
lz4
archive
json-c
ssh2
kernel
+4 -2
View File
@@ -1,6 +1,6 @@
# ezRemote Client
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB, NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB(Windows Share), NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
**New:** As of version 1.0.8, ezRemote Client has a Web Interface that can be access from any modern browser to manage the PS4 files.
@@ -27,7 +27,7 @@ To distinguish between FTP, SMB, NFS, WebDAV or HTTP, the URL must be prefix wit
then in the password field enter file:///data/ezremote-client
```
- The url format for SMB is
- The url format for SMB(Windows Share) is
```
smb://hostname[:port]/sharename
@@ -114,6 +114,7 @@ Remote Package Installation with all Remote Server, even if they are password pr
- Upload files to the PS4
- Download files from the PS4
- Install packages on the PS4
- Install packages from shared links from mediafire, google and pixeldrain. For other filehost, they can installed via AllDebrid/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.
@@ -171,6 +172,7 @@ Romanian
Ryukyuan
Thai
Turkish
Ukrainian
```
User must modify the file **/data/ezremote-client/config.ini** located in the ps4 hard drive and update the **language** setting to with the **exact** values from the list above.
+1
View File
@@ -41,6 +41,7 @@
permissionsUrl: '/__local__/permission',
installUrl: '/__local__/install',
uploadResumeSizeUrl: '__local__/uploadResumeSize',
installUrlUrl: '/__local__/install_url',
multipleDownloadFileName: 'ezremote-client.zip',
isExtractableFilePattern: /\.(7z|rar|zip)$/i,
pickCallback: function (item) {
+11 -1
View File
@@ -82,7 +82,7 @@ STR_ONETIME_URL=One Time Url
STR_NOT_A_VALID_PACKAGE=Not a valid Package
STR_WAIT_FOR_INSTALL_MSG=Waiting for Package to finish installing
STR_FAIL_INSTALL_TMP_PKG_MSG=Failed to install pkg file. Please delete the tmp pkg manually
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain google download URL
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain download URL
STR_AUTO_DELETE_TMP_PKG=Auto delete temporary downloaded pkg file after install
STR_PROTOCOL_NOT_SUPPORTED=Protocol not supported
STR_COULD_NOT_RESOLVE_HOST=Could not resolve hostname
@@ -150,3 +150,13 @@ STR_WEB_SERVER=Web Server
STR_ENABLE=Enable
STR_COMPRESSED_FILE_PATH=Compressed Files Location
STR_COMPRESSED_FILE_PATH_MSG=Location of where compressed files are stored on the web server
STR_ALLDEBRID=AllDebrid
STR_API_KEY=API Key
STR_CANT_EXTRACT_URL_MSG=Couldn't extract download url
STR_FAIL_INSTALL_FROM_URL_MSG=Failed to install from URL
STR_INVALID_URL=InValid URL
STR_ALLDEBRID_API_KEY_MISSING_MSG=To use this function, an API Key needs to be configured in the ezRemote Client settings
STR_LANGUAGE=Language
STR_TEMP_DIRECTORY=Temp Directory
STR_REALDEBRID=Real-Debrid
STR_BACKGROUND_INSTALL_INPROGRESS=Package install is running in the background. Don't close the app while install is in progress
+132
View File
@@ -0,0 +1,132 @@
STR_CONNECTION_SETTINGS=Налаштування підключення
STR_SITE=Сайт
STR_LOCAL=Локальний
STR_REMOTE=Дистанційний
STR_MESSAGES=Повідомлення
STR_UPDATE_SOFTWARE=Оновлення ПО
STR_CONNECT=Підключитися
STR_DISCONNECT=Від'єднатися
STR_SEARCH=Пошук
STR_REFRESH=Оновити
STR_SERVER=Сервер
STR_USERNAME=Ім'я користувача
STR_PASSWORD=Пароль
STR_PORT=Порт
STR_PASV=Пасв
STR_DIRECTORY=Каталог
STR_FILTER=Фільтир
STR_YES=Так
STR_NO=Ні
STR_CANCEL=Відмінити
STR_CONTINUE=Продовжити
STR_CLOSE=Закрити
STR_FOLDER=Тека
STR_FILE=Файл
STR_TYPE=Тип
STR_NAME=Ім'я
STR_SIZE=Розмір
STR_DATE=Дата
STR_NEW_FOLDER=Нова тека
STR_RENAME=Перейменувати
STR_DELETE=Видалити
STR_UPLOAD=Викласти
STR_DOWNLOAD=Завантажити
STR_SELECT_ALL=Вибрати Все
STR_CLEAR_ALL=Очистити Все
STR_UPLOADING=Викладання
STR_DOWNLOADING=Завантаження
STR_OVERWRITE=Перезапис
STR_DONT_OVERWRITE=Не Перезаписувати
STR_ASK_FOR_CONFIRM=Запросити Підтвердження
STR_DONT_ASK_CONFIRM=Не Запрошувати Підтвердження
STR_ALLWAYS_USE_OPTION=Завжди використовувати цю опцію і не перепитувати
STR_ACTIONS=Дії
STR_CONFIRM=Підтвердити
STR_OVERWRITE_OPTIONS=Налаштування Перезапису
STR_PROPERTIES=Властивості
STR_PROGRESS=Прогрес
STR_UPDATES=Оновлення
STR_DEL_CONFIRM_MSG=Ви впевнені що хочете видалити цей файл(и)/теку(и)?
STR_CANCEL_ACTION_MSG=Скасування. Очікування завершення останньої дії
STR_FAIL_UPLOAD_MSG=Помилка при викладанні файлу
STR_FAIL_DOWNLOAD_MSG=Помилка при завантаженні файлу
STR_FAIL_READ_LOCAL_DIR_MSG=Не вдалося прочитати вміст/каталог або тека не існує.
STR_CONNECTION_CLOSE_ERR_MSG=426 З'єднання закрито.
STR_REMOTE_TERM_CONN_MSG=426 Віддалений сервер розірвав з'єднання.
STR_FAIL_LOGIN_MSG=300 Помилка входу. Будь ласка перевірте ім'я користувача або пароль.
STR_FAIL_TIMEOUT_MSG=426 Не вдалося. Тайм-аут з'єднання.
STR_FAIL_DEL_DIR_MSG=Не вдалося видалити каталог.
STR_DELETING=Видалення
STR_FAIL_DEL_FILE_MSG=Не вдалося видалити файл
STR_DELETED=Видалено
STR_LINK=Посилання
STR_SHARE=Поділитися
STR_FAILED=310 Не вдалося
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Не вдалося створити файл локально
STR_INSTALL=Встановити
STR_INSTALLING=Встановлення
STR_INSTALL_SUCCESS=Успішно
STR_INSTALL_FAILED=Не вдалося
STR_INSTALL_SKIPPED=Пропушено
STR_CHECK_HTTP_MSG=Перевірка з'єднання с віддаленим HTTP-сервером
STR_FAILED_HTTP_CHECK=Не вдалося встановити з'єднання з HTTP-сервером
STR_REMOTE_NOT_HTTP=Спроба підключитися не до HTTP-сервера
STR_INSTALL_FROM_DATA_MSG=Пакет не у теці /data або /mnt/usbX
STR_ALREADY_INSTALLED_MSG=Пакет уже встановлено
STR_INSTALL_FROM_URL=Встановити з посилання
STR_CANNOT_READ_PKG_HDR_MSG=Не вдалося прочитати інформацію про заголовок пакета
STR_FAVORITE_URLS=Улюблені посилання
STR_SLOT=Слот
STR_EDIT=Редагувати
STR_ONETIME_URL=Одноразове посилання
STR_NOT_A_VALID_PACKAGE=Недійсний пакет
STR_WAIT_FOR_INSTALL_MSG=Зачекайте на заваршення встановлення пакету
STR_FAIL_INSTALL_TMP_PKG_MSG=Не вдалося встановити файловий пакет. Будь ласка видаліть тимчасовий пакет вручну
STR_AUTO_DELETE_TMP_PKG=Автоматичне видлення тимчасових завантажених пакетів після встановлення
STR_PROTOCOL_NOT_SUPPORTED=Протакол не підтримується
STR_COULD_NOT_RESOLVE_HOST=Не вдалося розпізнати ім'я хоста
STR_EXTRACT=Витяг
STR_EXTRACTING=Витягування
STR_FAILED_TO_EXTRACT=Не вдалося витягнути
STR_EXTRACT_LOCATION=Розташування витягу
STR_COMPRESS=Стиснути
STR_ZIP_FILE_PATH=Ім'я zip-файлу
STR_COMPRESSING=Стискання
STR_ERROR_CREATE_ZIP=Виникла помилка під час створення zip-файлу
STR_UNSUPPORTED_FILE_FORMAT=Непідтримуваний формат стисненого файлу
STR_CUT=Вирізати
STR_COPY=Копіювати
STR_PASTE=Вставит
STR_MOVING=Перемістити
STR_COPYING=Копіювання
STR_FAIL_MOVE_MSG=Не вдалося перемістити файл
STR_FAIL_COPY_MSG=Не вдалося копіювати файл
STR_CANT_MOVE_TO_SUBDIR_MSG=Неможливо перемістити головний каталогдо підкаталогу
STR_CANT_COPY_TO_SUBDIR_MSG=Неможливо копіювати головний каталогдо підкаталогу
STR_UNSUPPORTED_OPERATION_MSG=Операція не підтримується
STR_HTTP_PORT=HTTP Порт
STR_REINSTALL_CONFIRM_MSG=Вміст вже встановлено. Ви хочете продовжити встановлення
STR_REMOTE_NOT_SUPPORT_MSG=Віддалене встановлення пакетів не підтримується захищенимисерверами.
STR_CANNOT_CONNECT_REMOTE_MSG=Віддалений HTTP-сервер недоступний.
STR_DOWNLOAD_INSTALL_MSG=Віддалене встановлення пакета неможливе. Бажаєте замість цього завантажити пакунок і встановити?
STR_CHECKING_REMOTE_SERVER_MSG=Перевірка віддаленого сервера на можливість віддаленого встановлення пакетів.
STR_FILES=Файли
STR_EDITOR=Редактор
STR_SAVE=Зберегти
STR_MAX_EDIT_FILE_SIZE_MSG=Неможливо редагувати файли, розмір яких перевищує
STR_DELETE_LINE=Видалити Виділений Рядок
STR_INSERT_LINE=Вставити нижче виділеного рядка
STR_MODIFIED=Модифіковано
STR_FAIL_GET_TOKEN_MSG=Не вдалося отримати токен доступу від
STR_GET_TOKEN_SUCCESS_MSG=Успішний вхід. Ви можете закрити браузер і повернутися до програми
STR_NEW_FILE=Новий Файл
STR_SETTINGS=Налаштування
STR_GLOBAL=Глобальні
STR_COPY_LINE=Копіювати виділений рядок
STR_PASTE_LINE=Вставити в виділений рядок
STR_SHOW_HIDDEN_FILES=Показати приховані файли
STR_SET_DEFAULT_DIRECTORY=Встановити теку за замовчуванням
STR_SET_DEFAULT_DIRECTORY_MSG=встановлено директорією за замовчуванням
STR_NFS_EXP_PATH_MISSING_MSG=В URL-адресі відсутній шлях до експорту NFS
STR_FAIL_INIT_NFS_CONTEXT=Не вдалося ініціювати контекст NFS
STR_FAIL_MOUNT_NFS_MSG=Не вдалося змонтувати NFS ресурс
File diff suppressed because one or more lines are too long
+163 -86
View File
@@ -14,7 +14,9 @@
#include "clients/npxserve.h"
#include "clients/nfsclient.h"
#include "clients/iis.h"
#include "clients/rclone.h"
#include "clients/sftpclient.h"
#include "filehost/filehost.h"
#include "common.h"
#include "fs.h"
#include "config.h"
@@ -26,6 +28,7 @@
#include "web/request.hpp"
#include "web/urn.hpp"
#include "system.h"
#include "sfo.h"
#include "zip_util.h"
namespace Actions
@@ -462,6 +465,7 @@ namespace Actions
}
activity_inprogess = false;
file_transfering = false;
multi_selected_local_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_REMOTE_FILES;
return NULL;
@@ -706,7 +710,10 @@ namespace Actions
}
else
{
if (INSTALLER::InstallRemotePkg(it->path, &header) == 0)
std::string url = INSTALLER::getRemoteUrl(it->path, true);
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
failed++;
else
success++;
@@ -716,6 +723,37 @@ namespace Actions
skipped++;
}
}
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") ||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz"))
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path, remoteclient);
if (entry != nullptr)
{
while (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int res = pthread_create(&install_data->thread, NULL, ExtractArchivePkg, install_data);
INSTALLER::InstallArchivePkg(entry->filename, install_data);
ArchiveEntry *previos = entry;
entry = ZipUtil::GetNextPackageEntry(entry);
free(previos);
}
success++;
}
else
skipped++;
}
else
skipped++;
}
@@ -740,11 +778,47 @@ namespace Actions
if (res != 0)
{
activity_inprogess = false;
file_transfering = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
}
}
void *ExtractArchivePkg(void *argp)
{
ssize_t len;
char *buffer = (char*) malloc(ARCHIVE_TRANSFER_SIZE);
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) argp;
SplitFile *sp = install_data->split_file;
/* loop over file contents and write to fd */
sp->Open();
while (!install_data->stop_write_thread)
{
len = archive_read_data(install_data->archive_entry->archive, buffer, ARCHIVE_TRANSFER_SIZE);
if (len == 0)
break;
if (len < 0)
{
sprintf(status_message, "error archive_read_data('%s')", install_data->archive_entry->filename.c_str());
break;
}
if (sp->Write(buffer, len) != len)
{
sprintf(status_message, "error write('%s')", install_data->archive_entry->filename.c_str());
break;;
}
}
sp->Close();
free(buffer);
return NULL;
}
void *InstallLocalPkgsThread(void *argp)
{
int failed = 0;
@@ -768,7 +842,7 @@ namespace Actions
{
std::string path = std::string(it->path);
path = Util::ToLower(path);
if (path.size() > 4 && path.substr(path.size() - 4) == ".pkg")
if (Util::EndsWith(path,".pkg"))
{
pkg_header header;
memset(&header, 0, sizeof(header));
@@ -799,6 +873,37 @@ namespace Actions
skipped++;
}
}
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") || Util::EndsWith(path,".7z") ||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz") || Util::EndsWith(path,".tar.bz2") )
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path);
if (entry != nullptr)
{
while (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int res = pthread_create(&install_data->thread, NULL, ExtractArchivePkg, install_data);
INSTALLER::InstallArchivePkg(entry->filename, install_data);
ArchiveEntry *previous = entry;
entry = ZipUtil::GetNextPackageEntry(entry);
free(previous);
}
success++;
}
else
skipped++;
}
else
skipped++;
}
@@ -870,6 +975,49 @@ namespace Actions
}
}
void *ExtractRemoteZipThread(void *argp)
{
FS::MkDirs(extract_zip_folder);
std::vector<DirEntry> files;
if (multi_selected_remote_files.size() > 0)
std::copy(multi_selected_remote_files.begin(), multi_selected_remote_files.end(), std::back_inserter(files));
else
files.push_back(selected_remote_file);
for (std::vector<DirEntry>::iterator it = files.begin(); it != files.end(); ++it)
{
if (stop_activity)
break;
if (!it->isDir)
{
int ret = ZipUtil::Extract(*it, extract_zip_folder, remoteclient);
if (ret == 0)
{
sprintf(status_message, "%s %s", lang_strings[STR_FAILED_TO_EXTRACT], it->name);
sceKernelUsleep(100000);
}
}
}
activity_inprogess = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
selected_action = ACTION_REFRESH_LOCAL_FILES;
return NULL;
}
void ExtractRemoteZips()
{
sprintf(status_message, "%s", "");
int res = pthread_create(&bk_activity_thid, NULL, ExtractRemoteZipThread, NULL);
if (res != 0)
{
file_transfering = false;
activity_inprogess = false;
multi_selected_remote_files.clear();
Windows::SetModalMode(false);
}
}
void *MakeZipThread(void *argp)
{
zipFile zf = zipOpen64(zip_file_path, APPEND_STATUS_CREATE);
@@ -918,87 +1066,6 @@ namespace Actions
}
}
std::string GetGoogleDownloadUrl(std::string &url)
{
size_t scheme_pos = url.find_first_of("://");
size_t path_pos = url.find_first_of("/", scheme_pos + 3);
std::string host = url.substr(0, path_pos);
std::string path = url.substr(path_pos);
std::string first_download_path;
size_t file_id_start_pos = path.find("/file/d/");
if (file_id_start_pos != std::string::npos)
{
file_id_start_pos = file_id_start_pos + 8;
std::string file_id = path.substr(file_id_start_pos);
size_t file_id_end_pos = file_id.find_first_of("/");
file_id = file_id.substr(0, file_id_end_pos);
first_download_path = "/uc?export=download&id=" + file_id;
}
else if (path.find("/uc?export=download") != std::string::npos)
{
first_download_path = path;
}
else
{
return "";
}
WebDAV::WebDavClient tmp_client;
tmp_client.Connect(host.c_str(), "", "", false);
WebDAV::dict_t headers;
tmp_client.GetHeaders(first_download_path.c_str(), &headers);
std::string content_type = WebDAV::get(headers, "content-type");
if (content_type.find("application/octet-stream") != std::string::npos)
{
return first_download_path;
}
else if (content_type.find("text/html") == std::string::npos)
{
return "";
}
char *buffer_ptr = nullptr;
unsigned long long buffer_size = 0;
tmp_client.GetClient()->download_to(first_download_path, buffer_ptr, buffer_size);
lxb_status_t status;
lxb_dom_element_t *element;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)buffer_ptr, buffer_size);
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"form", 4);
if (status != LXB_STATUS_OK)
return "";
std::string download_url;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
std::string form_id((char *)element->attr_id->value->data, element->attr_id->value->length);
if (form_id == "download-form")
{
size_t value_len;
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"action", 6, &value_len);
download_url = std::string((char *)value, value_len);
break;
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return download_url;
}
void *InstallUrlPkgThread(void *argp)
{
bytes_transfered = 0;
@@ -1012,8 +1079,16 @@ namespace Actions
sprintf(filename, "%s/%lu.pkg", DATA_PATH, tick.mytick);
std::string full_url = std::string(install_pkg_url.url);
if (full_url.find("https://drive.google.com") != std::string::npos)
full_url = GetGoogleDownloadUrl(full_url);
FileHost *filehost = FileHost::getFileHost(full_url);
if (!filehost->IsValidUrl())
{
sprintf(status_message, "%s", lang_strings[STR_FAIL_TO_OBTAIN_GG_DL_MSG]);
activity_inprogess = false;
Windows::SetModalMode(false);
return NULL;
}
full_url = filehost->GetDownloadUrl();
delete(filehost);
if (full_url.empty())
{
@@ -1133,6 +1208,8 @@ namespace Actions
remoteclient = new NginxClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
remoteclient = new NpxServeClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
remoteclient = new RCloneClient();
}
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
{
@@ -1651,7 +1728,7 @@ namespace Actions
OrbisTick tick;
sceRtcGetCurrentClockLocalTime(&now);
sceRtcGetTick(&now, &tick);
sprintf(local_file, "%s/%lu.pkg", DATA_PATH, tick.mytick);
sprintf(local_file, "%s/%lu.pkg", temp_folder, tick.mytick);
sprintf(activity_message, "%s %s to %s", lang_strings[STR_DOWNLOADING], filename.c_str(), local_file);
remoteclient->Size(filename, &bytes_to_download);
+5 -1
View File
@@ -56,7 +56,8 @@ enum ACTIONS
ACTION_VIEW_LOCAL_IMAGE,
ACTION_VIEW_REMOTE_IMAGE,
ACTION_VIEW_LOCAL_PKG,
ACTION_VIEW_REMOTE_PKG
ACTION_VIEW_REMOTE_PKG,
ACTION_EXTRACT_REMOTE_ZIP,
};
enum OverWriteType
@@ -103,6 +104,8 @@ namespace Actions
void *KeepAliveThread(void *argp);
void *ExtractZipThread(void *argp);
void ExtractLocalZips();
void *ExtractRemoteZipThread(void *argp);
void ExtractRemoteZips();
void *MakeZipThread(void *argp);
void MakeLocalZip();
void *MoveLocalFilesThread(void *argp);
@@ -116,6 +119,7 @@ namespace Actions
int DownloadAndInstallPkg(const std::string &filename, pkg_header *header);
void CreateLocalFile(char *filename);
void CreateRemoteFile(char *filename);
void *ExtractArchivePkg(void *argp);
}
#endif
+6 -2
View File
@@ -6,7 +6,7 @@
class Base64
{
public:
static int Encode(const std::string &input, std::string &out)
static int Encode(unsigned char *input, size_t in_len, std::string &out)
{
static constexpr char sEncodingTable[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@@ -18,7 +18,6 @@ public:
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
size_t in_len = input.size();
size_t out_len = 4 * ((in_len + 2) / 3);
out.resize(out_len);
size_t i;
@@ -50,6 +49,11 @@ public:
return 1;
}
static int Encode(const std::string &input, std::string &out)
{
return Encode((unsigned char*)input.data(), input.size(), out);
}
static int Decode(const std::string &input, std::string &out)
{
static constexpr unsigned char kDecodingTable[] = {
+5 -25
View File
@@ -12,26 +12,6 @@ using httplib::Client;
using httplib::Headers;
using httplib::Result;
lxb_dom_node_t *nextChildElement(lxb_dom_element_t *element)
{
lxb_dom_node_t *node = element->node.first_child;
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
node = node->next;
}
return node;
}
lxb_dom_node_t *nextElement(lxb_dom_node_t *node)
{
lxb_dom_node_t *next = node->next;
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
next = next->next;
}
return next;
}
std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
@@ -101,7 +81,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
memset(&entry, 0, sizeof(DirEntry));
element = lxb_dom_collection_element(collection, i);
node = nextChildElement(element);
node = NextChildElement(element);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
@@ -114,7 +94,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
if (tmp_string.compare("td") == 0)
{
// get the child img element
lxb_dom_node_t *img = nextChildElement(lxb_dom_interface_element(node));
lxb_dom_node_t *img = NextChildElement(lxb_dom_interface_element(node));
if (img == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(img), &value_len);
@@ -142,7 +122,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
else continue; // invalid record
// file/folder name
node = nextElement(node);
node = NextElement(node);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
tmp_string = std::string((const char *)value, value_len);
@@ -165,7 +145,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
else continue; // not valid record
// datetime
node = nextElement(node);
node = NextElement(node);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
tmp_string = std::string((const char *)value, value_len);
@@ -195,7 +175,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
else continue; // invalid record
// filesize
node = nextElement(node);
node = NextElement(node);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
tmp_string = std::string((const char *)value, value_len);
+25 -3
View File
@@ -1,5 +1,3 @@
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <fstream>
#include <curl/curl.h>
#include "common.h"
@@ -44,6 +42,30 @@ int BaseClient::Connect(const std::string &url, const std::string &username, con
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("://");
size_t root_pos = url.find("/", scheme_pos + 3);
if (root_pos != std::string::npos)
{
scheme_host_port = url.substr(0, root_pos);
this->base_path = url.substr(root_pos);
}
client = new httplib::Client(scheme_host_port);
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);
client->set_read_timeout(30);
client->enable_server_certificate_verification(false);
if (Ping())
this->connected = true;
return 1;
}
int BaseClient::Mkdir(const std::string &path)
{
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
@@ -282,7 +304,7 @@ ClientType BaseClient::clientType()
uint32_t BaseClient::SupportedActions()
{
return REMOTE_ACTION_DOWNLOAD | REMOTE_ACTION_INSTALL;
return REMOTE_ACTION_DOWNLOAD | REMOTE_ACTION_INSTALL | REMOTE_ACTION_EXTRACT;
}
std::string BaseClient::EncodeUrl(const std::string &url)
+3
View File
@@ -3,6 +3,8 @@
#include <string>
#include <vector>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include "http/httplib.h"
#include "clients/remote_client.h"
#include "http/httplib.h"
@@ -14,6 +16,7 @@ public:
BaseClient();
~BaseClient();
int Connect(const std::string &url, const std::string &username, const std::string &password);
int Connect(const std::string &url, const std::string &api_key);
int Mkdir(const std::string &path);
int Rmdir(const std::string &path, bool recursive);
int Size(const std::string &path, int64_t *size);
+36 -20
View File
@@ -132,14 +132,31 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
return 0;
}
std::string cmd = "USER " + user;
std::string cmd;
if (user.length() > 0)
{
cmd = "USER " + user;
}
else
{
cmd = "USER anonymous";
}
if (!FtpSendCmd(cmd, '3', mp_ftphandle))
{
if (mp_ftphandle->ctrl != NULL)
return 1;
if (*LastResponse() == '2')
{
mp_ftphandle->is_connected = true;
return 1;
return 0;
}
else
{
Quit();
sprintf(mp_ftphandle->response, "%s", lang_strings[STR_FAIL_LOGIN_MSG]);
return 0;
}
}
cmd = "PASS " + pass;
@@ -1276,29 +1293,29 @@ int FtpClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
}
char buf[FTP_CLIENT_BUFSIZ];
int count = 0;
size_t bytes_remaining = size;
int count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(FTP_CLIENT_BUFSIZ, bytes_remaining);
count = FtpRead(buf, bytes_to_read, nData);
if (count > 0)
{
bytes_remaining -= count;
bool ok = sink.write((char*)buf, count);
do
{
size_t bytes_to_read = std::min<size_t>(FTP_CLIENT_BUFSIZ, bytes_remaining);
count = FtpRead(buf, bytes_to_read, nData);
if (count > 0)
{
bytes_remaining -= count;
bool ok = sink.write((char *)buf, count);
if (!ok)
{
FtpClose(nData);
mp_ftphandle->offset = 0;
return 0;
}
}
else
{
break;
}
} while (1);
}
else
{
break;
}
} while (1);
FtpClose(nData);
mp_ftphandle->offset = 0;
@@ -1317,7 +1334,7 @@ int FtpClient::GetRange(const std::string &path, void *buffer, uint64_t size, ui
char buf[8192];
int l = 0;
uint64_t remaining = size;
char *p = (char*) buffer;
char *p = (char *)buffer;
while ((l = FtpRead(buf, 8192, nData)) > 0)
{
if (l <= remaining)
@@ -1336,7 +1353,6 @@ int FtpClient::GetRange(const std::string &path, void *buffer, uint64_t size, ui
mp_ftphandle->offset = 0;
return 1;
}
/*
+1 -1
View File
@@ -9,7 +9,7 @@
#include "clients/remote_client.h"
#include "http/httplib.h"
#define FTP_CLIENT_MAX_FILENAME_LEN 128
#define FTP_CLIENT_MAX_FILENAME_LEN 255
typedef int (*FtpCallbackXfer)(int64_t xfered, void *arg);
+8 -8
View File
@@ -226,7 +226,7 @@ int GDriveClient::Rename(const std::string &src, const std::string &dst)
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);
@@ -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)));
@@ -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"))
{
+224
View File
@@ -0,0 +1,224 @@
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <fstream>
#include "common.h"
#include "clients/remote_client.h"
#include "clients/rclone.h"
#include "lang.h"
#include "util.h"
#include "system.h"
#include "windows.h"
using httplib::Client;
using httplib::Headers;
using httplib::Result;
std::vector<DirEntry> RCloneClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
DirEntry entry;
Util::SetupPreviousFolder(path, &entry);
out.push_back(entry);
std::string encoded_path = httplib::detail::encode_url(GetFullPath(path)+"/");
if (auto res = client->Get(encoded_path))
{
lxb_status_t status;
lxb_dom_attr_t *attr;
lxb_dom_element_t *tbody_element, *tr_element, *td_element;
lxb_html_document_t *document;
lxb_dom_collection_t *tbody_collection;
lxb_dom_collection_t *tr_collection;
lxb_dom_collection_t *td_collection;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
{
lxb_html_document_destroy(document);
goto finish;
}
tbody_collection = lxb_dom_collection_make(&document->dom_document, 1);
if (tbody_collection == NULL)
{
lxb_html_document_destroy(document);
goto finish;
}
tr_collection = lxb_dom_collection_make(&document->dom_document, 128);
if (tbody_collection == NULL)
{
lxb_html_document_destroy(document);
goto finish;
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
tbody_collection, (const lxb_char_t *)"tbody", 5);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
if (lxb_dom_collection_length(tbody_collection) < 1)
{
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
// Get the first tbody which should only be 1
tbody_element = lxb_dom_collection_element(tbody_collection, 0);
status = lxb_dom_elements_by_tag_name(tbody_element,
tr_collection, (const lxb_char_t *)"tr", 2);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
// skip row 0 , since it has the previous folder header
for (size_t i = 1; i < lxb_dom_collection_length(tr_collection); i++)
{
DirEntry entry;
std::string title, aclass;
memset(&entry.modified, 0, sizeof(DateTime));
const lxb_char_t *value;
size_t value_len;
std::string tmp_string;
tr_element = lxb_dom_collection_element(tr_collection, i);
td_collection = lxb_dom_collection_make(&document->dom_document, 5);
status = lxb_dom_elements_by_tag_name(tr_element,
td_collection, (const lxb_char_t *)"td", 2);
if (status != LXB_STATUS_OK || lxb_dom_collection_length(td_collection) < 0)
{
lxb_dom_collection_destroy(td_collection, true);
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
// td 0 is empty, td 1 is file or folder
td_element = lxb_dom_collection_element(td_collection, 1);
lxb_dom_node_t *use_node = NextChildElement(lxb_dom_interface_element(NextChildElement(td_element)));
value = lxb_dom_element_local_name(lxb_dom_interface_element(use_node), &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string.compare("use") != 0)
{
lxb_dom_collection_destroy(td_collection, true);
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(use_node), (const lxb_char_t *)"xlink:href", 10, &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string.compare("#folder") == 0)
{
entry.isDir = true;
entry.selectable = true;
entry.file_size = 0;
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
}
else
{
entry.isDir = false;
entry.selectable = true;
}
// <a> element contains the file/folder name
lxb_dom_node_t *a_node = NextChildElement(lxb_dom_interface_element(NextElement(NextChildElement(td_element))));
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(a_node), (const lxb_char_t *)"href", 4, &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string[tmp_string.length()-1] == '/')
tmp_string = tmp_string.substr(0, tmp_string.length()-1);
tmp_string = BaseClient::DecodeUrl(tmp_string);
sprintf(entry.name, "%s", tmp_string.c_str());
sprintf(entry.directory, "%s", path.c_str());
if (path.length() > 0 && path[path.length() - 1] == '/')
{
sprintf(entry.path, "%s%s", path.c_str(), entry.name);
}
else
{
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
}
// td 3 - filesize
if (!entry.isDir)
{
td_element = lxb_dom_collection_element(td_collection, 2);
lxb_dom_node_t *size_node = NextChildElement(td_element);
value = lxb_dom_node_text_content(size_node->first_child, &value_len);
tmp_string = std::string((const char *)value, value_len);
entry.file_size = atol(tmp_string.c_str());
DirEntry::SetDisplaySize(&entry);
}
// td 4 - datetime
td_element = lxb_dom_collection_element(td_collection, 3);
lxb_dom_node_t *date_node = NextChildElement(td_element);
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(date_node), (const lxb_char_t *)"datetime", 8, &value_len);
tmp_string = std::string((const char *)value, value_len);
std::vector<std::string> date_time = Util::Split(tmp_string, " ");
OrbisDateTime gmt;
OrbisDateTime lt;
if (date_time.size() > 1)
{
std::vector<std::string> adate = Util::Split(date_time[0], "-");
if (adate.size() == 3)
{
gmt.year = atoi(adate[0].c_str());
gmt.month = atoi(adate[1].c_str());
gmt.day = atoi(adate[2].c_str());
}
std::vector<std::string> atime = Util::Split(date_time[1], ":");
if (atime.size() == 3)
{
gmt.hour = atoi(atime[0].c_str());
gmt.minute = atoi(atime[1].c_str());
std::vector<std::string> sec_msec = Util::Split(atime[2], ".");
if (sec_msec.size() > 0)
{
gmt.second = atoi(sec_msec[0].c_str());
}
}
}
convertUtcToLocalTime(&gmt, &lt);
entry.modified.day = lt.day;
entry.modified.month = lt.month;
entry.modified.year = lt.year;
entry.modified.hours = lt.hour;
entry.modified.minutes = lt.minute;
entry.modified.seconds = lt.second;
lxb_dom_collection_destroy(td_collection, true);
out.push_back(entry);
}
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
return out;
}
finish:
return out;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef RCLONE_H
#define RCLONE_H
#include <string>
#include <vector>
#include "http/httplib.h"
#include "clients/baseclient.h"
#include "clients/remote_client.h"
#include "common.h"
class RCloneClient : public BaseClient
{
public:
std::vector<DirEntry> ListDir(const std::string &path);
};
#endif
+2 -1
View File
@@ -20,7 +20,8 @@ enum RemoteActions
REMOTE_ACTION_INSTALL = 256,
REMOTE_ACTION_EDIT = 512,
REMOTE_ACTION_NEW_FILE = 1024,
REMOTE_ACTION_ALL = 2047
REMOTE_ACTION_EXTRACT = 2048,
REMOTE_ACTION_ALL = 4095
};
enum ClientType
+7
View File
@@ -34,7 +34,14 @@ int SmbClient::Connect(const std::string &url, const std::string &user, const st
sprintf(response, "Failed to init SMB context");
return 0;
}
smb_url = smb2_parse_url(smb2, url.c_str());
if (smb_url == NULL || smb_url->share == NULL || strlen(smb_url->share) == 0)
{
sprintf(response, "Invalid SMB Url");
return 0;
}
if (pass.length() > 0)
smb2_set_password(smb2, pass.c_str());
smb2_set_security_mode(smb2, SMB2_NEGOTIATE_SIGNING_ENABLED);
+42
View File
@@ -4,6 +4,8 @@
#include <string>
#include <vector>
#include <string.h>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#define HTTP_SUCCESS(x) (x >= 200 && x < 300)
#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -86,4 +88,44 @@ struct DirEntry
}
};
static lxb_dom_node_t *NextChildElement(lxb_dom_element_t *element)
{
lxb_dom_node_t *node = element->node.first_child;
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
node = node->next;
}
return node;
}
static lxb_dom_node_t *NextElement(lxb_dom_node_t *node)
{
lxb_dom_node_t *next = node->next;
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
next = next->next;
}
return next;
}
static lxb_dom_node_t *NextChildTextNode(lxb_dom_element_t *element)
{
lxb_dom_node_t *node = element->node.first_child;
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_TEXT)
{
node = node->next;
}
return node;
}
static lxb_dom_node_t *NextTextNode(lxb_dom_node_t *node)
{
lxb_dom_node_t *next = node->next;
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_TEXT)
{
next = next->next;
}
return next;
}
#endif
+75 -2
View File
@@ -25,6 +25,7 @@ char remote_directory[255];
char app_ver[6];
char last_site[32];
char display_site[32];
std::vector<std::string> langs;
char language[128];
std::vector<std::string> sites;
std::vector<std::string> http_servers;
@@ -37,6 +38,9 @@ bool auto_delete_tmp_pkg;
int max_edit_file_size;
GoogleAppInfo gg_app;
bool show_hidden_files;
char alldebrid_api_key[64];
char realdebrid_api_key[64];
char temp_folder[256];
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
@@ -151,7 +155,11 @@ namespace CONFIG
sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10",
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE};
langs = { "Default", "Arabic", "Catalan", "Croatian", "Dutch", "English", "Euskera", "French", "Galego", "German", "Greek",
"Hungarian", "Indonesian", "Italiano", "Japanese", "Korean", "Polish", "Portuguese_BR", "Russian", "Romanian", "Ryukyuan", "Spanish", "Turkish",
"Simplified Chinese", "Traditional Chinese", "Thai", "Ukrainian"};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE};
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
@@ -166,7 +174,7 @@ namespace CONFIG
WriteInt(CONFIG_GLOBAL, CONFIG_VERSION, CONFIG_VERSION_NUM);
// Load global config
sprintf(language, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LANGUAGE, ""));
sprintf(language, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LANGUAGE, "Default"));
WriteString(CONFIG_GLOBAL, CONFIG_LANGUAGE, language);
sprintf(local_directory, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, "/"));
@@ -181,6 +189,45 @@ namespace CONFIG
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
// alldebrid api key
char tmp_api_key[512];
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, ""));
std::string encrypted_api_key;
if (strlen(tmp_api_key) > 0)
{
std::string decrypted_api_key;
int ret = Decrypt(tmp_api_key, decrypted_api_key);
if (ret == 0)
sprintf(alldebrid_api_key, "%s", tmp_api_key);
else
sprintf(alldebrid_api_key, "%s", decrypted_api_key.c_str());
Encrypt(alldebrid_api_key, encrypted_api_key);
}
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
// 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);
@@ -355,17 +402,43 @@ namespace CONFIG
Encrypt(gg_app.client_secret, encrypted_secret);
else
encrypted_secret = std::string(gg_app.client_secret);
std::string encrypted_api_key;
if (strlen(alldebrid_api_key) > 0)
Encrypt(alldebrid_api_key, encrypted_api_key);
else
encrypted_api_key = std::string(alldebrid_api_key);
WriteString(CONFIG_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_TMP_FOLDER_PATH, temp_folder);
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
WriteString(CONFIG_GLOBAL, CONFIG_LANGUAGE, language);
WriteInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, http_server_port);
WriteString(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_COMPRESSED_FILE_PATH, compressed_file_path);
WriteBool(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_ENABLED, web_server_enabled);
WriteIniFile(CONFIG_INI_FILE);
CloseIniFile();
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
if (!FS::FolderExists(compressed_file_path))
{
FS::MkDirs(compressed_file_path);
}
}
void SaveLocalDirecotry(const std::string &path)
+10
View File
@@ -17,6 +17,7 @@
#define TMP_EDITOR_FILE DATA_PATH "/tmp_editor.txt"
#define TMP_SFO_PATH DATA_PATH "/tmp_pkg.sfo"
#define TMP_ICON_PATH DATA_PATH "/tmp_icon.png"
#define TMP_FOLDER_PATH DATA_PATH "/tmp"
#define CONFIG_GLOBAL "Global"
@@ -57,6 +58,9 @@
#define CONFIG_REMOTE_HTTP_SERVER_TYPE "remote_server_http_server_type"
#define CONFIG_REMOTE_DEFAULT_DIRECTORY "remote_server_default_directory"
#define CONFIG_ALLDEBRID_API_KEY "alldebrid_api_key"
#define CONFIG_REALDEBRID_API_KEY "realdebrid_api_key"
#define CONFIG_VERSION "config_version"
#define CONFIG_VERSION_NUM 1
@@ -68,6 +72,7 @@
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
#define CONFIG_LOCAL_DIRECTORY "local_directory"
#define CONFIG_TMP_FOLDER_PATH "temp_folder"
#define CONFIG_LANGUAGE "language"
@@ -75,6 +80,7 @@
#define HTTP_SERVER_MS_IIS "Microsoft IIS"
#define HTTP_SERVER_NGINX "Nginx"
#define HTTP_SERVER_NPX_SERVE "Serve"
#define HTTP_SERVER_RCLONE "RClone"
#define MAX_EDIT_FILE_SIZE 32768
@@ -123,6 +129,7 @@ extern char remote_directory[255];
extern char app_ver[6];
extern char last_site[32];
extern char display_site[32];
extern std::vector<std::string> langs;
extern char language[128];
extern RemoteSettings *remote_settings;
extern RemoteClient *remoteclient;
@@ -134,6 +141,9 @@ extern unsigned char cipher_key[32];
extern unsigned char cipher_iv[16];
extern GoogleAppInfo gg_app;
extern bool show_hidden_files;
extern char alldebrid_api_key[64];
extern char realdebrid_api_key[64];
extern char temp_folder[256];
namespace CONFIG
{
+142
View File
@@ -0,0 +1,142 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "1fichier.h"
#define VALIDATION_REGEX "https:\\/\\/1fichier\\.com\\/(.*)"
FichierHost::FichierHost(const std::string &url) : FileHost(url)
{
}
bool FichierHost::IsValidUrl()
{
std::regex regex(VALIDATION_REGEX);
if (std::regex_match(url, regex))
return true;
return false;
}
std::string FichierHost::GetDownloadUrl()
{
std::regex re("https:\\/\\/1fichier\\.com");
std::string path = std::regex_replace(url, re, "");
httplib::Client tmp_client("https://1fichier.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
lxb_status_t status;
lxb_dom_element_t *element;
lxb_dom_node_t *node;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
const lxb_char_t *value;
size_t value_len;
std::string download_url = "";
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"input", 5);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
std::string post_data;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"name", 4, &value_len);
if (value != nullptr)
{
std::string name_attr((char *)value, value_len);
if (name_attr == "adz")
{
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"value", 5, &value_len);
std::string adz_value((char *)value, value_len);
post_data = std::string("adz=") + adz_value + "&did=0&dl_no_ssl=off&dlinline=on";
break;
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
if (auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded"))
{
if (HTTP_SUCCESS(res->status))
{
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"a", 1);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"class", 5, &value_len);
if (value != nullptr)
{
std::string class_value((char*) value, value_len);
if (class_value == "ok btn-general btn-orange")
{
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"href", 4, &value_len);
if (value != nullptr)
{
download_url = std::string((char*) value, value_len);
break;
}
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
}
}
return download_url;
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef FICHIER_HOST_H
#define FICHIER_HOST_H
#include "filehost.h"
class FichierHost : public FileHost
{
public:
FichierHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+64
View File
@@ -0,0 +1,64 @@
#include <http/httplib.h>
#include <json-c/json.h>
#include "config.h"
#include "common.h"
#include "alldebrid.h"
AllDebridHost::AllDebridHost(const std::string &url) : FileHost(url)
{
}
bool AllDebridHost::IsValidUrl()
{
httplib::Client tmp_client("https://api.alldebrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
std::string path = std::string("/v4/link/unlock?agent=ezRemoteClient&apikey=") + alldebrid_api_key + "&link=" + httplib::detail::encode_url(url);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *status = json_object_get_string(json_object_object_get(jobj, "status"));
if (strcmp(status, "success") == 0)
return true;
}
return false;
}
std::string AllDebridHost::GetDownloadUrl()
{
httplib::Client tmp_client("https://api.alldebrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
std::string path = std::string("/v4/link/unlock?agent=ezRemoteClient&apikey=") + alldebrid_api_key + "&link=" + httplib::detail::encode_url(url);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *status = json_object_get_string(json_object_object_get(jobj, "status"));
if (status != nullptr && strcmp(status, "success") == 0)
{
json_object *data = json_object_object_get(jobj, "data");
const char *link = json_object_get_string(json_object_object_get(data, "link"));
return std::string(link);
}
else
{
return "";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef ALLDEBRID_HOST_H
#define ALLDEBRID_HOST_H
#include "filehost.h"
class AllDebridHost : public FileHost
{
public:
AllDebridHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+28
View File
@@ -0,0 +1,28 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "directhost.h"
#define VALIDATION_REGEX "(.*)"
DirectHost::DirectHost(const std::string &url) : FileHost(url)
{
}
bool DirectHost::IsValidUrl()
{
std::regex regex_1(VALIDATION_REGEX);
if (std::regex_match(url, regex_1))
return true;
return false;
}
std::string DirectHost::GetDownloadUrl()
{
return url;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef DIRECT_HOST_H
#define DIRECT_HOST_H
#include "filehost.h"
class DirectHost : public FileHost
{
public:
DirectHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+60
View File
@@ -0,0 +1,60 @@
#include <regex>
#include <string>
#include <vector>
#include <map>
#include "filehost.h"
#include "1fichier.h"
#include "filehost/alldebrid.h"
#include "filehost/realdebrid.h"
#include "filehost/directhost.h"
#include "filehost/gdrive.h"
#include "filehost/mediafire.h"
#include "filehost/pixeldrain.h"
#include "config.h"
#include "util.h"
#define GDRIVE_REGEX "https:\\/\\/drive\\.google\\.com\\/(.*)"
#define MEDIAFIRE_REGEX "https:\\/\\/www\\.mediafire\\.com\\/(.*)"
#define PIXELDRAIN_REGEX "https:\\/\\/pixeldrain\\.com\\/(.*)"
#define FICHIER_REGEX "https:\\/\\/1fichier\\.com\\/(.*)"
static std::map<std::string, std::string> cache_downloal_urls;
std::string FileHost::GetUrl()
{
return url;
}
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);
std::regex pixeldrain_re(PIXELDRAIN_REGEX);
std::regex fichier_re(FICHIER_REGEX);
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))
return new MediaFireHost(url);
else if (std::regex_match(url, pixeldrain_re))
return new PixelDrainHost(url);
else
return new DirectHost(url);
}
std::string FileHost::GetCachedDownloadUrl(std::string &hash)
{
return cache_downloal_urls[hash];
}
void FileHost::AddCacheDownloadUrl(std::string &hash, std::string &url)
{
std::pair<std::string, std::string> pair = std::make_pair(hash, url);
cache_downloal_urls.erase(hash);
cache_downloal_urls.insert(pair);
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef FILEHOST_H
#define FILEHOST_H
#include <string>
#include <vector>
class FileHost
{
public:
FileHost(const std::string &url) { this->url = url; };
virtual ~FileHost(){};
virtual bool IsValidUrl() = 0;
virtual std::string GetDownloadUrl() = 0;
std::string GetUrl();
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);
protected:
std::string url;
};
#endif
+118
View File
@@ -0,0 +1,118 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "gdrive.h"
#define VALIDATION_REGEX_1 "https:\\/\\/drive\\.google\\.com\\/file\\/d\\/(.*)\\/(edit|view)\\?usp=(.*)"
#define VALIDATION_REGEX_2 "https:\\/\\/drive\\.google\\.com\\/(.*)uc\\?(id=|export=)(.*)&(id=|export=)(.*)"
GDriveHost::GDriveHost(const std::string &url) : FileHost(url)
{
}
bool GDriveHost::IsValidUrl()
{
std::regex regex_1(VALIDATION_REGEX_1);
std::regex regex_2(VALIDATION_REGEX_2);
if (std::regex_match(url, regex_1) || std::regex_match(url, regex_2))
return true;
return false;
}
std::string GDriveHost::GetDownloadUrl()
{
std::regex regex_1(VALIDATION_REGEX_1);
std::smatch matches;
std::string path;
if(std::regex_search(url, matches, regex_1))
{
path = std::string("/uc?export=download&id=") + matches[1].str();
}
else
{
std::regex re("https:\\/\\/drive\\.google\\.com");
path = std::regex_replace(url, re, "");
}
httplib::Client tmp_client("https://drive.google.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
auto res = tmp_client.Head(path);
if (HTTP_SUCCESS(res->status))
{
std::string content_type = res->get_header_value("Content-Type");
if (content_type == "application/octet-stream")
return url;
else if (content_type.find("text/html") == std::string::npos)
return "";
}
else
return "";
res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
lxb_status_t status;
lxb_dom_element_t *element;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
{
lxb_html_document_destroy(document);
return "";
}
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"form", 4);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
std::string download_url;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
if (element->attr_id != nullptr)
{
std::string form_id((char *)element->attr_id->value->data, element->attr_id->value->length);
if (form_id == "download-form")
{
size_t value_len;
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"action", 6, &value_len);
download_url = std::string((char *)value, value_len);
break;
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return download_url;
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef GDRIVE_HOST_H
#define GDRIVE_HOST_H
#include "filehost.h"
class GDriveHost : public FileHost
{
public:
GDriveHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+89
View File
@@ -0,0 +1,89 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "mediafire.h"
#define VALIDATION_REGEX "https:\\/\\/www\\.mediafire\\.com\\/file\\/(.*)\\/(.*)\\/file"
MediaFireHost::MediaFireHost(const std::string &url) : FileHost(url)
{
}
bool MediaFireHost::IsValidUrl()
{
std::regex regex(VALIDATION_REGEX);
if (std::regex_match(url, regex))
return true;
return false;
}
std::string MediaFireHost::GetDownloadUrl()
{
std::regex re("https:\\/\\/www\\.mediafire\\.com");
std::string path = std::regex_replace(url, re, "");
httplib::Client tmp_client("https://www.mediafire.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
lxb_status_t status;
lxb_dom_element_t *element;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"a", 1);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
std::string download_url;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
if (element->attr_id != nullptr)
{
std::string a_id((char *)element->attr_id->value->data, element->attr_id->value->length);
if (a_id == "downloadButton")
{
size_t value_len;
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"href", 4, &value_len);
download_url = std::string((char *)value, value_len);
break;
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return download_url;
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef MEDIAFIRE_HOST_H
#define MEDIAFIRE_HOST_H
#include "filehost.h"
class MediaFireHost : public FileHost
{
public:
MediaFireHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+38
View File
@@ -0,0 +1,38 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "pixeldrain.h"
#define VALIDATION_REGEX "https:\\/\\/pixeldrain\\.com\\/u\\/(.*)"
PixelDrainHost::PixelDrainHost(const std::string &url) : FileHost(url)
{
}
bool PixelDrainHost::IsValidUrl()
{
std::regex re(VALIDATION_REGEX);
if (std::regex_match(url, re))
return true;
return false;
}
std::string PixelDrainHost::GetDownloadUrl()
{
std::regex re(VALIDATION_REGEX);
std::smatch matches;
if(std::regex_search(url, matches, re))
{
if (matches.size() > 1)
{
return std::string("https://pixeldrain.com/api/file/") + matches[1].str() + "?download=";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef PIXELDRAIN_HOST_H
#define PIXELDRAIN_HOST_H
#include "filehost.h"
class PixelDrainHost : public FileHost
{
public:
PixelDrainHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+68
View File
@@ -0,0 +1,68 @@
#include <http/httplib.h>
#include <json-c/json.h>
#include "config.h"
#include "common.h"
#include "realdebrid.h"
RealDebridHost::RealDebridHost(const std::string &url) : FileHost(url)
{
}
bool RealDebridHost::IsValidUrl()
{
httplib::Client tmp_client("https://api.real-debrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
tmp_client.set_bearer_token_auth(realdebrid_api_key);
std::string path = std::string("/rest/1.0/unrestrict/check");
std::string post_data = std::string("link=") + httplib::detail::encode_url(this->url) + "&password=";
auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded");
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
uint64_t supported = json_object_get_uint64(json_object_object_get(jobj, "supported"));
if (supported == 1)
return true;
}
return false;
}
std::string RealDebridHost::GetDownloadUrl()
{
httplib::Client tmp_client("https://api.real-debrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
tmp_client.set_bearer_token_auth(realdebrid_api_key);
std::string path = std::string("/rest/1.0/unrestrict/link");
std::string post_data = std::string("link=") + httplib::detail::encode_url(this->url) + "&password=&remote=0";
auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded");
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *download = json_object_get_string(json_object_object_get(jobj, "download"));
if (download != nullptr)
{
return std::string(download);
}
else
{
return "";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef REALDEBRID_HOST_H
#define REALDEBRID_HOST_H
#include "filehost.h"
class RealDebridHost : public FileHost
{
public:
RealDebridHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+1
View File
@@ -1900,6 +1900,7 @@ namespace detail {
std::string encode_query_param(const std::string &value);
std::string encode_url(const std::string &s);
std::string decode_url(const std::string &s, bool convert_plus_to_space);
void read_file(const std::string &path, std::string &out);
+2 -2
View File
@@ -10692,7 +10692,7 @@ void ImGui::NavUpdateCreateMoveRequest()
// When using gamepad, we project the reference nav bounding box into window visible area.
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad all movements are relative
// (can't focus a visible object like we can with the mouse).
if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
/*if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
{
bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;
bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;
@@ -10709,7 +10709,7 @@ void ImGui::NavUpdateCreateMoveRequest()
window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
g.NavId = g.NavFocusScopeId = 0;
}
}
}*/
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
ImRect scoring_rect;
+407 -40
View File
@@ -21,14 +21,25 @@
#include "lang.h"
#include "system.h"
#include "fs.h"
#include "sfo.h"
#include "clients/webdavclient.h"
#include "clients/remote_client.h"
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
struct BgProgressCheck
{
ArchivePkgInstallData* pkg_data;
int task_id;
std::string hash;
};
static OrbisBgftInitParams s_bgft_init_params;
static bool s_bgft_initialized = false;
static std::map<std::string, ArchivePkgInstallData *> archive_pkg_install_data_list;
namespace INSTALLER
{
int Init(void)
@@ -99,6 +110,96 @@ namespace INSTALLER
s_bgft_initialized = false;
}
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header)
{
size_t entry_count = BE32(header->pkg_entry_count);
uint32_t entry_table_offset = BE32(header->pkg_table_offset);
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
void *entry_table_data = malloc(entry_table_size);
int ret = client->GetRange(path, entry_table_data, entry_table_size, entry_table_offset);
if (ret == 0)
{
free(entry_table_data);
return "";
}
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
void* param_sfo_data = nullptr;
uint32_t param_sfo_offset = 0;
uint32_t param_sfo_size = 0;
for (size_t i = 0; i < entry_count; ++i)
{
if (BE32(entries[i].id) == PKG_ENTRY_ID__PARAM_SFO)
{
param_sfo_offset = BE32(entries[i].offset);
param_sfo_size = BE32(entries[i].size);
break;
}
}
free(entry_table_data);
std::string title;
if (param_sfo_offset > 0 && param_sfo_size > 0)
{
param_sfo_data = malloc(param_sfo_size);
int ret = client->GetRange(path, param_sfo_data, param_sfo_size, param_sfo_offset);
if (ret)
{
const char* tmp_title = SFO::GetString((const char*)param_sfo_data, param_sfo_size, "TITLE");
if (tmp_title != nullptr)
title = std::string(tmp_title);
}
free(param_sfo_data);
}
return title;
}
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header)
{
size_t entry_count = BE32(header->pkg_entry_count);
uint32_t entry_table_offset = BE32(header->pkg_table_offset);
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
void *entry_table_data = malloc(entry_table_size);
FILE *fd = FS::OpenRead(path);
FS::Seek(fd, entry_table_offset);
FS::Read(fd, entry_table_data, entry_table_size);
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
void* param_sfo_data = NULL;
uint32_t param_sfo_offset = 0;
uint32_t param_sfo_size = 0;
void *icon0_png_data = NULL;
uint32_t icon0_png_offset = 0;
uint32_t icon0_png_size = 0;
for (size_t i = 0; i < entry_count; ++i)
{
if (BE32(entries[i].id) == PKG_ENTRY_ID__PARAM_SFO)
{
param_sfo_offset = BE32(entries[i].offset);
param_sfo_size = BE32(entries[i].size);
break;
}
}
free(entry_table_data);
std::string title;
if (param_sfo_offset > 0 && param_sfo_size > 0)
{
param_sfo_data = malloc(param_sfo_size);
FS::Seek(fd, param_sfo_offset);
FS::Read(fd, param_sfo_data, param_sfo_size);
const char* tmp_title = SFO::GetString((const char*)param_sfo_data, param_sfo_size, "TITLE");
if (tmp_title != nullptr)
title = std::string(tmp_title);
free(param_sfo_data);
}
return title;
}
std::string getRemoteUrl(const std::string path, bool encodeUrl)
{
if (strlen(remote_settings->username) == 0 && strlen(remote_settings->password) == 0 &&
@@ -125,11 +226,14 @@ namespace INSTALLER
else
{
std::string encoded_path = path;
std::string encoded_site_name = remote_settings->site_name;
Web::Urn::Path uri(encoded_path);
Web::Urn::Path site_name(encoded_site_name);
CURL *curl = curl_easy_init();
encoded_path = uri.quote(curl);
encoded_site_name = site_name.quote(curl);
curl_easy_cleanup(curl);
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_path;
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_site_name + encoded_path;
return full_url;
}
@@ -142,23 +246,22 @@ namespace INSTALLER
return true;
}
int InstallRemotePkg(const std::string &path, pkg_header *header)
int InstallRemotePkg(const std::string &url, pkg_header *header, std::string title, bool prompt)
{
std::string url = getRemoteUrl(path, true);
if (url.empty())
return 0;
int ret;
std::string filename = path.substr(path.find_last_of("/")+1);
std::string cid = std::string((char *)header->pkg_content_id);
cid = cid.substr(cid.find_first_of("-") + 1, 9);
std::string display_title = title.length() > 0 ? title : cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
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)
{
@@ -196,7 +299,7 @@ namespace INSTALLER
params.entitlementType = 5;
params.id = (char *)header->pkg_content_id;
params.contentUrl = url.c_str();
params.contentName = filename.c_str();
params.contentName = display_title.c_str();
params.iconPath = "";
params.playgoScenarioId = "0";
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
@@ -213,18 +316,30 @@ namespace INSTALLER
ret = sceBgftServiceIntDebugDownloadRegisterPkg(&params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
sprintf(confirm_message, "%s - %s?", path.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
while (confirm_state == CONFIRM_WAIT)
if (prompt)
{
sceKernelUsleep(100000);
}
activity_inprogess = true;
selected_action = action_to_take;
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
while (confirm_state == CONFIRM_WAIT)
{
sceKernelUsleep(100000);
}
activity_inprogess = true;
selected_action = action_to_take;
if (confirm_state == CONFIRM_YES)
if (confirm_state == CONFIRM_YES)
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
goto err;
}
goto retry;
}
}
else
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
@@ -233,27 +348,37 @@ namespace INSTALLER
}
}
else if (ret > 0)
{
goto err;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
goto err;
}
Util::Notify("%s queued", filename.c_str());
Util::Notify("%s queued", display_title.c_str());
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (bytes_transfered < 99)
if (prompt)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
return 0;
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
sceSystemServicePowerTick();
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (!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;
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;
@@ -265,6 +390,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;
@@ -286,6 +413,9 @@ namespace INSTALLER
return 0;
}
std::string title = GetLocalPkgTitle(path, &header);
std::string display_title = title.length() > 0 ? title : std::string(titleId);
OrbisBgftTaskProgress progress_info;
OrbisBgftDownloadParamEx download_params;
memset(&download_params, 0, sizeof(download_params));
@@ -293,7 +423,7 @@ namespace INSTALLER
download_params.params.entitlementType = 5;
download_params.params.id = (char *)header.pkg_content_id;
download_params.params.contentUrl = filepath;
download_params.params.contentName = path.c_str();
download_params.params.contentName = display_title.c_str();
;
download_params.params.iconPath = "";
download_params.params.playgoScenarioId = "0";
@@ -318,18 +448,24 @@ namespace INSTALLER
if (ret)
return 0;
Util::Notify("%s queued", path.c_str());
Util::Notify("%s queued", display_title.c_str());
file_transfering = true;
bytes_to_download = 100;
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;
@@ -341,6 +477,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)
@@ -360,6 +498,9 @@ namespace INSTALLER
return 0;
}
std::string title = GetLocalPkgTitle(path, header);
std::string display_title = title.length() > 0 ? title : std::string(titleId);
OrbisBgftTaskProgress progress_info;
int prog = 0;
OrbisBgftDownloadParamEx download_params;
@@ -368,7 +509,7 @@ namespace INSTALLER
download_params.params.entitlementType = 5;
download_params.params.id = (char *)header->pkg_content_id;
download_params.params.contentUrl = filepath;
download_params.params.contentName = filename.c_str();
download_params.params.contentName = display_title.c_str();
;
download_params.params.iconPath = "";
download_params.params.playgoScenarioId = "0";
@@ -381,7 +522,7 @@ namespace INSTALLER
ret = sceBgftServiceIntDownloadRegisterTaskByStorageEx(&download_params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
sprintf(confirm_message, "%s - %s?", path.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
@@ -416,22 +557,27 @@ namespace INSTALLER
if (!remove_after_install)
{
Util::Notify("%s queued", filename.c_str());
Util::Notify("%s queued", display_title.c_str());
return 1;
}
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);
@@ -587,4 +733,225 @@ namespace INSTALLER
return true;
}
}
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash)
{
return archive_pkg_install_data_list[hash];
}
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data)
{
std::pair<std::string, ArchivePkgInstallData*> pair = std::make_pair(hash, pkg_data);
archive_pkg_install_data_list.erase(hash);
archive_pkg_install_data_list.insert(pair);
}
void RemoveArchivePkgInstallData(const std::string &hash)
{
archive_pkg_install_data_list.erase(hash);
}
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:
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);
return nullptr;
}
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg)
{
pkg_header header;
pkg_data->split_file->Read((char*)&header, sizeof(pkg_header), 0);
int ret;
std::string cid = std::string((char *)header.pkg_content_id);
cid = cid.substr(cid.find_first_of("-") + 1, 9);
std::string display_title = cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
uint32_t content_type = BE32(header.pkg_content_type);
uint32_t flags = BE32(header.pkg_content_flags);
bool is_patch = false;
bool completed = false;
switch (content_type)
{
case PKG_CONTENT_TYPE_GD:
package_type = "PS4GD";
break;
case PKG_CONTENT_TYPE_AC:
package_type = "PS4AC";
break;
case PKG_CONTENT_TYPE_AL:
package_type = "PS4AL";
break;
case PKG_CONTENT_TYPE_DP:
package_type = "PS4DP";
break;
default:
package_type = NULL;
return 0;
break;
}
if (flags & PKG_CONTENT_FLAGS_FIRST_PATCH ||
flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH ||
flags & PKG_CONTENT_FLAGS_DELTA_PATCH ||
flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
{
is_patch = true;
}
std::string hash = Util::UrlHash(path);
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
AddArchivePkgInstallData(hash, pkg_data);
OrbisBgftTaskProgress progress_info;
OrbisBgftDownloadParam params;
memset(&params, 0, sizeof(params));
{
params.userId = user_id;
params.entitlementType = 5;
params.id = (char *)header.pkg_content_id;
params.contentUrl = full_url.c_str();
params.contentName = display_title.c_str();
params.iconPath = "";
params.playgoScenarioId = "0";
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
params.packageType = package_type;
params.packageSubType = "";
params.packageSize = BE64(header.pkg_size);
}
retry:
int task_id = -1;
if (!is_patch)
ret = sceBgftServiceIntDownloadRegisterTask(&params, &task_id);
else
ret = sceBgftServiceIntDebugDownloadRegisterPkg(&params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
if (!bg)
{
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
while (confirm_state == CONFIRM_WAIT)
{
sceKernelUsleep(100000);
}
activity_inprogess = true;
selected_action = action_to_take;
if (confirm_state == CONFIRM_YES)
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
ret = 0;
goto finish;
}
goto retry;
}
}
else
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
ret = 0;
goto finish;
}
goto retry;
}
}
else if (ret > 0)
{
ret = 0;
goto finish;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
ret = 0;
goto finish;
}
Util::Notify("%s queued", display_title.c_str());
if (!bg)
{
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (!completed)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
{
ret = 0;
goto finish;
}
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
if (progress_info.length > 0)
{
completed = progress_info.transferred == progress_info.length;
bytes_to_download = progress_info.length;
bytes_transfered = progress_info.transferred;
}
sceSystemServicePowerTick();
}
}
else
{
BgProgressCheck *bg_check_data = (BgProgressCheck*) malloc(sizeof(BgProgressCheck));
memset(bg_check_data, 0, sizeof(BgProgressCheck));
bg_check_data->pkg_data = pkg_data;
bg_check_data->task_id = task_id;
bg_check_data->hash = hash;
ret = pthread_create(&bk_install_thid, NULL, CheckBgInstallTaskThread, bg_check_data);
return 1;
}
ret = 1;
finish:
pkg_data->stop_write_thread = true;
pthread_join(pkg_data->thread, NULL);
delete(pkg_data->split_file);
free(pkg_data);
RemoveArchivePkgInstallData(hash);
return ret;
}
}
+24 -1
View File
@@ -1,5 +1,10 @@
#pragma once
#include "clients/remote_client.h"
#include "zip_util.h"
#include "split_file.h"
#include "pthread.h"
#define SWAP16(x) \
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
(((uint16_t)(x)&UINT16_C(0xFF00)) >> 8)))
@@ -44,6 +49,8 @@
#define PKG_ENTRY_ID__PARAM_SFO 0x1000
#define PKG_ENTRY_ID__ICON0_PNG 0x1200
#define INSTALL_ARCHIVE_PKG_SPLIT_SIZE 10485760
typedef struct
{
uint32_t pkg_magic; // 0x000 - 0x7F434E54
@@ -114,6 +121,16 @@ enum pkg_content_type
PKG_CONTENT_TYPE_DP = 0x1E, /* pkg_ps4_delta_patch */
};
struct ArchivePkgInstallData
{
SplitFile *split_file;
ArchiveEntry *archive_entry;
pthread_t thread;
bool stop_write_thread;
};
static pthread_t bk_install_thid;
namespace INSTALLER
{
int Init(void);
@@ -121,9 +138,15 @@ namespace INSTALLER
bool canInstallRemotePkg(const std::string &url);
std::string getRemoteUrl(const std::string path, bool encodeUrl = false);
int InstallRemotePkg(const std::string &path, pkg_header *header);
int InstallRemotePkg(const std::string &path, pkg_header *header, std::string title, bool prompt = false);
int InstallLocalPkg(const std::string &path);
int InstallLocalPkg(const std::string &path, pkg_header *header, bool remove_after_install = false);
bool ExtractLocalPkg(const std::string &path, const std::string sfo_path, const std::string icon_path);
bool ExtractRemotePkg(const std::string &path, const std::string sfo_path, const std::string icon_path);
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header);
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header);
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash);
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data);
void RemoveArchivePkgInstallData(const std::string &hash);
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg = false);
}
+163 -153
View File
@@ -10,158 +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 google 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
"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;
@@ -175,7 +185,7 @@ namespace Lang
std::string lang = std::string(language);
lang = Util::Trim(lang, " ");
if (lang.size() > 0)
if (lang.size() > 0 && lang.compare("Default") != 0)
{
sprintf(langFile, "/app0/assets/langs/%s.ini", lang.c_str());
}
+164 -154
View File
@@ -3,159 +3,169 @@
#include "config.h"
#define FOREACH_STR(FUNC) \
FUNC(STR_CONNECTION_SETTINGS) \
FUNC(STR_SITE) \
FUNC(STR_LOCAL) \
FUNC(STR_REMOTE) \
FUNC(STR_MESSAGES) \
FUNC(STR_UPDATE_SOFTWARE) \
FUNC(STR_CONNECT) \
FUNC(STR_DISCONNECT) \
FUNC(STR_SEARCH) \
FUNC(STR_REFRESH) \
FUNC(STR_SERVER) \
FUNC(STR_USERNAME) \
FUNC(STR_PASSWORD) \
FUNC(STR_PORT) \
FUNC(STR_PASV) \
FUNC(STR_DIRECTORY) \
FUNC(STR_FILTER) \
FUNC(STR_YES) \
FUNC(STR_NO) \
FUNC(STR_CANCEL) \
FUNC(STR_CONTINUE) \
FUNC(STR_CLOSE) \
FUNC(STR_FOLDER) \
FUNC(STR_FILE) \
FUNC(STR_TYPE) \
FUNC(STR_NAME) \
FUNC(STR_SIZE) \
FUNC(STR_DATE) \
FUNC(STR_NEW_FOLDER) \
FUNC(STR_RENAME) \
FUNC(STR_DELETE) \
FUNC(STR_UPLOAD) \
FUNC(STR_DOWNLOAD) \
FUNC(STR_SELECT_ALL) \
FUNC(STR_CLEAR_ALL) \
FUNC(STR_UPLOADING) \
FUNC(STR_DOWNLOADING) \
FUNC(STR_OVERWRITE) \
FUNC(STR_DONT_OVERWRITE) \
FUNC(STR_ASK_FOR_CONFIRM) \
FUNC(STR_DONT_ASK_CONFIRM) \
FUNC(STR_ALLWAYS_USE_OPTION) \
FUNC(STR_ACTIONS) \
FUNC(STR_CONFIRM) \
FUNC(STR_OVERWRITE_OPTIONS) \
FUNC(STR_PROPERTIES) \
FUNC(STR_PROGRESS) \
FUNC(STR_UPDATES) \
FUNC(STR_DEL_CONFIRM_MSG) \
FUNC(STR_CANCEL_ACTION_MSG) \
FUNC(STR_FAIL_UPLOAD_MSG) \
FUNC(STR_FAIL_DOWNLOAD_MSG) \
FUNC(STR_FAIL_READ_LOCAL_DIR_MSG) \
FUNC(STR_CONNECTION_CLOSE_ERR_MSG) \
FUNC(STR_REMOTE_TERM_CONN_MSG) \
FUNC(STR_FAIL_LOGIN_MSG) \
FUNC(STR_FAIL_TIMEOUT_MSG) \
FUNC(STR_FAIL_DEL_DIR_MSG) \
FUNC(STR_DELETING) \
FUNC(STR_FAIL_DEL_FILE_MSG) \
FUNC(STR_DELETED) \
FUNC(STR_LINK) \
FUNC(STR_SHARE) \
FUNC(STR_FAILED) \
FUNC(STR_FAIL_CREATE_LOCAL_FILE_MSG) \
FUNC(STR_INSTALL) \
FUNC(STR_INSTALLING) \
FUNC(STR_INSTALL_SUCCESS) \
FUNC(STR_INSTALL_FAILED) \
FUNC(STR_INSTALL_SKIPPED) \
FUNC(STR_CHECK_HTTP_MSG) \
FUNC(STR_FAILED_HTTP_CHECK) \
FUNC(STR_REMOTE_NOT_HTTP) \
FUNC(STR_INSTALL_FROM_DATA_MSG) \
FUNC(STR_ALREADY_INSTALLED_MSG) \
FUNC(STR_INSTALL_FROM_URL) \
FUNC(STR_CANNOT_READ_PKG_HDR_MSG) \
FUNC(STR_FAVORITE_URLS) \
FUNC(STR_SLOT) \
FUNC(STR_EDIT) \
FUNC(STR_ONETIME_URL) \
FUNC(STR_NOT_A_VALID_PACKAGE) \
FUNC(STR_WAIT_FOR_INSTALL_MSG) \
FUNC(STR_FAIL_INSTALL_TMP_PKG_MSG) \
FUNC(STR_FAIL_TO_OBTAIN_GG_DL_MSG) \
FUNC(STR_AUTO_DELETE_TMP_PKG) \
FUNC(STR_PROTOCOL_NOT_SUPPORTED) \
FUNC(STR_COULD_NOT_RESOLVE_HOST) \
FUNC(STR_EXTRACT) \
FUNC(STR_EXTRACTING) \
FUNC(STR_FAILED_TO_EXTRACT) \
FUNC(STR_EXTRACT_LOCATION) \
FUNC(STR_COMPRESS) \
FUNC(STR_ZIP_FILE_PATH) \
FUNC(STR_COMPRESSING) \
FUNC(STR_ERROR_CREATE_ZIP) \
FUNC(STR_UNSUPPORTED_FILE_FORMAT) \
FUNC(STR_CUT) \
FUNC(STR_COPY) \
FUNC(STR_PASTE) \
FUNC(STR_MOVING) \
FUNC(STR_COPYING) \
FUNC(STR_FAIL_MOVE_MSG) \
FUNC(STR_FAIL_COPY_MSG) \
FUNC(STR_CANT_MOVE_TO_SUBDIR_MSG) \
FUNC(STR_CANT_COPY_TO_SUBDIR_MSG) \
FUNC(STR_UNSUPPORTED_OPERATION_MSG) \
FUNC(STR_HTTP_PORT) \
FUNC(STR_REINSTALL_CONFIRM_MSG) \
FUNC(STR_REMOTE_NOT_SUPPORT_MSG) \
FUNC(STR_CANNOT_CONNECT_REMOTE_MSG) \
FUNC(STR_DOWNLOAD_INSTALL_MSG) \
FUNC(STR_CHECKING_REMOTE_SERVER_MSG) \
FUNC(STR_ENABLE_RPI) \
FUNC(STR_ENABLE_RPI_FTP_SMB_MSG) \
FUNC(STR_ENABLE_RPI_WEBDAV_MSG) \
FUNC(STR_FILES) \
FUNC(STR_EDITOR) \
FUNC(STR_SAVE) \
FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \
FUNC(STR_DELETE_LINE) \
FUNC(STR_INSERT_LINE) \
FUNC(STR_MODIFIED) \
FUNC(STR_FAIL_GET_TOKEN_MSG) \
FUNC(STR_GET_TOKEN_SUCCESS_MSG) \
FUNC(STR_PERM_DRIVE) \
FUNC(STR_PERM_DRIVE_APPDATA) \
FUNC(STR_PERM_DRIVE_FILE) \
FUNC(STR_PERM_DRIVE_METADATA) \
FUNC(STR_PERM_DRIVE_METADATA_RO) \
FUNC(STR_GOOGLE_LOGIN_FAIL_MSG) \
FUNC(STR_GOOGLE_LOGIN_TIMEOUT_MSG) \
FUNC(STR_NEW_FILE) \
FUNC(STR_SETTINGS) \
FUNC(STR_CLIENT_ID) \
FUNC(STR_CLIENT_SECRET) \
FUNC(STR_GLOBAL) \
FUNC(STR_GOOGLE) \
FUNC(STR_COPY_LINE) \
FUNC(STR_PASTE_LINE) \
FUNC(STR_SHOW_HIDDEN_FILES) \
FUNC(STR_SET_DEFAULT_DIRECTORY) \
FUNC(STR_SET_DEFAULT_DIRECTORY_MSG) \
FUNC(STR_VIEW_IMAGE) \
FUNC(STR_VIEW_PKG_INFO) \
FUNC(STR_NFS_EXP_PATH_MISSING_MSG) \
FUNC(STR_FAIL_INIT_NFS_CONTEXT) \
FUNC(STR_FAIL_MOUNT_NFS_MSG) \
FUNC(STR_WEB_SERVER) \
FUNC(STR_ENABLE) \
FUNC(STR_COMPRESSED_FILE_PATH) \
FUNC(STR_COMPRESSED_FILE_PATH_MSG)
#define FOREACH_STR(FUNC) \
FUNC(STR_CONNECTION_SETTINGS) \
FUNC(STR_SITE) \
FUNC(STR_LOCAL) \
FUNC(STR_REMOTE) \
FUNC(STR_MESSAGES) \
FUNC(STR_UPDATE_SOFTWARE) \
FUNC(STR_CONNECT) \
FUNC(STR_DISCONNECT) \
FUNC(STR_SEARCH) \
FUNC(STR_REFRESH) \
FUNC(STR_SERVER) \
FUNC(STR_USERNAME) \
FUNC(STR_PASSWORD) \
FUNC(STR_PORT) \
FUNC(STR_PASV) \
FUNC(STR_DIRECTORY) \
FUNC(STR_FILTER) \
FUNC(STR_YES) \
FUNC(STR_NO) \
FUNC(STR_CANCEL) \
FUNC(STR_CONTINUE) \
FUNC(STR_CLOSE) \
FUNC(STR_FOLDER) \
FUNC(STR_FILE) \
FUNC(STR_TYPE) \
FUNC(STR_NAME) \
FUNC(STR_SIZE) \
FUNC(STR_DATE) \
FUNC(STR_NEW_FOLDER) \
FUNC(STR_RENAME) \
FUNC(STR_DELETE) \
FUNC(STR_UPLOAD) \
FUNC(STR_DOWNLOAD) \
FUNC(STR_SELECT_ALL) \
FUNC(STR_CLEAR_ALL) \
FUNC(STR_UPLOADING) \
FUNC(STR_DOWNLOADING) \
FUNC(STR_OVERWRITE) \
FUNC(STR_DONT_OVERWRITE) \
FUNC(STR_ASK_FOR_CONFIRM) \
FUNC(STR_DONT_ASK_CONFIRM) \
FUNC(STR_ALLWAYS_USE_OPTION) \
FUNC(STR_ACTIONS) \
FUNC(STR_CONFIRM) \
FUNC(STR_OVERWRITE_OPTIONS) \
FUNC(STR_PROPERTIES) \
FUNC(STR_PROGRESS) \
FUNC(STR_UPDATES) \
FUNC(STR_DEL_CONFIRM_MSG) \
FUNC(STR_CANCEL_ACTION_MSG) \
FUNC(STR_FAIL_UPLOAD_MSG) \
FUNC(STR_FAIL_DOWNLOAD_MSG) \
FUNC(STR_FAIL_READ_LOCAL_DIR_MSG) \
FUNC(STR_CONNECTION_CLOSE_ERR_MSG) \
FUNC(STR_REMOTE_TERM_CONN_MSG) \
FUNC(STR_FAIL_LOGIN_MSG) \
FUNC(STR_FAIL_TIMEOUT_MSG) \
FUNC(STR_FAIL_DEL_DIR_MSG) \
FUNC(STR_DELETING) \
FUNC(STR_FAIL_DEL_FILE_MSG) \
FUNC(STR_DELETED) \
FUNC(STR_LINK) \
FUNC(STR_SHARE) \
FUNC(STR_FAILED) \
FUNC(STR_FAIL_CREATE_LOCAL_FILE_MSG) \
FUNC(STR_INSTALL) \
FUNC(STR_INSTALLING) \
FUNC(STR_INSTALL_SUCCESS) \
FUNC(STR_INSTALL_FAILED) \
FUNC(STR_INSTALL_SKIPPED) \
FUNC(STR_CHECK_HTTP_MSG) \
FUNC(STR_FAILED_HTTP_CHECK) \
FUNC(STR_REMOTE_NOT_HTTP) \
FUNC(STR_INSTALL_FROM_DATA_MSG) \
FUNC(STR_ALREADY_INSTALLED_MSG) \
FUNC(STR_INSTALL_FROM_URL) \
FUNC(STR_CANNOT_READ_PKG_HDR_MSG) \
FUNC(STR_FAVORITE_URLS) \
FUNC(STR_SLOT) \
FUNC(STR_EDIT) \
FUNC(STR_ONETIME_URL) \
FUNC(STR_NOT_A_VALID_PACKAGE) \
FUNC(STR_WAIT_FOR_INSTALL_MSG) \
FUNC(STR_FAIL_INSTALL_TMP_PKG_MSG) \
FUNC(STR_FAIL_TO_OBTAIN_GG_DL_MSG) \
FUNC(STR_AUTO_DELETE_TMP_PKG) \
FUNC(STR_PROTOCOL_NOT_SUPPORTED) \
FUNC(STR_COULD_NOT_RESOLVE_HOST) \
FUNC(STR_EXTRACT) \
FUNC(STR_EXTRACTING) \
FUNC(STR_FAILED_TO_EXTRACT) \
FUNC(STR_EXTRACT_LOCATION) \
FUNC(STR_COMPRESS) \
FUNC(STR_ZIP_FILE_PATH) \
FUNC(STR_COMPRESSING) \
FUNC(STR_ERROR_CREATE_ZIP) \
FUNC(STR_UNSUPPORTED_FILE_FORMAT) \
FUNC(STR_CUT) \
FUNC(STR_COPY) \
FUNC(STR_PASTE) \
FUNC(STR_MOVING) \
FUNC(STR_COPYING) \
FUNC(STR_FAIL_MOVE_MSG) \
FUNC(STR_FAIL_COPY_MSG) \
FUNC(STR_CANT_MOVE_TO_SUBDIR_MSG) \
FUNC(STR_CANT_COPY_TO_SUBDIR_MSG) \
FUNC(STR_UNSUPPORTED_OPERATION_MSG) \
FUNC(STR_HTTP_PORT) \
FUNC(STR_REINSTALL_CONFIRM_MSG) \
FUNC(STR_REMOTE_NOT_SUPPORT_MSG) \
FUNC(STR_CANNOT_CONNECT_REMOTE_MSG) \
FUNC(STR_DOWNLOAD_INSTALL_MSG) \
FUNC(STR_CHECKING_REMOTE_SERVER_MSG) \
FUNC(STR_ENABLE_RPI) \
FUNC(STR_ENABLE_RPI_FTP_SMB_MSG) \
FUNC(STR_ENABLE_RPI_WEBDAV_MSG) \
FUNC(STR_FILES) \
FUNC(STR_EDITOR) \
FUNC(STR_SAVE) \
FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \
FUNC(STR_DELETE_LINE) \
FUNC(STR_INSERT_LINE) \
FUNC(STR_MODIFIED) \
FUNC(STR_FAIL_GET_TOKEN_MSG) \
FUNC(STR_GET_TOKEN_SUCCESS_MSG) \
FUNC(STR_PERM_DRIVE) \
FUNC(STR_PERM_DRIVE_APPDATA) \
FUNC(STR_PERM_DRIVE_FILE) \
FUNC(STR_PERM_DRIVE_METADATA) \
FUNC(STR_PERM_DRIVE_METADATA_RO) \
FUNC(STR_GOOGLE_LOGIN_FAIL_MSG) \
FUNC(STR_GOOGLE_LOGIN_TIMEOUT_MSG) \
FUNC(STR_NEW_FILE) \
FUNC(STR_SETTINGS) \
FUNC(STR_CLIENT_ID) \
FUNC(STR_CLIENT_SECRET) \
FUNC(STR_GLOBAL) \
FUNC(STR_GOOGLE) \
FUNC(STR_COPY_LINE) \
FUNC(STR_PASTE_LINE) \
FUNC(STR_SHOW_HIDDEN_FILES) \
FUNC(STR_SET_DEFAULT_DIRECTORY) \
FUNC(STR_SET_DEFAULT_DIRECTORY_MSG) \
FUNC(STR_VIEW_IMAGE) \
FUNC(STR_VIEW_PKG_INFO) \
FUNC(STR_NFS_EXP_PATH_MISSING_MSG) \
FUNC(STR_FAIL_INIT_NFS_CONTEXT) \
FUNC(STR_FAIL_MOUNT_NFS_MSG) \
FUNC(STR_WEB_SERVER) \
FUNC(STR_ENABLE) \
FUNC(STR_COMPRESSED_FILE_PATH) \
FUNC(STR_COMPRESSED_FILE_PATH_MSG) \
FUNC(STR_ALLDEBRID) \
FUNC(STR_API_KEY) \
FUNC(STR_CANT_EXTRACT_URL_MSG) \
FUNC(STR_FAIL_INSTALL_FROM_URL_MSG) \
FUNC(STR_INVALID_URL) \
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG) \
FUNC(STR_LANGUAGE) \
FUNC(STR_TEMP_DIRECTORY) \
FUNC(STR_REALDEBRID) \
FUNC(STR_BACKGROUND_INSTALL_INPROGRESS)
#define GET_VALUE(x) x,
#define GET_STRING(x) #x,
@@ -165,7 +175,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 152
#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];
+61
View File
@@ -2,9 +2,70 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/uio.h>
#include <orbis/libkernel.h>
#include <libjbc.h>
#define SYSCALL(nr, fn) __attribute__((naked)) fn\
{\
asm volatile("mov $" #nr ", %rax\nmov %rcx, %r10\nsyscall\nret");\
}
SYSCALL(22, static int unmount(const char* path, int flags))
SYSCALL(378, static int nmount(struct iovec* iov, unsigned int niov, int flags))
static void build_iovec(struct iovec** iov, int* iovlen, const char* name, const void* val, size_t len) {
int i;
if (*iovlen < 0)
return;
i = *iovlen;
*iov = (struct iovec*)realloc(*iov, sizeof **iov * (i + 2));
if (*iov == NULL) {
*iovlen = -1;
return;
}
(*iov)[i].iov_base = strdup(name);
(*iov)[i].iov_len = strlen(name) + 1;
++i;
(*iov)[i].iov_base = (void*)val;
if (len == (size_t)-1) {
if (val != NULL)
len = strlen((const char*)val) + 1;
else
len = 0;
}
(*iov)[i].iov_len = (int)len;
*iovlen = ++i;
}
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags)
{
struct iovec* iov = NULL;
int iovlen = 0;
unmount(mountpoint, 0);
build_iovec(&iov, &iovlen, "fstype", fstype, -1);
build_iovec(&iov, &iovlen, "fspath", mountpoint, -1);
build_iovec(&iov, &iovlen, "from", device, -1);
build_iovec(&iov, &iovlen, "large", "yes", -1);
build_iovec(&iov, &iovlen, "timezone", "static", -1);
build_iovec(&iov, &iovlen, "async", "", -1);
build_iovec(&iov, &iovlen, "ignoreacl", "", -1);
if (mode) {
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
build_iovec(&iov, &iovlen, "mask", mode, -1);
}
return nmount(iov, iovlen, flags);
}
// Variables for (un)jailbreaking
jbc_cred g_Cred;
jbc_cred g_RootCreds;
+3
View File
@@ -1,7 +1,10 @@
#ifndef __ORBIS_JBC_H__
#define __ORBIS_JBC_H__
#define MNT_UPDATE 0x0000000000010000ULL
int initialize_jbc();
void terminate_jbc();
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags);
#endif
+236 -29
View File
@@ -8,12 +8,14 @@
#include "clients/smbclient.h"
#include "clients/ftpclient.h"
#include "clients/nfsclient.h"
#include "filehost/filehost.h"
#include "config.h"
#include "fs.h"
#include "windows.h"
#include "lang.h"
#include "system.h"
#include "zip_util.h"
#include "util.h"
#include "installer.h"
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
@@ -920,34 +922,55 @@ namespace HttpServer
res.set_content(str.c_str(), "text/plain");
});
svr->Get("/rmt_inst/(.*)", [&](const Request & req, Response & res)
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request & req, Response & res)
{
RemoteClient *tmp_client;
auto path = std::string("/") + std::string(req.matches[1]);
RemoteSettings *tmp_settings;
auto site_idx = std::stoi(req.matches[1])-1;
std::string path;
if (remote_settings->type == CLIENT_TYPE_SFTP)
if (site_idx != 98)
{
tmp_client = new SFTPClient();
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
}
else if (remote_settings->type == CLIENT_TYPE_SMB)
{
tmp_client = new SmbClient();
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
}
else if (remote_settings->type == CLIENT_TYPE_FTP)
{
tmp_client = new FtpClient();
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
}
else if (remote_settings->type == CLIENT_TYPE_NFS)
{
tmp_client = new NfsClient();
tmp_client->Connect(remote_settings->server, remote_settings->username, remote_settings->password);
path = std::string("/") + std::string(req.matches[3]);
tmp_settings = &site_settings[sites[site_idx]];
if (tmp_settings->type == CLIENT_TYPE_SFTP)
{
tmp_client = new SFTPClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else if (tmp_settings->type == CLIENT_TYPE_SMB)
{
tmp_client = new SmbClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else if (tmp_settings->type == CLIENT_TYPE_FTP)
{
tmp_client = new FtpClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else if (tmp_settings->type == CLIENT_TYPE_NFS)
{
tmp_client = new NfsClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else
{
tmp_client = remoteclient;
}
}
else
{
tmp_client = remoteclient;
std::string hash = std::string(req.matches[3]);
std::string url = FileHost::GetCachedDownloadUrl(hash);
size_t scheme_pos = url.find("://");
size_t root_pos = url.find("/", scheme_pos + 3);
std::string host = url.substr(0, root_pos);
path = url.substr(root_pos);
tmp_client = new BaseClient();
tmp_client->Connect(host, "", "");
}
if (tmp_client == nullptr || !tmp_client->IsConnected())
@@ -983,11 +1006,12 @@ namespace HttpServer
int ret = tmp_client->GetRange(path, sink, length, offset);
return (ret == 1);
},
[tmp_client, path](bool success) {
[tmp_client, path, site_idx](bool success) {
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|| tmp_client->clientType() == CLIENT_TYPE_NFS))
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
{
tmp_client->Quit();
delete tmp_client;
@@ -1000,9 +1024,9 @@ namespace HttpServer
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 65536ul - req.ranges[0].first;
range_len = 524288ul;
res.set_header("Content-Length", std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-65535/"+std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
@@ -1011,11 +1035,12 @@ namespace HttpServer
int ret = tmp_client->GetRange(path, sink, range_len, range.first);
return (ret == 1);
},
[tmp_client, path, range, range_len](bool success) {
[tmp_client, site_idx, path, range, range_len](bool success) {
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|| tmp_client->clientType() == CLIENT_TYPE_NFS))
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
{
tmp_client->Quit();
delete tmp_client;
@@ -1024,6 +1049,188 @@ namespace HttpServer
}
});
svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res)
{
RemoteClient *tmp_client;
RemoteSettings *tmp_settings;
std::string hash = req.matches[1];
ArchivePkgInstallData *pkg_data = INSTALLER::GetArchivePkgInstallData(hash);
if (req.method == "HEAD")
{
res.status = 204;
res.set_header("Content-Length", std::to_string(pkg_data->archive_entry->filesize));
res.set_header("Accept-Ranges", "bytes");
return;
}
if (req.ranges.empty())
{
res.status = 200;
res.set_content_provider(
131072, "application/octet-stream",
[pkg_data](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(131072);
size_t bytes_read = pkg_data->split_file->Read(buf, 131072, offset);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
else
{
res.status = 206;
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 524288ul;
res.set_header("Content-Length", std::to_string(range_len));
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
range_len, "application/octet-stream",
[pkg_data, range, range_len](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(range_len);
size_t bytes_read = pkg_data->split_file->Read(buf, range_len, range.first);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
});
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
{
std::string url;
const char *url_param;
bool use_alldebrid = 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 parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
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, use_realdebrid);
if (!filehost->IsValidUrl())
{
failed(res, 200, lang_strings[STR_INVALID_URL]);
return;
}
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]);
return;
}
delete(filehost);
size_t scheme_pos = download_url.find("://");
size_t root_pos = download_url.find("/", scheme_pos + 3);
std::string host = download_url.substr(0, root_pos);
std::string path = download_url.substr(root_pos);
pkg_header header;
BaseClient *baseclient = new BaseClient();
baseclient->Connect(host, "", "");
baseclient->Head(path, &header, sizeof(pkg_header));
if (BE32(header.pkg_magic) == 0x7F434E54)
{
FileHost::AddCacheDownloadUrl(hash, download_url);
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
delete(baseclient);
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title, true);
if (rc == 0)
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
return;
}
}
else
{
ArchiveEntry *entry = ZipUtil::GetPackageEntry(path, baseclient);
if (entry != nullptr)
{
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
memset(install_data, 0, sizeof(ArchivePkgInstallData));
std::string install_pkg_path = std::string(temp_folder) + "/" + entry->filename;
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE);
install_data->archive_entry = entry;
install_data->split_file = sp;
install_data->stop_write_thread = false;
int ret = pthread_create(&install_data->thread, NULL, Actions::ExtractArchivePkg, install_data);
ret = INSTALLER::InstallArchivePkg(entry->filename, install_data);
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;
}
}
activity_inprogess = false;
file_transfering = false;
Windows::SetModalMode(false);
success(res);
});
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
{
svr->stop();
@@ -1043,7 +1250,7 @@ namespace HttpServer
dbglogger_log("%s", log(req, res).c_str());
});
*/
svr->set_payload_max_length(1024 * 1024 * 12);
svr->set_tcp_nodelay(true);
svr->set_mount_point("/", "/");
@@ -1072,4 +1279,4 @@ namespace HttpServer
if (svr != nullptr)
svr->stop();
}
}
}
+221
View File
@@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdio.h>
#include <string>
#include "common.h"
#include "split_file.h"
SplitFile::SplitFile(const std::string &path, size_t block_size)
{
this->block_size = block_size;
this->path = path;
this->complete = false;
sem_init(&this->block_ready, 0, 0);
}
SplitFile::~SplitFile()
{
for (int i = 0; i < this->file_blocks.size(); i++)
{
if (this->file_blocks[i] != nullptr && this->file_blocks[i]->status != BLOCK_STATUS_DELETED)
{
if (this->file_blocks[i]->fd != nullptr)
{
fclose(this->file_blocks[i]->fd);
}
remove(this->file_blocks[i]->block_file.c_str());
free(this->file_blocks[i]);
}
}
sem_destroy(&this->block_ready);
};
int SplitFile::Open()
{
this->block_in_progress = NewBlock();
this->block_in_progress->fd = fopen(block_in_progress->block_file.c_str(), "w");
return (block_in_progress->fd == nullptr);
}
size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
{
int first_block_num, block_num;
size_t block_offset;
size_t remaining;
size_t bytes_read;
size_t total_bytes_read;
FileBlock *block;
FILE *fd;
char *p;
first_block_num= offset / this->block_size;
block_num = first_block_num;
block_offset = offset % this->block_size;
while ((block_num >= this->file_blocks.size() && !this->complete) ||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
if (block->status == BLOCK_STATUS_DELETED)
{
return -1;
}
if (block_offset > block->size - 1 && this->complete)
{
// requested offset is pass the end of split file
return 0;
}
remaining = buf_size;
bool eof = false;
total_bytes_read = 0;
p = buf;
while (remaining > 0 && !eof)
{
fd = block->fd;
if (fd == nullptr)
{
fd = fopen(block->block_file.c_str(), "rb");
block->fd = fd;
}
fseek(fd, block_offset, SEEK_SET);
bytes_read = fread(p, 1, remaining, fd);
if (bytes_read == remaining)
{
p += bytes_read;
total_bytes_read += bytes_read;
}
else
{
if (feof(fd))
{
p += bytes_read;
total_bytes_read += bytes_read;
if (block->is_last)
{
eof = true;
continue;
}
}
else
return -1;
}
remaining -= bytes_read;
if (remaining == 0)
continue;
block_num++;
block_offset = 0;
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
}
// delete blocks before the first read offset block. Assumuption, that reads are always
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
for (int j=0; j < first_block_num - 2; j++)
{
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
{
if (this->file_blocks[j]->fd != nullptr)
{
fclose(this->file_blocks[j]->fd);
this->file_blocks[j]->fd = nullptr;
}
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
remove(this->file_blocks[j]->block_file.c_str());
}
}
return total_bytes_read;
}
size_t SplitFile::Write(char *buf, size_t buf_size)
{
size_t bytes_written;
size_t block_space_remaining;
size_t bytes_to_write;
char *p = buf;
size_t total_bytes_written = 0;
size_t remaining_to_write = buf_size;
while (remaining_to_write > 0)
{
block_space_remaining = this->block_size - block_in_progress->size;
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
bytes_written = fwrite(p, 1, bytes_to_write, block_in_progress->fd);
block_in_progress->size += bytes_written;
total_bytes_written += bytes_written;
remaining_to_write -= bytes_written;
block_space_remaining -= bytes_written;
p += bytes_written;
// error if bytes_to_write != bytes_written
if (bytes_written != bytes_to_write)
{
break;
}
if (block_space_remaining == 0)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
block_in_progress->status = BLOCK_STATUS_CREATED;
this->file_blocks.push_back(block_in_progress);
sem_post(&this->block_ready);
block_in_progress = NewBlock();
}
}
return total_bytes_written;
}
int SplitFile::Close()
{
if (block_in_progress->fd != nullptr)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
}
block_in_progress->status = BLOCK_STATUS_CREATED;
block_in_progress->is_last = true;
this->file_blocks.push_back(block_in_progress);
this->complete = true;
sem_post(&this->block_ready);
return 0;
}
FileBlock *SplitFile::NewBlock()
{
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
memset(block, 0, sizeof(FileBlock));
block->is_last = false;
block->size = 0;
block->block_file = this->path + "." + std::to_string(this->file_blocks.size());
block->fd = fopen(block->block_file.c_str(), "w");
return block;
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef SPLIT_FILE_H
#define SPLIT_FILE_H
#include <string>
#include <vector>
#include <mutex>
#include <pthread.h>
enum FileBlockStatus
{
BLOCK_STATUS_NOT_EXISTS,
BLOCK_STATUS_CREATED,
BLOCK_STATUS_DELETED
};
typedef struct
{
std::string block_file;
size_t size;
FILE* fd;
bool is_last;
FileBlockStatus status;
} FileBlock;
class SplitFile
{
public:
SplitFile(const std::string& path, size_t block_size);
~SplitFile();
size_t Read(char* buf, size_t buf_size, size_t offset);
size_t Write(char* buf, size_t buf_size);
int Open();
int Close();
private:
std::vector<FileBlock*> file_blocks;
size_t write_offset;
size_t block_size;
std::string path;
int write_error;
bool complete;
FileBlock *block_in_progress;
sem_t block_ready;
FileBlock *NewBlock();
};
#endif
+22
View File
@@ -6,6 +6,8 @@
#include <algorithm>
#include <stdarg.h>
#include <orbis/libkernel.h>
#include "base64.h"
#include "openssl/md5.h"
#include "lang.h"
namespace Util
@@ -47,6 +49,13 @@ namespace Util
return s;
}
static inline bool EndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static inline std::vector<std::string> Split(const std::string &str, const std::string &delimiter)
{
std::string text = std::string(str);
@@ -66,6 +75,19 @@ namespace Util
return tokens;
}
static inline std::string UrlHash(const std::string &text)
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)text.c_str(), text.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
}
static inline void Notify(const char *fmt, ...)
{
OrbisNotificationRequest request;
+158 -28
View File
@@ -243,20 +243,33 @@ namespace Windows
{
std::string zipfolder;
std::vector<DirEntry> files;
bool local_browser_selected = saved_selected_browser & LOCAL_BROWSER;
bool remote_browser_selected = saved_selected_browser & REMOTE_BROWSER;
if (multi_selected_local_files.size() > 0)
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
if (local_browser_selected)
{
if (multi_selected_local_files.size() > 0)
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
else
files.push_back(selected_local_file);
}
else
files.push_back(selected_local_file);
{
if (multi_selected_remote_files.size() > 0)
std::copy(multi_selected_remote_files.begin(), multi_selected_remote_files.end(), std::back_inserter(files));
else
files.push_back(selected_remote_file);
}
if (strncmp(files.begin()->directory, "/data", 5) != 0 &&
strncmp(files.begin()->directory, "/mnt/usb", 8) != 0)
if (strncmp(local_directory, "/data", 5) != 0 &&
strncmp(local_directory, "/mnt/usb", 8) != 0 &&
strncmp(local_directory, "/user/data", 10) != 0)
{
zipfolder = "/data";
}
else if (files.size() > 1)
{
zipfolder = files.begin()->directory;
zipfolder = local_directory;
}
else
{
@@ -1049,26 +1062,29 @@ namespace Windows
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Extract##settings");
if (ImGui::Selectable(lang_strings[STR_EXTRACT], false, getSelectableFlag(REMOTE_ACTION_EXTRACT) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
ResetImeCallbacks();
sprintf(extract_zip_folder, "%s", getExtractFolder().c_str());
ime_single_field = extract_zip_folder;
ime_field_size = 255;
ime_callback = SingleValueImeCallback;
if (local_browser_selected)
ime_after_update = AfterExtractFolderCallback;
else
ime_after_update = AfterExtractRemoteFolderCallback;
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
if (local_browser_selected)
{
ImGui::PushID("Extract##settings");
if (ImGui::Selectable(lang_strings[STR_EXTRACT], false, getSelectableFlag(REMOTE_ACTION_NONE) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
ResetImeCallbacks();
sprintf(extract_zip_folder, "%s", getExtractFolder().c_str());
ime_single_field = extract_zip_folder;
ime_field_size = 255;
ime_callback = SingleValueImeCallback;
ime_after_update = AfterExtractFolderCallback;
Dialog::initImeDialog(lang_strings[STR_EXTRACT_LOCATION], extract_zip_folder, 255, ORBIS_TYPE_BASIC_LATIN, 600, 350);
gui_mode = GUI_MODE_IME;
file_transfering = true;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("Compress##settings");
if (ImGui::Selectable(lang_strings[STR_COMPRESS], false, getSelectableFlag(REMOTE_ACTION_NONE) | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
@@ -1605,11 +1621,38 @@ namespace Windows
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
ImGui::SetNextWindowPos(ImVec2(1050, 80));
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 500), NULL, NULL);
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 650), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
char id[192];
ImVec2 field_size;
float width;
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_LANGUAGE]);
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::SetNextItemWidth(690);
if (ImGui::BeginCombo("##Language", language, ImGuiComboFlags_PopupAlignLeft | ImGuiComboFlags_HeightLargest))
{
for (int n = 0; n < langs.size(); n++)
{
const bool is_selected = strcmp(langs[n].c_str(), language) == 0;
if (ImGui::Selectable(langs[n].c_str(), is_selected))
{
sprintf(language, "%s", langs[n].c_str());
}
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_AUTO_DELETE_TMP_PKG]);
ImGui::SameLine();
@@ -1623,6 +1666,26 @@ namespace Windows
ImGui::Checkbox("##show_hidden_files", &show_hidden_files);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_TEMP_DIRECTORY]);
ImGui::SameLine();
field_size = ImGui::CalcTextSize(lang_strings[STR_TEMP_DIRECTORY]);
width = field_size.x + 45;
sprintf(id, "%s##temp_direcotry", temp_folder);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = temp_folder;
ime_field_size = 512;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_COMPRESSED_FILE_PATH], temp_folder, 255, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
// Web Server settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_WEB_SERVER]);
ImGui::Separator();
@@ -1633,15 +1696,13 @@ namespace Windows
ImGui::Checkbox("##web_server_enabled", &web_server_enabled);
ImGui::Separator();
ImVec2 field_size;
field_size = ImGui::CalcTextSize(lang_strings[STR_PORT]);
float width = field_size.x + 45;
width = field_size.x + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_PORT]);
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
char id[192];
sprintf(id, "%s##http_server_port", txt_http_server_port);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
if (ImGui::Button(id, ImVec2(835-width, 0)))
@@ -1674,6 +1735,60 @@ namespace Windows
ImGui::PopStyleVar();
ImGui::Separator();
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
ImGui::Separator();
field_size = ImGui::CalcTextSize(lang_strings[STR_API_KEY]);
width = field_size.x + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_API_KEY]);
ImGui::SameLine();
ImGui::SetCursorPosX(width);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (strlen(alldebrid_api_key) > 0)
sprintf(id, "%s", "*********************************************##alldebrid_api_key");
else
sprintf(id, "%s", "##alldebrid_api_key");
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = alldebrid_api_key;
ime_field_size = 63;
ime_callback = SingleValueImeCallback;
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();
ImGui::Separator();
// Google settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GOOGLE]);
ImGui::Separator();
@@ -1976,6 +2091,15 @@ namespace Windows
selected_action = ACTION_NONE;
Actions::ExtractLocalZips();
break;
case ACTION_EXTRACT_REMOTE_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = true;
selected_action = ACTION_NONE;
Actions::ExtractRemoteZips();
break;
case ACTION_CREATE_LOCAL_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
@@ -2058,6 +2182,7 @@ namespace Windows
case ACTION_INSTALL_REMOTE_PKG:
sprintf(status_message, "%s", "");
activity_inprogess = true;
file_transfering = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
Actions::InstallRemotePkgs();
@@ -2355,6 +2480,11 @@ namespace Windows
selected_action = ACTION_EXTRACT_LOCAL_ZIP;
}
void AfterExtractRemoteFolderCallback(int ime_result)
{
selected_action = ACTION_EXTRACT_REMOTE_ZIP;
}
void AfterZipFileCallback(int ime_result)
{
selected_action = ACTION_CREATE_LOCAL_ZIP;
+1
View File
@@ -206,6 +206,7 @@ namespace Windows
void AfterPackageUrlCallback(int ime_result);
void AfterFavoriteUrlCallback(int ime_result);
void AfterExtractFolderCallback(int ime_result);
void AfterExtractRemoteFolderCallback(int ime_result);
void AfterZipFileCallback(int ime_result);
void AferServerChangeCallback(int ime_result);
void AfterHttpPortChangeCallback(int ime_result);
+502 -119
View File
@@ -9,18 +9,24 @@
#include <minizip/zip.h>
#include <un7zip.h>
#include <unrar.h>
#include <archive.h>
#include <archive_entry.h>
#include "clients/remote_client.h"
#include "config.h"
#include "common.h"
#include "fs.h"
#include "ime_dialog.h"
#include "lang.h"
#include "system.h"
#include "windows.h"
#include "util.h"
#include "zip_util.h"
#define TRANSFER_SIZE (128 * 1024)
namespace ZipUtil
{
static char filename_extracted[256];
static char password[128];
void callback_7zip(const char *fileName, unsigned long fileSize, unsigned fileNum, unsigned numFiles)
{
@@ -90,12 +96,12 @@ namespace ZipUtil
}
// Add file to zip
void *buf = memalign(4096, TRANSFER_SIZE);
void *buf = memalign(4096, ARCHIVE_TRANSFER_SIZE);
uint64_t seek = 0;
while (1)
{
int read = FS::Read(fd, buf, TRANSFER_SIZE);
int read = FS::Read(fd, buf, ARCHIVE_TRANSFER_SIZE);
if (read < 0)
{
free(buf);
@@ -217,153 +223,530 @@ namespace ZipUtil
return 1;
}
CompressFileType getCompressFileType(const std::string &file)
/* duplicate a path name, possibly converting to lower case */
static char *pathdup(const char *path)
{
char buf[8];
char *str;
size_t i, len;
memset(buf, 0, 8);
int ret = FS::Head(file, buf, 8);
if (ret == 0)
return COMPRESS_FILE_TYPE_UNKNOWN;
if (path == NULL || path[0] == '\0')
return (NULL);
if (strncmp(buf, (const char *)MAGIC_7Z_1, 6) == 0)
return COMPRESS_FILE_TYPE_7Z;
else if (strncmp(buf, (const char *)MAGIC_RAR_1, 7) == 0 || strncmp(buf, (const char *)MAGIC_RAR_2, 8) == 0)
return COMPRESS_FILE_TYPE_RAR;
else if (strncmp(buf, (const char *)MAGIC_ZIP_1, 4) == 0 || strncmp(buf, (const char *)MAGIC_ZIP_2, 4) == 0 || strncmp(buf, (const char *)MAGIC_ZIP_3, 4) == 0)
return COMPRESS_FILE_TYPE_ZIP;
len = strlen(path);
while (len && path[len - 1] == '/')
len--;
if ((str = (char *)malloc(len + 1)) == NULL)
{
errno = ENOMEM;
}
memcpy(str, path, len);
return COMPRESS_FILE_TYPE_UNKNOWN;
str[len] = '\0';
return (str);
}
int ExtractZip(const DirEntry &file, const std::string &dir)
/* concatenate two path names */
static char *pathcat(const char *prefix, const char *path)
{
file_transfering = true;
unz_global_info global_info;
unz_file_info file_info;
unzFile zipfile = unzOpen(file.path);
std::string dest_dir = std::string(dir);
if (dest_dir[dest_dir.length() - 1] != '/')
{
dest_dir = dest_dir + "/";
}
if (zipfile == NULL)
{
return 0;
}
unzGetGlobalInfo(zipfile, &global_info);
unzGoToFirstFile(zipfile);
uint64_t curr_extracted_bytes = 0;
uint64_t curr_file_bytes = 0;
int num_files = global_info.number_entry;
char fname[512];
char ext_fname[512];
char read_buffer[TRANSFER_SIZE];
char *str;
size_t prelen, len;
for (int zip_idx = 0; zip_idx < num_files; ++zip_idx)
prelen = prefix ? strlen(prefix) + 1 : 0;
len = strlen(path) + 1;
if ((str = (char *)malloc(prelen + len)) == NULL)
{
if (stop_activity)
break;
unzGetCurrentFileInfo(zipfile, &file_info, fname, 512, NULL, 0, NULL, 0);
sprintf(ext_fname, "%s%s", dest_dir.c_str(), fname);
const size_t filename_length = strlen(ext_fname);
bytes_transfered = 0;
bytes_to_download = file_info.uncompressed_size;
if (ext_fname[filename_length - 1] != '/')
{
snprintf(activity_message, 255, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, fname);
curr_file_bytes = 0;
unzOpenCurrentFile(zipfile);
FS::MkDirs(ext_fname, true);
FILE *f = fopen(ext_fname, "wb");
while (curr_file_bytes < file_info.uncompressed_size)
{
int rbytes = unzReadCurrentFile(zipfile, read_buffer, TRANSFER_SIZE);
if (rbytes > 0)
{
fwrite(read_buffer, 1, rbytes, f);
curr_extracted_bytes += rbytes;
curr_file_bytes += rbytes;
bytes_transfered = curr_file_bytes;
}
}
fclose(f);
unzCloseCurrentFile(zipfile);
}
else
{
FS::MkDirs(ext_fname, true);
}
if ((zip_idx + 1) < num_files)
{
unzGoToNextFile(zipfile);
}
errno = ENOMEM;
}
unzClose(zipfile);
return 1;
if (prefix)
{
memcpy(str, prefix, prelen); /* includes zero */
str[prelen - 1] = '/'; /* splat zero */
}
memcpy(str + prelen, path, len); /* includes zero */
return (str);
}
int Extract7Zip(const DirEntry &file, const std::string &dir)
/*
* Extract a directory.
*/
static void extract_dir(struct archive *a, struct archive_entry *e, const std::string &path)
{
file_transfering = false;
FS::MkDirs(dir, true);
sprintf(filename_extracted, "%s", file.name);
int res = Extract7zFileEx(file.path, dir.c_str(), callback_7zip, DEFAULT_IN_BUF_SIZE);
return res == 0;
int mode;
if (path[0] == '\0')
return;
FS::MkDirs(path);
archive_read_data_skip(a);
}
int ExtractRar(const DirEntry &file, const std::string &dir)
/*
* Extract to a file descriptor
*/
static int extract2fd(struct archive *a, const std::string &pathname, int fd)
{
file_transfering = false;
HANDLE hArcData; // Archive Handle
struct RAROpenArchiveDataEx rarOpenArchiveData;
struct RARHeaderDataEx rarHeaderData;
char destPath[256];
ssize_t len;
unsigned char *buffer = (unsigned char *) malloc(ARCHIVE_TRANSFER_SIZE);
bytes_transfered = 0;
memset(&rarOpenArchiveData, 0, sizeof(rarOpenArchiveData));
memset(&rarHeaderData, 0, sizeof(rarHeaderData));
sprintf(destPath, "%s", dir.c_str());
rarOpenArchiveData.ArcName = (char *)file.path;
rarOpenArchiveData.CmtBuf = NULL;
rarOpenArchiveData.CmtBufSize = 0;
rarOpenArchiveData.OpenMode = RAR_OM_EXTRACT;
hArcData = RAROpenArchiveEx(&rarOpenArchiveData);
if (rarOpenArchiveData.OpenResult != ERAR_SUCCESS)
/* loop over file contents and write to fd */
for (int n = 0;; n++)
{
return 0;
}
len = archive_read_data(a, buffer, ARCHIVE_TRANSFER_SIZE);
while (RARReadHeaderEx(hArcData, &rarHeaderData) == ERAR_SUCCESS)
{
sprintf(activity_message, "%s %s: %s", lang_strings[STR_EXTRACTING], file.name, rarHeaderData.FileName);
if (RARProcessFile(hArcData, RAR_EXTRACT, destPath, NULL) != ERAR_SUCCESS)
if (len == 0)
{
RARCloseArchive(hArcData);
free(buffer);
return 1;
}
if (len < 0)
{
sprintf(status_message, "error archive_read_data('%s')", pathname.c_str());
free(buffer);
return 0;
}
bytes_transfered += len;
if (write(fd, buffer, len) != len)
{
sprintf(status_message, "error write('%s')", pathname.c_str());
free(buffer);
return 0;
}
}
RARCloseArchive(hArcData);
free(buffer);
return 1;
}
int Extract(const DirEntry &file, const std::string &dir)
/*
* Extract a regular file.
*/
static void extract_file(struct archive *a, struct archive_entry *e, const std::string &path)
{
CompressFileType fileType = getCompressFileType(file.path);
struct stat sb;
int fd;
const char *linkname;
if (fileType == COMPRESS_FILE_TYPE_ZIP)
return ExtractZip(file, dir);
else if (fileType == COMPRESS_FILE_TYPE_7Z)
return Extract7Zip(file, dir);
else if (fileType == COMPRESS_FILE_TYPE_RAR)
return ExtractRar(file, dir);
/* look for existing file of same name */
recheck:
if (lstat(path.c_str(), &sb) == 0)
{
(void)unlink(path.c_str());
}
/* process symlinks */
linkname = archive_entry_symlink(e);
if (linkname != NULL)
{
if (symlink(linkname, path.c_str()) != 0)
{
sprintf(status_message, "error symlink('%s')", path.c_str());
return;
}
/* set access and modification time */
return;
}
bytes_to_download = archive_entry_size(e);
if ((fd = open(path.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0777)) < 0)
{
sprintf(status_message, "error open('%s')", path.c_str());
return;
}
extract2fd(a, path, fd);
/* set access and modification time */
if (close(fd) != 0)
{
return;
}
}
static void extract(struct archive *a, struct archive_entry *e, const std::string &base_dir)
{
char *pathname, *realpathname;
mode_t filetype;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
return;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL)
{
archive_read_data_skip(a);
free(pathname);
return;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISDIR(filetype) && !S_ISREG(filetype) && !S_ISLNK(filetype))
{
archive_read_data_skip(a);
free(pathname);
return;
}
realpathname = pathcat(base_dir.c_str(), pathname);
/* ensure that parent directory exists */
FS::MkDirs(realpathname, true);
if (S_ISDIR(filetype))
extract_dir(a, e, realpathname);
else
{
sprintf(status_message, "%s - %s", file.name, lang_strings[STR_UNSUPPORTED_FILE_FORMAT]);
return -1;
snprintf(activity_message, 255, "%s: %s", lang_strings[STR_EXTRACTING], pathname);
extract_file(a, e, realpathname);
}
free(realpathname);
free(pathname);
}
/*
* Callback function for reading passphrase.
* Originally from cpio.c and passphrase.c, libarchive.
*/
static const char *passphrase_callback(struct archive *a, void *_client_data)
{
Dialog::initImeDialog(lang_strings[STR_PASSWORD], password, 127, ORBIS_TYPE_DEFAULT, 560, 200);
int ime_result = Dialog::updateImeDialog();
if (ime_result == IME_DIALOG_RESULT_FINISHED || ime_result == IME_DIALOG_RESULT_CANCELED)
{
if (ime_result == IME_DIALOG_RESULT_FINISHED)
{
snprintf(password, 127, "%s", (char *)Dialog::getImeDialogInputText());
return password;
}
else
{
memset(password, 0, sizeof(password));
}
}
memset(password, 0, sizeof(password));
return password;
}
static RemoteArchiveData *OpenRemoteArchive(const std::string &file, RemoteClient *client)
{
RemoteArchiveData *data;
data = (RemoteArchiveData *)malloc(sizeof(RemoteArchiveData));
memset(data, 0, sizeof(RemoteArchiveData));
data->offset = 0;
client->Size(file, &data->size);
data->client = client;
data->path = file;
return data;
}
static ssize_t ReadRemoteArchive(struct archive *a, void *client_data, const void **buff)
{
ssize_t to_read;
int ret;
RemoteArchiveData *data;
data = (RemoteArchiveData *)client_data;
*buff = data->buf;
to_read = data->size - data->offset;
if (to_read == 0)
return 0;
to_read = MIN(to_read, ARCHIVE_TRANSFER_SIZE);
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
if (ret == 0)
return -1;
data->offset = data->offset + to_read;
return to_read;
}
static int CloseRemoteArchive(struct archive *a, void *client_data)
{
if (client_data != nullptr)
free(client_data);
return 0;
}
/*
* Main loop: open the zipfile, iterate over its contents and decide what
* to do with each entry.
*/
int Extract(const DirEntry &file, const std::string &basepath, RemoteClient *client)
{
struct archive *a;
struct archive_entry *e;
RemoteArchiveData *client_data = nullptr;
int ret;
uintmax_t total_size, file_count, error_count;
if ((a = archive_read_new()) == NULL)
sprintf(status_message, "%s", "archive_read_new failed");
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
archive_read_set_passphrase_callback(a, NULL, &passphrase_callback);
if (client == nullptr)
{
ret = archive_read_open_filename(a, file.path, ARCHIVE_TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
}
else
{
client_data = OpenRemoteArchive(file.path, client);
if (client_data == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return 0;
}
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
if (ret < ARCHIVE_OK)
{
if (client_data != nullptr)
{
free(client_data);
}
sprintf(status_message, "%s", "archive_read_open failed");
return 0;
}
}
for (;;)
{
if (stop_activity)
break;
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
archive_read_free(a);
return 0;
}
if (ret == ARCHIVE_EOF)
break;
extract(a, e, basepath);
}
archive_read_free(a);
return 1;
}
ArchiveEntry *GetPackageEntry(const std::string &zip_file, RemoteClient *client)
{
struct archive *a;
struct archive_entry *e;
RemoteArchiveData *client_data = nullptr;
char *pathname;
mode_t filetype;
ArchiveEntry *pkg_entry = nullptr;
int ret;
if ((a = archive_read_new()) == NULL)
sprintf(status_message, "%s", "archive_read_new failed");
archive_read_support_format_all(a);
archive_read_support_filter_all(a);
archive_read_set_passphrase_callback(a, NULL, &passphrase_callback);
if (client == nullptr)
{
ret = archive_read_open_filename(a, zip_file.c_str(), ARCHIVE_TRANSFER_SIZE);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
}
else
{
client_data = OpenRemoteArchive(zip_file, client);
if (client_data == nullptr)
{
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
if (ret < ARCHIVE_OK)
{
if (client_data != nullptr)
{
free(client_data);
}
sprintf(status_message, "%s", "archive_read_open_filename failed");
return nullptr;
}
}
for (;;)
{
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
if (client_data != nullptr)
{
free(client_data);
}
archive_read_free(a);
return nullptr;
}
if (ret == ARCHIVE_EOF)
break;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
continue;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL)
{
archive_read_data_skip(a);
free(pathname);
continue;
;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISREG(filetype))
{
archive_read_data_skip(a);
free(pathname);
continue;
}
if (Util::EndsWith(Util::ToLower(pathname), ".pkg"))
{
pkg_entry = (ArchiveEntry *)malloc(sizeof(ArchiveEntry));
memset(pkg_entry, 0, sizeof(ArchiveEntry));
pkg_entry->archive = a;
pkg_entry->entry = e;
pkg_entry->client_data = client_data;
pkg_entry->filename = pathname;
pkg_entry->filesize = archive_entry_size(e);
free(pathname);
return pkg_entry;
}
free(pathname);
}
archive_read_free(a);
return nullptr;
}
ArchiveEntry *GetNextPackageEntry(ArchiveEntry *archive_entry)
{
struct archive *a = archive_entry->archive;
struct archive_entry *e = nullptr;
RemoteArchiveData *client_data = archive_entry->client_data;
char *pathname;
mode_t filetype;
ArchiveEntry *pkg_entry = nullptr;
int ret;
for (;;)
{
ret = archive_read_next_header(a, &e);
if (ret < ARCHIVE_OK)
{
sprintf(status_message, "%s", "archive_read_next_header failed");
if (client_data != nullptr)
{
free(client_data);
}
archive_read_free(a);
return nullptr;
}
if (ret == ARCHIVE_EOF)
break;
if ((pathname = pathdup(archive_entry_pathname(e))) == NULL)
{
archive_read_data_skip(a);
continue;
}
filetype = archive_entry_filetype(e);
/* sanity checks */
if (pathname[0] == '/' ||
strncmp(pathname, "../", 3) == 0 ||
strstr(pathname, "/../") != NULL)
{
archive_read_data_skip(a);
free(pathname);
continue;
;
}
/* I don't think this can happen in a zipfile.. */
if (!S_ISREG(filetype))
{
archive_read_data_skip(a);
free(pathname);
continue;
}
if (Util::EndsWith(Util::ToLower(pathname), ".pkg"))
{
pkg_entry = (ArchiveEntry *)malloc(sizeof(ArchiveEntry));
memset(pkg_entry, 0, sizeof(ArchiveEntry));
pkg_entry->archive = a;
pkg_entry->entry = e;
pkg_entry->client_data = client_data;
pkg_entry->filename = pathname;
pkg_entry->filesize = archive_entry_size(e);
free(pathname);
return pkg_entry;
}
free(pathname);
}
archive_read_free(a);
return nullptr;
}
}
+25 -1
View File
@@ -5,9 +5,13 @@
#include <stdlib.h>
#include <minizip/unzip.h>
#include <minizip/zip.h>
#include <archive.h>
#include <archive_entry.h>
#include "common.h"
#include "fs.h"
#define ARCHIVE_TRANSFER_SIZE 5242880
static uint8_t MAGIC_ZIP_1[4] = {0x50, 0x4B, 0x03, 0x04};
static uint8_t MAGIC_ZIP_2[4] = {0x50, 0x4B, 0x05, 0x06};
static uint8_t MAGIC_ZIP_3[4] = {0x50, 0x4B, 0x07, 0x08};
@@ -24,9 +28,29 @@ enum CompressFileType {
COMPRESS_FILE_TYPE_UNKNOWN
};
struct RemoteArchiveData
{
std::string path;
ssize_t size;
ssize_t offset;
uint8_t buf[ARCHIVE_TRANSFER_SIZE];
RemoteClient *client;
};
struct ArchiveEntry
{
struct archive *archive;
struct archive_entry *entry;
std::string filename;
size_t filesize;
RemoteArchiveData *client_data;
};
namespace ZipUtil
{
int ZipAddPath(zipFile zf, const std::string &path, int filename_start, int level);
int Extract(const DirEntry &file, const std::string &dir);
int Extract(const DirEntry &file, const std::string &dir, RemoteClient *client = nullptr);
ArchiveEntry *GetPackageEntry(const std::string &zip_file, RemoteClient *client = nullptr);
ArchiveEntry *GetNextPackageEntry(ArchiveEntry *archive_entry);
}
#endif