Compare commits

..

25 Commits

Author SHA1 Message Date
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
34 changed files with 2283 additions and 561 deletions
+8 -1
View File
@@ -42,6 +42,7 @@ add_executable(ezremote_client
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
@@ -66,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.17" 32 0)
target_link_libraries(ezremote_client
c
@@ -93,6 +95,11 @@ target_link_libraries(ezremote_client
minizip
un7zip
unrar
bz2
b2
lzma
lz4
archive
json-c
ssh2
kernel
+1
View File
@@ -172,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.
+4
View File
@@ -156,3 +156,7 @@ STR_CANT_EXTRACT_URL_MSG=Couldn't extract download url
STR_FAIL_INSTALL_FROM_URL_MSG=Failed to install from URL
STR_INVALID_URL=InValid URL
STR_ALLDEBRID_API_KEY_MISSING_MSG=To use this function, an API Key needs to be configured in the ezRemote Client settings
STR_LANGUAGE=Language
STR_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
+147 -3
View File
@@ -28,6 +28,7 @@
#include "web/request.hpp"
#include "web/urn.hpp"
#include "system.h"
#include "sfo.h"
#include "zip_util.h"
namespace Actions
@@ -464,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;
@@ -709,7 +711,9 @@ namespace Actions
else
{
std::string url = INSTALLER::getRemoteUrl(it->path, true);
if (INSTALLER::InstallRemotePkg(url, &header, true) == 0)
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
failed++;
else
success++;
@@ -719,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++;
}
@@ -748,6 +783,41 @@ namespace Actions
}
}
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;
@@ -771,7 +841,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));
@@ -802,6 +872,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++;
}
@@ -873,6 +974,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);
@@ -1583,7 +1727,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
+25 -1
View File
@@ -42,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]);
@@ -280,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)
+1
View File
@@ -16,6 +16,7 @@ public:
BaseClient();
~BaseClient();
int Connect(const std::string &url, const std::string &username, const std::string &password);
int Connect(const std::string &url, const std::string &api_key);
int Mkdir(const std::string &path);
int Rmdir(const std::string &path, bool recursive);
int Size(const std::string &path, int64_t *size);
+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"))
{
+1 -2
View File
@@ -8,7 +8,6 @@
#include "util.h"
#include "system.h"
#include "windows.h"
#include "dbglogger.h"
using httplib::Client;
using httplib::Headers;
@@ -161,7 +160,7 @@ std::vector<DirEntry> RCloneClient::ListDir(const std::string &path)
lxb_dom_node_t *size_node = NextChildElement(td_element);
value = lxb_dom_node_text_content(size_node->first_child, &value_len);
tmp_string = std::string((const char *)value, value_len);
entry.file_size = atoi(tmp_string.c_str());
entry.file_size = atol(tmp_string.c_str());
DirEntry::SetDisplaySize(&entry);
}
+2 -1
View File
@@ -20,7 +20,8 @@ enum RemoteActions
REMOTE_ACTION_INSTALL = 256,
REMOTE_ACTION_EDIT = 512,
REMOTE_ACTION_NEW_FILE = 1024,
REMOTE_ACTION_ALL = 2047
REMOTE_ACTION_EXTRACT = 2048,
REMOTE_ACTION_ALL = 4095
};
enum ClientType
+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);
+54 -6
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,7 +38,9 @@ bool auto_delete_tmp_pkg;
int max_edit_file_size;
GoogleAppInfo gg_app;
bool show_hidden_files;
char alldebrid_api_key[32];
char alldebrid_api_key[64];
char realdebrid_api_key[64];
char temp_folder[256];
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
@@ -152,6 +155,10 @@ 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"};
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" };
@@ -167,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, "/"));
@@ -182,22 +189,45 @@ namespace CONFIG
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
// alldebrid api key
char tmp_api_key[512];
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, ""));
std::string encrypted_api_key;
if (strlen(tmp_api_key) > 0)
{
std::string decrypted__api_key;
int ret = Decrypt(tmp_api_key, decrypted__api_key);
std::string decrypted_api_key;
int ret = Decrypt(tmp_api_key, decrypted_api_key);
if (ret == 0)
sprintf(alldebrid_api_key, "%s", tmp_api_key);
else
sprintf(alldebrid_api_key, "%s", decrypted__api_key.c_str());
sprintf(alldebrid_api_key, "%s", decrypted_api_key.c_str());
Encrypt(alldebrid_api_key, encrypted_api_key);
}
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
// realdebrid api key
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_REALDEBRID_API_KEY, ""));
encrypted_api_key = "";
if (strlen(tmp_api_key) > 0)
{
std::string decrypted_api_key;
int ret = Decrypt(tmp_api_key, decrypted_api_key);
if (ret == 0)
sprintf(realdebrid_api_key, "%s", tmp_api_key);
else
sprintf(realdebrid_api_key, "%s", decrypted_api_key.c_str());
Encrypt(realdebrid_api_key, encrypted_api_key);
}
WriteString(CONFIG_GLOBAL, CONFIG_REALDEBRID_API_KEY, encrypted_api_key.c_str());
// Load Google Account Info
sprintf(gg_app.client_id, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, ""));
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
@@ -378,19 +408,37 @@ namespace CONFIG
Encrypt(alldebrid_api_key, encrypted_api_key);
else
encrypted_api_key = std::string(alldebrid_api_key);
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
if (strlen(realdebrid_api_key) > 0)
Encrypt(realdebrid_api_key, encrypted_api_key);
else
encrypted_api_key = std::string(realdebrid_api_key);
WriteString(CONFIG_GLOBAL, CONFIG_REALDEBRID_API_KEY, encrypted_api_key.c_str());
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str());
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions);
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
WriteString(CONFIG_GLOBAL, CONFIG_LANGUAGE, language);
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)
+7 -1
View File
@@ -17,6 +17,7 @@
#define TMP_EDITOR_FILE DATA_PATH "/tmp_editor.txt"
#define TMP_SFO_PATH DATA_PATH "/tmp_pkg.sfo"
#define TMP_ICON_PATH DATA_PATH "/tmp_icon.png"
#define TMP_FOLDER_PATH DATA_PATH "/tmp"
#define CONFIG_GLOBAL "Global"
@@ -58,6 +59,7 @@
#define CONFIG_REMOTE_DEFAULT_DIRECTORY "remote_server_default_directory"
#define CONFIG_ALLDEBRID_API_KEY "alldebrid_api_key"
#define CONFIG_REALDEBRID_API_KEY "realdebrid_api_key"
#define CONFIG_VERSION "config_version"
#define CONFIG_VERSION_NUM 1
@@ -70,6 +72,7 @@
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
#define CONFIG_LOCAL_DIRECTORY "local_directory"
#define CONFIG_TMP_FOLDER_PATH "temp_folder"
#define CONFIG_LANGUAGE "language"
@@ -126,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;
@@ -137,7 +141,9 @@ extern unsigned char cipher_key[32];
extern unsigned char cipher_iv[16];
extern GoogleAppInfo gg_app;
extern bool show_hidden_files;
extern char alldebrid_api_key[32];
extern char alldebrid_api_key[64];
extern char realdebrid_api_key[64];
extern char temp_folder[256];
namespace CONFIG
{
+6 -13
View File
@@ -2,17 +2,16 @@
#include <string>
#include <vector>
#include <map>
#include "openssl/md5.h"
#include "filehost.h"
#include "1fichier.h"
#include "filehost/alldebrid.h"
#include "filehost/realdebrid.h"
#include "filehost/directhost.h"
#include "filehost/gdrive.h"
#include "filehost/mediafire.h"
#include "filehost/pixeldrain.h"
#include "config.h"
#include "base64.h"
#include "util.h"
#define GDRIVE_REGEX "https:\\/\\/drive\\.google\\.com\\/(.*)"
@@ -22,20 +21,12 @@
static std::map<std::string, std::string> cache_downloal_urls;
std::string FileHost::Hash()
std::string FileHost::GetUrl()
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)this->url.c_str(), this->url.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
return url;
}
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid, bool use_realdebrid)
{
std::regex google_re(GDRIVE_REGEX);
std::regex mediafire_re(MEDIAFIRE_REGEX);
@@ -44,6 +35,8 @@ FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
if (use_alldebrid)
return new AllDebridHost(url);
else if (use_realdebrid)
return new RealDebridHost(url);
else if (std::regex_match(url, google_re))
return new GDriveHost(url);
else if (std::regex_match(url, mediafire_re))
+2 -2
View File
@@ -11,9 +11,9 @@ public:
virtual ~FileHost(){};
virtual bool IsValidUrl() = 0;
virtual std::string GetDownloadUrl() = 0;
std::string GetUrl();
std::string Hash();
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false);
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false, bool use_realdebrid = false);
static std::string GetCachedDownloadUrl(std::string &hash);
static void AddCacheDownloadUrl(std::string &hash, std::string &url);
+68
View File
@@ -0,0 +1,68 @@
#include <http/httplib.h>
#include <json-c/json.h>
#include "config.h"
#include "common.h"
#include "realdebrid.h"
RealDebridHost::RealDebridHost(const std::string &url) : FileHost(url)
{
}
bool RealDebridHost::IsValidUrl()
{
httplib::Client tmp_client("https://api.real-debrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
tmp_client.set_bearer_token_auth(realdebrid_api_key);
std::string path = std::string("/rest/1.0/unrestrict/check");
std::string post_data = std::string("link=") + httplib::detail::encode_url(this->url) + "&password=";
auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded");
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
uint64_t supported = json_object_get_uint64(json_object_object_get(jobj, "supported"));
if (supported == 1)
return true;
}
return false;
}
std::string RealDebridHost::GetDownloadUrl()
{
httplib::Client tmp_client("https://api.real-debrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
tmp_client.set_bearer_token_auth(realdebrid_api_key);
std::string path = std::string("/rest/1.0/unrestrict/link");
std::string post_data = std::string("link=") + httplib::detail::encode_url(this->url) + "&password=&remote=0";
auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded");
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *download = json_object_get_string(json_object_object_get(jobj, "download"));
if (download != nullptr)
{
return std::string(download);
}
else
{
return "";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef REALDEBRID_HOST_H
#define REALDEBRID_HOST_H
#include "filehost.h"
class RealDebridHost : public FileHost
{
public:
RealDebridHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+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;
+338 -10
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 &&
@@ -145,7 +246,7 @@ namespace INSTALLER
return true;
}
int InstallRemotePkg(const std::string &url, pkg_header *header, bool prompt)
int InstallRemotePkg(const std::string &url, pkg_header *header, std::string title, bool prompt)
{
if (url.empty())
return 0;
@@ -153,6 +254,7 @@ namespace INSTALLER
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 = title.length() > 0 ? title : cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
@@ -196,7 +298,7 @@ namespace INSTALLER
params.entitlementType = 5;
params.id = (char *)header->pkg_content_id;
params.contentUrl = url.c_str();
params.contentName = cid.c_str();
params.contentName = display_title.c_str();
params.iconPath = "";
params.playgoScenarioId = "0";
params.option = ORBIS_BGFT_TASK_OPT_DISABLE_CDN_QUERY_PARAM;
@@ -215,7 +317,7 @@ namespace INSTALLER
{
if (prompt)
{
sprintf(confirm_message, "%s - %s?", cid.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;
@@ -230,7 +332,9 @@ namespace INSTALLER
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
goto err;
}
goto retry;
}
}
@@ -243,15 +347,16 @@ namespace INSTALLER
}
}
else if (ret > 0)
{
goto err;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
goto err;
}
Util::Notify("%s queued", cid.c_str());
Util::Notify("%s queued", display_title.c_str());
if (prompt)
{
@@ -299,6 +404,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));
@@ -306,7 +414,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";
@@ -331,7 +439,7 @@ namespace INSTALLER
if (ret)
return 0;
Util::Notify("%s queued", path.c_str());
Util::Notify("%s queued", display_title.c_str());
file_transfering = true;
bytes_to_download = 100;
@@ -373,6 +481,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;
@@ -381,7 +492,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";
@@ -394,7 +505,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;
@@ -429,7 +540,7 @@ namespace INSTALLER
if (!remove_after_install)
{
Util::Notify("%s queued", filename.c_str());
Util::Notify("%s queued", display_title.c_str());
return 1;
}
@@ -600,4 +711,221 @@ 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;
}
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;
}
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, bool prompt = false);
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 -159
View File
@@ -10,164 +10,168 @@ char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE] = {
// This is properly populated so that emulator won't crash if an user launches it without language INI files.
char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"Connection Settings", // STR_CONNECTION_SETTINGS
"Site", // STR_SITE
"Local", // STR_LOCAL
"Remote", // STR_REMOTE
"Messages", // STR_MESSAGES
"Update Software", // STR_UPDATE_SOFTWARE
"Connect", // STR_CONNECT
"Disconnect", // STR_DISCONNECT
"Search", // STR_SEARCH
"Refresh", // STR_REFRESH
"Server", // STR_SERVER
"Username", // STR_USERNAME
"Password", // STR_PASSWORD
"Port", // STR_PORT
"Pasv", // STR_PASV
"Directory", // STR_DIRECTORY
"Filter", // STR_FILTER
"Yes", // STR_YES
"No", // STR_NO
"Cancel", // STR_CANCEL
"Continue", // STR_CONTINUE
"Close", // STR_CLOSE
"Folder", // STR_FOLDER
"File", // STR_FILE
"Type", // STR_TYPE
"Name", // STR_NAME
"Size", // STR_SIZE
"Date", // STR_DATE
"New Folder", // STR_NEW_FOLDER
"Rename", // STR_RENAME
"Delete", // STR_DELETE
"Upload", // STR_UPLOAD
"Download", // STR_DOWNLOAD
"Select All", // STR_SELECT_ALL
"Clear All", // STR_CLEAR_ALL
"Uploading", // STR_UPLOADING
"Downloading", // STR_DOWNLOADING
"Overwrite", // STR_OVERWRITE
"Don't Overwrite", // STR_DONT_OVERWRITE
"Ask for Confirmation", // STR_ASK_FOR_CONFIRM
"Don't Ask for Confirmation", // STR_DONT_ASK_CONFIRM
"Always use this option and don't ask again", // STR_ALLWAYS_USE_OPTION
"Actions", // STR_ACTIONS
"Confirm", // STR_CONFIRM
"Overwrite Options", // STR_OVERWRITE_OPTIONS
"Properties", // STR_PROPERTIES
"Progress", // STR_PROGRESS
"Updates", // STR_UPDATES
"Are you sure you want to delete this file(s)/folder(s)?", // STR_DEL_CONFIRM_MSG
"Canceling. Waiting for last action to complete", // STR_CANCEL_ACTION_MSG
"Failed to upload file", // STR_FAIL_UPLOAD_MSG
"Failed to download file", // STR_FAIL_DOWNLOAD_MSG
"Failed to read contents of directory or folder does not exist.", // STR_FAIL_READ_LOCAL_DIR_MSG
"426 Connection closed.", // STR_CONNECTION_CLOSE_ERR_MSG
"426 Remote Server has terminated the connection.", // STR_REMOTE_TERM_CONN_MSG
"300 Failed Login. Please check your username or password.", // STR_FAIL_LOGIN_MSG
"426 Failed. Connection timeout.", // STR_FAIL_TIMEOUT_MSG
"Failed to delete directory", // STR_FAIL_DEL_DIR_MSG
"Deleting", // STR_DELETING
"Failed to delete file", // STR_FAIL_DEL_FILE_MSG
"Deleted", // STR_DELETED
"Link", // STR_LINK
"Share", // STR_SHARE
"310 Failed", // STR_FAILED
"310 Failed to create file on local", // STR_FAIL_CREATE_LOCAL_FILE_MSG
"Install", // STR_INSTALL
"Installing", // STR_INSTALLING
"Success", // STR_INSTALL_SUCCESS
"Failed", // STR_INSTALL_FAILED
"Skipped", // STR_INSTALL_SKIPPED
"Checking connection to remote HTTP Server", // STR_CHECK_HTTP_MSG
"Failed connecting to HTTP Server", // STR_FAILED_HTTP_CHECK
"Remote is not a HTTP Server", // STR_REMOTE_NOT_HTTP
"Package not in the /data or /mnt/usbX folder", // STR_INSTALL_FROM_DATA_MSG
"Package is already installed", // STR_ALREADY_INSTALLED_MSG
"Install from URL", // STR_INSTALL_FROM_URL
"Could not read package header info", // STR_CANNOT_READ_PKG_HDR_MSG
"Favorite URLs", // STR_FAVORITE_URLS
"Slot", // STR_SLOT
"Edit", // STR_EDIT
"One Time Url", // STR_ONETIME_URL
"Not a valid Package", // STR_NOT_A_VALID_PACKAGE
"Waiting for Package to finish installing", // STR_WAIT_FOR_INSTALL_MSG
"Failed to install pkg file. Please delete the tmp pkg manually", // STR_FAIL_INSTALL_TMP_PKG_MSG
"Failed to obtain download URL", // STR_FAIL_TO_OBTAIN_GG_DL_MSG
"Auto delete temporary downloaded pkg file after install", // STR_AUTO_DELETE_TMP_PKG
"Protocol not supported", // STR_PROTOCOL_NOT_SUPPORTED
"Could not resolve hostname", // STR_COULD_NOT_RESOLVE_HOST
"Extract", // STR_EXTRACT
"Extracting", // STR_EXTRACTING
"Failed to extract", // STR_FAILED_TO_EXTRACT
"Extract Location", // STR_EXTRACT_LOCATION
"Compress", // STR_COMPRESS
"Zip Filename", // STR_ZIP_FILE_PATH
"Compressing", // STR_COMPRESSING
"Error occured while creating zip", // STR_ERROR_CREATE_ZIP
"Unsupported compressed file format", // STR_UNSUPPORTED_FILE_FORMAT
"Cut", // STR_CUT
"Copy", // STR_COPY
"Paste", // STR_PASTE
"Moving", // STR_MOVING
"Copying", // STR_COPYING
"Failed to move file", // STR_FAIL_MOVE_MSG
"Failed to copy file", // STR_FAIL_COPY_MSG
"Cannot move parent directory to sub subdirectory", // STR_CANT_MOVE_TO_SUBDIR_MSG
"Cannot copy parent directory to sub subdirectory", // STR_CANT_COPY_TO_SUBDIR_MSG
"Operation not supported", // STR_UNSUPPORTED_OPERATION_MSG
"Http Port", // STR_HTTP_PORT
"The content has already been installed. Do you want to continue installing", // STR_REINSTALL_CONFIRM_MSG
"Remote package installation is not supported for protected servers.", // STR_REMOTE_NOT_SUPPORT_MSG
"Remote HTTP Server not reachable.", // STR_CANNOT_CONNECT_REMOTE_MSG
"Remote Package Install not possible. Would you like to download package and install?", // STR_DOWNLOAD_INSTALL_MSG
"Checking remote server for Remote Package Install.", // STR_CHECKING_REMOTE_SERVER_MSG
"RPI", // STR_ENABLE_RPI
"This option enables Remote Package Installation.", // STR_ENABLE_RPI_FTP_SMB_MSG
"This option enables Remote Package Installation.", // STR_ENABLE_RPI_WEBDAV_MSG
"Files", // STR_FILES
"Editor", // STR_EDITOR
"Save", // STR_SAVE
"Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG
"Delete Selected Line", // STR_DELETE_LINE
"Insert Below Selected Line", // STR_INSERT_LINE
"Modified", // STR_MODIFIED
"Failed to obtain an access token from", // STR_FAIL_GET_TOKEN_MSG
"Login Success. You may close the browser and return to the application", // STR_GET_TOKEN_SUCCESS_MSG
"See, edit, create, and delete all of your Google Drive files", // STR_PERM_DRIVE
"See, create, and delete its own configuration data in your Google Drive", // STR_PERM_DRIVE_APPDATA
"See, edit, create, and delete only the specific Google Drive files you use with this app", // STR_PERM_DRIVE_FILE
"View and manage metadata of files in your Google Drive", // STR_PERM_DRIVE_METADATA
"See information about your Google Drive files", // STR_PERM_DRIVE_METADATA_RO
"Google login failed", // STR_GOOGLE_LOGIN_FAIL_MSG
"Google login timed out", // STR_GOOGLE_LOGIN_TIMEOUT_MSG
"New File", // STR_NEW_FILE
"Settings", // STR_SETTINGS
"Client ID", // STR_CLIENT_ID
"Client Secret", // STR_CLIENT_SECRET
"Global", // STR_GLOBAL
"Google", // STR_GOOGLE
"Copy selected line", // STR_COPY_LINE
"Paste into selected line", // STR_PASTE_LINE
"Show hidden files", // STR_SHOW_HIDDEN_FILES
"Set Default Folder", // STR_SET_DEFAULT_DIRECTORY
"has being set as default direcotry", // STR_SET_DEFAULT_DIRECTORY_MSG
"View Image", // STR_VIEW_IMAGE
"Package Information", // STR_VIEW_PKG_INFO
"NFS export path missing in URL", // STR_NFS_EXP_PATH_MISSING_MSG
"Failed to init NFS context", // STR_FAIL_INIT_NFS_CONTEXT
"Failed to mount NFS share", // STR_FAIL_MOUNT_NFS_MSG
"Web Server", // STR_WEB_SERVER
"Enable", // STR_ENABLE
"Compressed Files Location", // STR_COMPRESSED_FILE_PATH
"Location of where compressed files are stored on the web server", // STR_COMPRESSED_FILE_PATH_MSG
"AllDebrid", // STR_ALLDEBRID
"API Key", // STR_API_KEY
"Couldn't extract download url", // STR_CANT_EXTRACT_URL_MSG
"Failed to install from URL", // STR_FAIL_INSTALL_FROM_URL_MSG
"InValid URL", // STR_INVALID_URL
"To use this function, an API Key needs to be configured in the ezRemote Client settings", // STR_ALLDEBRID_API_KEY_MISSING_MSG
"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;
@@ -181,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 -160
View File
@@ -3,165 +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) \
FUNC(STR_ALLDEBRID) \
FUNC(STR_API_KEY) \
FUNC(STR_CANT_EXTRACT_URL_MSG) \
FUNC(STR_FAIL_INSTALL_FROM_URL_MSG) \
FUNC(STR_INVALID_URL) \
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG)
#define 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,
@@ -171,7 +175,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 158
#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];
+113 -16
View File
@@ -15,6 +15,7 @@
#include "lang.h"
#include "system.h"
#include "zip_util.h"
#include "util.h"
#include "installer.h"
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
@@ -1023,9 +1024,9 @@ namespace HttpServer
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 65536ul - req.ranges[0].first;
range_len = 524288ul - req.ranges[0].first;
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)+"-524288/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
@@ -1048,19 +1049,80 @@ namespace HttpServer
}
});
svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res)
{
RemoteClient *tmp_client;
RemoteSettings *tmp_settings;
std::string hash = req.matches[1];
ArchivePkgInstallData *pkg_data = INSTALLER::GetArchivePkgInstallData(hash);
if (req.method == "HEAD")
{
res.status = 204;
res.set_header("Content-Length", std::to_string(pkg_data->archive_entry->filesize));
res.set_header("Accept-Ranges", "bytes");
return;
}
if (req.ranges.empty())
{
res.status = 200;
res.set_content_provider(
131072, "application/octet-stream",
[pkg_data](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(131072);
size_t bytes_read = pkg_data->split_file->Read(buf, 131072, offset);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
else
{
res.status = 206;
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
if (req.ranges[0].second >= 18000000000000000000ul)
{
range_len = 524288ul - req.ranges[0].first;
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)+"-524288/"+std::to_string(range_len));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
range_len, "application/octet-stream",
[pkg_data, range, range_len](size_t offset, size_t length, DataSink &sink) {
char *buf = (char*) malloc(range_len);
size_t bytes_read = pkg_data->split_file->Read(buf, range_len, range.first);
sink.write(buf, bytes_read);
free(buf);
return true;
},
[](bool success) {
return true;
});
}
});
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
{
std::string url;
const char *url_param;
bool use_alldebrid;
bool use_alldebrid = false;
bool use_realdebrid = false;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
use_realdebrid = json_object_get_boolean(json_object_object_get(jobj, "use_realdebrid"));
if (url_param == nullptr)
{
bad_request(res, "Required url_param, use_alldebrid parameter missing");
bad_request(res, "Required url_param parameter missing");
return;
}
}
@@ -1070,14 +1132,14 @@ namespace HttpServer
return;
}
if (use_alldebrid && strlen(alldebrid_api_key) == 0)
if ((use_alldebrid && strlen(alldebrid_api_key) == 0) || (use_realdebrid && strlen(realdebrid_api_key) == 0))
{
failed(res, 200, lang_strings[STR_ALLDEBRID_API_KEY_MISSING_MSG]);
return;
}
url = std::string(url_param);
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid);
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid, use_realdebrid);
if (!filehost->IsValidUrl())
{
@@ -1085,7 +1147,7 @@ namespace HttpServer
return;
}
std::string hash = filehost->Hash();
std::string hash = Util::UrlHash(filehost->GetUrl());
std::string download_url = filehost->GetDownloadUrl();
if (download_url.empty())
{
@@ -1093,7 +1155,6 @@ namespace HttpServer
return;
}
FileHost::AddCacheDownloadUrl(hash, download_url);
delete(filehost);
size_t scheme_pos = download_url.find("://");
@@ -1105,16 +1166,52 @@ namespace HttpServer
BaseClient *baseclient = new BaseClient();
baseclient->Connect(host, "", "");
baseclient->Head(path, &header, sizeof(pkg_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);
if (rc == 0)
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
return;
if (BE32(header.pkg_magic) == 0x7F434E54)
{
FileHost::AddCacheDownloadUrl(hash, download_url);
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
delete(baseclient);
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title);
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, true);
if (ret == 0)
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
return;
}
}
else
{
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
return;
}
}
success(res);
});
+221
View File
@@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdio.h>
#include <string>
#include "common.h"
#include "split_file.h"
SplitFile::SplitFile(const std::string &path, size_t block_size)
{
this->block_size = block_size;
this->path = path;
this->complete = false;
sem_init(&this->block_ready, 0, 0);
}
SplitFile::~SplitFile()
{
for (int i = 0; i < this->file_blocks.size(); i++)
{
if (this->file_blocks[i] != nullptr && this->file_blocks[i]->status != BLOCK_STATUS_DELETED)
{
if (this->file_blocks[i]->fd != nullptr)
{
fclose(this->file_blocks[i]->fd);
}
remove(this->file_blocks[i]->block_file.c_str());
free(this->file_blocks[i]);
}
}
sem_destroy(&this->block_ready);
};
int SplitFile::Open()
{
this->block_in_progress = NewBlock();
this->block_in_progress->fd = fopen(block_in_progress->block_file.c_str(), "w");
return (block_in_progress->fd == nullptr);
}
size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
{
int first_block_num, block_num;
size_t block_offset;
size_t remaining;
size_t bytes_read;
size_t total_bytes_read;
FileBlock *block;
FILE *fd;
char *p;
first_block_num= offset / this->block_size;
block_num = first_block_num;
block_offset = offset % this->block_size;
while ((block_num >= this->file_blocks.size() && !this->complete) ||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
if (block->status == BLOCK_STATUS_DELETED)
{
return -1;
}
if (block_offset > block->size - 1 && this->complete)
{
// requested offset is pass the end of split file
return 0;
}
remaining = buf_size;
bool eof = false;
total_bytes_read = 0;
p = buf;
while (remaining > 0 && !eof)
{
fd = block->fd;
if (fd == nullptr)
{
fd = fopen(block->block_file.c_str(), "rb");
block->fd = fd;
}
fseek(fd, block_offset, SEEK_SET);
bytes_read = fread(p, 1, remaining, fd);
if (bytes_read == remaining)
{
p += bytes_read;
total_bytes_read += bytes_read;
}
else
{
if (feof(fd))
{
p += bytes_read;
total_bytes_read += bytes_read;
if (block->is_last)
{
eof = true;
continue;
}
}
else
return -1;
}
remaining -= bytes_read;
if (remaining == 0)
continue;
block_num++;
block_offset = 0;
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
}
// delete blocks before the first read offset block. Assumuption, that reads are always
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
for (int j=0; j < first_block_num - 2; j++)
{
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
{
if (this->file_blocks[j]->fd != nullptr)
{
fclose(this->file_blocks[j]->fd);
this->file_blocks[j]->fd = nullptr;
}
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
remove(this->file_blocks[j]->block_file.c_str());
}
}
return total_bytes_read;
}
size_t SplitFile::Write(char *buf, size_t buf_size)
{
size_t bytes_written;
size_t block_space_remaining;
size_t bytes_to_write;
char *p = buf;
size_t total_bytes_written = 0;
size_t remaining_to_write = buf_size;
while (remaining_to_write > 0)
{
block_space_remaining = this->block_size - block_in_progress->size;
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
bytes_written = fwrite(p, 1, bytes_to_write, block_in_progress->fd);
block_in_progress->size += bytes_written;
total_bytes_written += bytes_written;
remaining_to_write -= bytes_written;
block_space_remaining -= bytes_written;
p += bytes_written;
// error if bytes_to_write != bytes_written
if (bytes_written != bytes_to_write)
{
break;
}
if (block_space_remaining == 0)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
block_in_progress->status = BLOCK_STATUS_CREATED;
this->file_blocks.push_back(block_in_progress);
sem_post(&this->block_ready);
block_in_progress = NewBlock();
}
}
return total_bytes_written;
}
int SplitFile::Close()
{
if (block_in_progress->fd != nullptr)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
}
block_in_progress->status = BLOCK_STATUS_CREATED;
block_in_progress->is_last = true;
this->file_blocks.push_back(block_in_progress);
this->complete = true;
sem_post(&this->block_ready);
return 0;
}
FileBlock *SplitFile::NewBlock()
{
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
memset(block, 0, sizeof(FileBlock));
block->is_last = false;
block->size = 0;
block->block_file = this->path + "." + std::to_string(this->file_blocks.size());
block->fd = fopen(block->block_file.c_str(), "w");
return block;
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef SPLIT_FILE_H
#define SPLIT_FILE_H
#include <string>
#include <vector>
#include <mutex>
#include <pthread.h>
enum FileBlockStatus
{
BLOCK_STATUS_NOT_EXISTS,
BLOCK_STATUS_CREATED,
BLOCK_STATUS_DELETED
};
typedef struct
{
std::string block_file;
size_t size;
FILE* fd;
bool is_last;
FileBlockStatus status;
} FileBlock;
class SplitFile
{
public:
SplitFile(const std::string& path, size_t block_size);
~SplitFile();
size_t Read(char* buf, size_t buf_size, size_t offset);
size_t Write(char* buf, size_t buf_size);
int Open();
int Close();
private:
std::vector<FileBlock*> file_blocks;
size_t write_offset;
size_t block_size;
std::string path;
int write_error;
bool complete;
FileBlock *block_in_progress;
sem_t block_ready;
FileBlock *NewBlock();
};
#endif
+22
View File
@@ -6,6 +6,8 @@
#include <algorithm>
#include <stdarg.h>
#include <orbis/libkernel.h>
#include "base64.h"
#include "openssl/md5.h"
#include "lang.h"
namespace Util
@@ -47,6 +49,13 @@ namespace Util
return s;
}
static inline bool EndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static inline std::vector<std::string> Split(const std::string &str, const std::string &delimiter)
{
std::string text = std::string(str);
@@ -66,6 +75,19 @@ namespace Util
return tokens;
}
static inline std::string UrlHash(const std::string &text)
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)text.c_str(), text.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
}
static inline void Notify(const char *fmt, ...)
{
OrbisNotificationRequest request;
+133 -32
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)))
{
@@ -1608,8 +1624,35 @@ namespace Windows
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,7 +1735,6 @@ namespace Windows
ImGui::PopStyleVar();
ImGui::Separator();
// Google settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
ImGui::Separator();
@@ -1689,14 +1749,41 @@ namespace Windows
if (strlen(alldebrid_api_key) > 0)
sprintf(id, "%s", "*********************************************##alldebrid_api_key");
else
sprintf(id, "%s", "##client_secret_input");
sprintf(id, "%s", "##alldebrid_api_key");
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = alldebrid_api_key;
ime_field_size = 31;
ime_field_size = 63;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_API_KEY], alldebrid_api_key, 31, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
Dialog::initImeDialog(lang_strings[STR_API_KEY], alldebrid_api_key, 63, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_REALDEBRID]);
ImGui::Separator();
field_size = ImGui::CalcTextSize(lang_strings[STR_API_KEY]);
width = field_size.x + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_API_KEY]);
ImGui::SameLine();
ImGui::SetCursorPosX(width);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (strlen(realdebrid_api_key) > 0)
sprintf(id, "%s", "*********************************************##realdebrid_api_key");
else
sprintf(id, "%s", "##realdebrid_api_key");
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = realdebrid_api_key;
ime_field_size = 63;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_API_KEY], realdebrid_api_key, 63, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
@@ -2000,10 +2087,19 @@ namespace Windows
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = true;
file_transfering = false;
selected_action = ACTION_NONE;
Actions::ExtractLocalZips();
break;
case ACTION_EXTRACT_REMOTE_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = false;
selected_action = ACTION_NONE;
Actions::ExtractRemoteZips();
break;
case ACTION_CREATE_LOCAL_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
@@ -2383,6 +2479,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);
+499 -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,527 @@ 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);
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;
}
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;
}
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