Compare commits

...

40 Commits

Author SHA1 Message Date
Chee Yee 7a908ebf1b improve speed of installing from compress file by increase read buffer 2024-02-10 00:27:18 -08:00
Chee Yee f83629d107 add ability to install pkg in compress file on public shares like mediafire, gdrive, pixeldrain and alldebrid 2024-02-09 21:31:59 -08:00
Chee Yee f0c0213940 fix file list navigration jumping to top of list when last item is selected 2024-02-07 23:54:25 -08:00
Chee Yee 9baf6c18fa enable extracting compress files from http servers 2024-02-07 07:38:54 -08:00
Chee Yee 263822ef66 update to install all pkgs inside compress file 2024-02-07 02:28:44 -08:00
Chee Yee 487e288635 fix rclone filesize display 2024-02-06 23:40:17 -08:00
Chee Yee 267551c979 add ability to install pkg inside compress files 2024-02-03 18:58:42 -08:00
Chee Yee b761596fe3 set extract folder to current local directory on multi select 2024-01-31 02:16:54 -08:00
Chee Yee 99568b9990 update logic for selecting default extract folder 2024-01-31 02:13:32 -08:00
Chee Yee 414a8a4b50 add ability to extract files from remote server 2024-01-31 01:47:51 -08:00
Chee Yee 628312360c clear multi selection after uploading files 2024-01-24 23:19:55 -08:00
Chee Yee b4f6a8f763 add compatibility with PS5 etaHEN ftp server 2024-01-24 20:57:35 -08:00
cy33hc acfdd00f4f Update README.md 2024-01-24 08:10:55 -08:00
Chee Yee ac55a1e5a6 add 1 more compress format to webui 2024-01-24 07:48:33 -08:00
Chee Yee ffdfa6d04d add new compression formats to web ui 2024-01-24 07:45:08 -08:00
Chee Yee 7855c9a7f4 add option to change language 2024-01-23 22:19:59 -08:00
Chee Yee f4625bce73 increase max ftp filename length to 255 2024-01-23 18:06:57 -08:00
Chee Yee 6b0808e48f add Ukrainian lang 2024-01-23 18:06:11 -08:00
Chee Yee e8eb3fa9da rebuild with support for all password protected zip files 2024-01-15 17:34:21 -08:00
Chee Yee df6a068bd3 add support for more compress formats and password protected archive 2024-01-13 19:48:07 -08:00
Chee Yee c1307d4221 fix crash for invalid smb url 2024-01-08 18:06:09 -08:00
Chee Yee 832c60862b display title name instead of id during install 2023-11-16 23:22:57 -08:00
Chee Yee 529d88af06 remove old hash from map 2023-08-30 13:37:17 -07:00
Chee Yee d26baf817e update readme 2023-08-30 08:34:22 -07:00
Chee Yee 01f2f44942 add ability to install via alldebrid 2023-08-30 02:30:26 -07:00
Chee Yee e28e562a10 add ability to install shared URL from web interface 2023-08-06 17:53:27 -07:00
Chee Yee 83661c7fcb add rclone http server support 2023-08-01 22:11:05 -07:00
Chee Yee 8aba3939a8 close nfs handle on error 2023-07-26 00:58:11 -07:00
Chee Yee 51eb0760d8 Merge branch 'master' of github.com:cy33hc/ps4-ezremote-client 2023-07-24 16:43:49 -07:00
Chee Yee 8c8d23603c proper closing of handles 2023-07-24 16:43:40 -07:00
cy33hc 338107c951 Merge pull request #11 from rex07/master
Update Arabic.ini
2023-07-24 08:10:07 -07:00
Chee Yee 499dbc1b27 update Arabic language 2023-07-23 21:47:49 -07:00
Rex_sa e02e81acc1 Update Arabic.ini 2023-07-24 04:03:17 +03:00
cy33hc d6c97303b0 Update README.md 2023-07-23 15:48:47 -07:00
Chee Yee d98284a050 fix type 2023-07-21 23:49:08 -07:00
Chee Yee 3dc2054e44 free memory 2023-07-21 23:47:53 -07:00
cy33hc b18f764d27 Update README.md 2023-07-21 20:39:12 -07:00
cy33hc 3354af7f88 Update README.md 2023-07-21 20:37:32 -07:00
Chee Yee 0dac26d98c add ability to install fpkgs directly direct from remote servers 2023-07-21 19:29:06 -07:00
Chee Yee 1f2b27b52a read the current chunk size 2023-07-17 22:04:05 -07:00
66 changed files with 3885 additions and 769 deletions
+15 -1
View File
@@ -40,6 +40,14 @@ add_executable(ezremote_client
source/clients/smbclient.cpp
source/clients/webdavclient.cpp
source/clients/sftpclient.cpp
source/clients/rclone.cpp
source/filehost/alldebrid.cpp
source/filehost/directhost.cpp
source/filehost/gdrive.cpp
source/filehost/filehost.cpp
source/filehost/1fichier.cpp
source/filehost/mediafire.cpp
source/filehost/pixeldrain.cpp
source/server/http_server.cpp
source/actions.cpp
source/config.cpp
@@ -58,11 +66,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.08" 32 0)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.15" 32 0)
target_link_libraries(ezremote_client
c
@@ -85,6 +94,11 @@ target_link_libraries(ezremote_client
minizip
un7zip
unrar
bz2
b2
lzma
lz4
archive
json-c
ssh2
kernel
+8 -2
View File
@@ -1,9 +1,13 @@
# ezRemote Client
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB, NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
![Preview](/screenshot.jpg)
**New:** As of version 1.0.8, ezRemote Client has a Web Interface that can be access from any modern browser to manage the PS4 files.
**New:** As of version 1.0.9. Remote Package Installation does not require you to host an external Http Server. The embedded Web Server built into ezRemote Client acts as a Proxy Server between the PS4 and remote server (FTP, SFTP, SMB, NFS, WebDav, HttpServer(IIS/Nginx/Apache/Serve) and GoogleDrive). There's no data written to the PS4 hard drive in the process, rather everything is streamed via embedded Web Server directly to the PS4 installer.
![Preview](/screenshot.jpg)
![Preview](/ezremote_client_web.png)
## Usage
@@ -83,7 +87,7 @@ Tested with following WebDAV server:
- drivehq.com
## Remote Package Installer Feature
Remote Package Installation only works if the WebDAV server allow anonymous access. It's a limitation of the PS4 Installer not able to access protected links. As suggested, use the [Dufs](https://github.com/sigoden/dufs) app for WebDAV.
Remote Package Installation with all Remote Server, even if they are password protected.
## Features Native Application##
- Transfer files back and forth between PS4 and FTP/SMB/NFS/WebDAV server
@@ -110,6 +114,7 @@ Remote Package Installation only works if the WebDAV server allow anonymous acce
- Upload files to the PS4
- Download files from the PS4
- Install packages on the PS4
- Install packages from shared links from mediafire, google and pixeldrain. For other filehost, they can installed via AllDebrid (See AllDebrid website for supported filehost).
## How to access the Web Interface ##
You need to launch the "ezRemote Client" app on the PS4. Then on any device(laptop, tablet, phone etc..) with web browser goto to http://<ip_address_of_ps4>:8080 . That's all.
@@ -167,6 +172,7 @@ Romanian
Ryukyuan
Thai
Turkish
Ukrainian
```
User must modify the file **/data/ezremote-client/config.ini** located in the ps4 hard drive and update the **language** setting to with the **exact** values from the list above.
+1
View File
@@ -41,6 +41,7 @@
permissionsUrl: '/__local__/permission',
installUrl: '/__local__/install',
uploadResumeSizeUrl: '__local__/uploadResumeSize',
installUrlUrl: '/__local__/install_url',
multipleDownloadFileName: 'ezremote-client.zip',
isExtractableFilePattern: /\.(7z|rar|zip)$/i,
pickCallback: function (item) {
+113 -36
View File
@@ -1,75 +1,152 @@
STR_CONNECTION_SETTINGS=إعداد الاتصال
STR_CONNECTION_SETTINGS=إعدادات الإتصال
STR_SITE=الموقع
STR_LOCAL=محلي
STR_REMOTE=بعيد
STR_MESSAGES=الرسائل
STR_UPDATE_SOFTWARE=تحديث التطبيق
STR_CONNECT=توصيل
STR_UPDATE_SOFTWARE=تحديث البرنامج
STR_CONNECT=اتصال
STR_DISCONNECT=قطع الاتصال
STR_SEARCH=بحث
STR_REFRESH=تحديث
STR_REFRESH=تنشيط
STR_SERVER=الخادم
STR_USERNAME=اسم المستخدم
STR_PASSWORD=كلمة المرور
STR_PORT=المنفذ
STR_PASV=متجاوز
STR_DIRECTORY=المسار
STR_FILTER=الفلتر
STR_FILTER=المرشح
STR_YES=نعم
STR_NO=لا
STR_CANCEL=إلغاء
STR_CANCEL=الغاء
STR_CONTINUE=استمرار
STR_CLOSE=اغلاق
STR_FOLDER=المجلد
STR_FILE=الملف
STR_FOLDER=مجلد
STR_FILE=ملف
STR_TYPE=النوع
STR_NAME=الاسم
STR_SIZE=الحجم
STR_DATE=التاريخ
STR_NEW_FOLDER=مجلد جديد
STR_RENAME=أعادة تسمية
STR_RENAME=اعادة تسمية
STR_DELETE=حذف
STR_UPLOAD=رفع
STR_DOWNLOAD=تحميل
STR_DOWNLOAD=تنزيل
STR_SELECT_ALL=تحديد الكل
STR_CLEAR_ALL=تجاهل الكل
STR_CLEAR_ALL=الغاء الكل
STR_UPLOADING=قيد الرفع
STR_DOWNLOADING=قيد التحميل
STR_OVERWRITE=الكتابة فوق
STR_DOWNLOADING=قيد التنزيل
STR_OVERWRITE=كتابة فوق
STR_DONT_OVERWRITE=لاتكتب فوق
STR_ASK_FOR_CONFIRM=أسال لتأكيد
STR_DONT_ASK_CONFIRM=لاتسأل لتأكيد
STR_ALLWAYS_USE_OPTION=استخدم هذا الاختيار بشكل دائم ولاتسأل مجددا
STR_ACTIONS=الإجراءات
STR_ASK_FOR_CONFIRM=اطلب التاكيد
STR_DONT_ASK_CONFIRM=لاتطلب التاكيد
STR_ALLWAYS_USE_OPTION=استخدم دائما هذا الخيار ولاتسال مجددا
STR_ACTIONS=الاجرءات
STR_CONFIRM=تأكيد
STR_OVERWRITE_OPTIONS=خيارات الاستبدال او الكتابة فوق
STR_PROPERTIES=الخصائص
STR_OVERWRITE_OPTIONS=خيارات الكتابة فوف
STR_PROPERTIES=الخيارات
STR_PROGRESS=التقدم
STR_UPDATES=التحديثات
STR_DEL_CONFIRM_MSG=هل انت متأكد من اجراء حذف حذف الملف او المجلد?
STR_CANCEL_ACTION_MSG=قيد الإلغاء. بأنتظار الاتصال الاخير ليتم إلغائه
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=٤٢٦ أغلق الاتصال.
STR_REMOTE_TERM_CONN_MSG=٤٢٦ الخادم البعيد قطع الإتصال.
STR_FAIL_LOGIN_MSG=٣٠٠ فشل تسجيل الدخول. الرجاء التاكد من اسم المستخدم وكلمة المرور.
STR_FAIL_TIMEOUT_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_LINK=رابط
STR_SHARE=مشاركة
STR_FAILED=٣١٠ فشل
STR_FAIL_CREATE_LOCAL_FILE_MSG= فشل في انشاء الملف في المحلي ٣١٠
STR_FAILED=310 فشل
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 فشل إنشاء ملف على المستوى المحلي
STR_INSTALL=تثبيت
STR_INSTALLING=يقوم بالتثبيت
STR_INSTALLING=قيد التثبيت
STR_INSTALL_SUCCESS=تم بنجاح
STR_INSTALL_FAILED=فشل
STR_INSTALL_SKIPPED=تم التخطي
STR_CHECK_HTTP_MSG=فحص الإتصال بخادم HTTP البعيد
STR_FAILED_HTTP_CHECK=فشل الإتصال بخادم HTTP
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_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=فشل تثبيت ملف pkg. يرجى حذف tmp pkg يدويًا
STR_FAIL_TO_OBTAIN_GG_DL_MSG=فشل الحصول على رابط تحميل قوقل
STR_AUTO_DELETE_TMP_PKG=الحذف التلقائي لملف 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=اسم الملف المضغوط
STR_COMPRESSING=قيد الضغط
STR_ERROR_CREATE_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_ENABLE_RPI=RPI
STR_ENABLE_RPI_FTP_SMB_MSG=يتيح هذا الخيار تثبيت الحزمة عن بُعد عبر خادم الويب المضمن.
STR_ENABLE_RPI_WEBDAV_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_PERM_DRIVE=يمكنك الاطلاع على جميع ملفات Google Drive وتعديلها وإنشاؤها وحذفها
STR_PERM_DRIVE_APPDATA=مشاهدة وإنشاء وحذف بيانات التكوين الخاصة به في Google Drive الخاص بك
STR_PERM_DRIVE_FILE=يمكنك مشاهدة ملفات Google Drive المحددة التي تستخدمها مع هذا التطبيق وتعديلها وإنشاؤها وحذفها فقط
STR_PERM_DRIVE_METADATA=عرض وإدارة البيانات الوصفية للملفات في Google Drive
STR_PERM_DRIVE_METADATA_RO=اطلع على معلومات حول ملفات Google Drive الخاصة بك
STR_GOOGLE_LOGIN_FAIL_MSG=فشل تسجيل الدخول إلى Google
STR_GOOGLE_LOGIN_TIMEOUT_MSG=انتهت مهلة تسجيل الدخول إلى Google
STR_NEW_FILE=ملف جديد
STR_SETTINGS=الاعدادات
STR_CLIENT_ID=معرف العميل
STR_CLIENT_SECRET=اسرار الخادم
STR_GLOBAL=عالمي
STR_GOOGLE=قوقل
STR_COPY_LINE=نسخ النص المحدد
STR_PASTE_LINE=لصق في الخط المخصص
STR_SHOW_HIDDEN_FILES=اضهار الملفات المخفيه
STR_SET_DEFAULT_DIRECTORY=تعيين المجلد الافتراضي
STR_SET_DEFAULT_DIRECTORY_MSG=تم تعيينه كمسار افتراضي
STR_VIEW_IMAGE=عرض الصور
STR_VIEW_PKG_INFO=معلومات الحزمة
STR_NFS_EXP_PATH_MISSING_MSG=مسار تصدير NFS مفقود في URL
STR_FAIL_INIT_NFS_CONTEXT=فشل في تهيئة سياق NFS
STR_FAIL_MOUNT_NFS_MSG=فشل تحميل مشاركة NFS
STR_WEB_SERVER=خادم الويب
STR_ENABLE=تمكين
STR_COMPRESSED_FILE_PATH=مسار الملف المظغوط
STR_COMPRESSED_FILE_PATH_MSG=المسار حيث يتم تخزين الملفات المضغوطة على خادم الويب
+11 -3
View File
@@ -82,7 +82,7 @@ STR_ONETIME_URL=One Time Url
STR_NOT_A_VALID_PACKAGE=Not a valid Package
STR_WAIT_FOR_INSTALL_MSG=Waiting for Package to finish installing
STR_FAIL_INSTALL_TMP_PKG_MSG=Failed to install pkg file. Please delete the tmp pkg manually
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain google download URL
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Failed to obtain download URL
STR_AUTO_DELETE_TMP_PKG=Auto delete temporary downloaded pkg file after install
STR_PROTOCOL_NOT_SUPPORTED=Protocol not supported
STR_COULD_NOT_RESOLVE_HOST=Could not resolve hostname
@@ -112,8 +112,8 @@ STR_CANNOT_CONNECT_REMOTE_MSG=Remote HTTP Server not reachable.
STR_DOWNLOAD_INSTALL_MSG=Remote Package Install not possible. Would you like to download package and install instead?
STR_CHECKING_REMOTE_SERVER_MSG=Checking remote server for Remote Package Install.
STR_ENABLE_RPI=RPI
STR_ENABLE_RPI_FTP_SMB_MSG=This option enables Remote Package Installation. This requires a HTTP Server setup on the same host sharing the same folder with anonymous access.
STR_ENABLE_RPI_WEBDAV_MSG=This option enables Remote Package Installation. This requires the Server with anonymous access that does not need username/password.
STR_ENABLE_RPI_FTP_SMB_MSG=This option enables Remote Package Installation via embedded Web Server.
STR_ENABLE_RPI_WEBDAV_MSG==This option enables Remote Package Installation via embedded Web Server.
STR_FILES=Files
STR_EDITOR=Editor
STR_SAVE=Save
@@ -150,3 +150,11 @@ STR_WEB_SERVER=Web Server
STR_ENABLE=Enable
STR_COMPRESSED_FILE_PATH=Compressed Files Location
STR_COMPRESSED_FILE_PATH_MSG=Location of where compressed files are stored on the web server
STR_ALLDEBRID=AllDebrid
STR_API_KEY=API Key
STR_CANT_EXTRACT_URL_MSG=Couldn't extract download url
STR_FAIL_INSTALL_FROM_URL_MSG=Failed to install from URL
STR_INVALID_URL=InValid URL
STR_ALLDEBRID_API_KEY_MISSING_MSG=To use this function, an API Key needs to be configured in the ezRemote Client settings
STR_LANGUAGE=Language
STR_TEMP_DIRECTORY=Temp Directory
+2 -2
View File
@@ -112,8 +112,8 @@ STR_CANNOT_CONNECT_REMOTE_MSG=Servidor HTTP remoto não esta acessível.
STR_DOWNLOAD_INSTALL_MSG=A instalação remota do pacote não é possível. Você gostaria de baixar o pacote e instalar?
STR_CHECKING_REMOTE_SERVER_MSG=Verificando servidor remoto para instalação de pacote remoto.
STR_ENABLE_RPI=RPI
STR_ENABLE_RPI_FTP_SMB_MSG=Esta opção permite a instalação remota de pacotes. Isso requer uma configuração de servidor HTTP no mesmo Host compartilhando a mesma pasta com acesso anônimo.
STR_ENABLE_RPI_WEBDAV_MSG=Esta opção permite a instalação remota de pacotes. Isso requer o servidor com acesso anônimo que não precisa de nome de usuário/senha.
STR_ENABLE_RPI_FTP_SMB_MSG=Esta opção permite a instalação remota de pacotes.
STR_ENABLE_RPI_WEBDAV_MSG=Esta opção permite a instalação remota de pacotes.
STR_FILES=Arquivos
STR_EDITOR=Editar
STR_SAVE=Salvar
+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
+166 -86
View File
@@ -4,6 +4,7 @@
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <minizip/unzip.h>
#include <orbis/SystemService.h>
#include "clients/gdrive.h"
#include "clients/ftpclient.h"
#include "clients/smbclient.h"
@@ -13,7 +14,9 @@
#include "clients/npxserve.h"
#include "clients/nfsclient.h"
#include "clients/iis.h"
#include "clients/rclone.h"
#include "clients/sftpclient.h"
#include "filehost/filehost.h"
#include "common.h"
#include "fs.h"
#include "config.h"
@@ -25,6 +28,7 @@
#include "web/request.hpp"
#include "web/urn.hpp"
#include "system.h"
#include "sfo.h"
#include "zip_util.h"
namespace Actions
@@ -365,6 +369,7 @@ namespace Actions
return remoteclient->Put(src, dest);
}
sceSystemServicePowerTick();
return 1;
}
@@ -460,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;
@@ -516,6 +522,7 @@ namespace Actions
return remoteclient->Get(dest, src);
}
sceSystemServicePowerTick();
return 1;
}
@@ -672,6 +679,7 @@ namespace Actions
{
download_and_install = true;
}
for (std::vector<DirEntry>::iterator it = files.begin(); it != files.end(); ++it)
{
if (stop_activity)
@@ -702,7 +710,10 @@ namespace Actions
}
else
{
if (INSTALLER::InstallRemotePkg(it->path, &header) == 0)
std::string url = INSTALLER::getRemoteUrl(it->path, true);
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
failed++;
else
success++;
@@ -712,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++;
}
@@ -741,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;
@@ -764,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));
@@ -795,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++;
}
@@ -866,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);
@@ -914,87 +1065,6 @@ namespace Actions
}
}
std::string GetGoogleDownloadUrl(std::string &url)
{
size_t scheme_pos = url.find_first_of("://");
size_t path_pos = url.find_first_of("/", scheme_pos + 3);
std::string host = url.substr(0, path_pos);
std::string path = url.substr(path_pos);
std::string first_download_path;
size_t file_id_start_pos = path.find("/file/d/");
if (file_id_start_pos != std::string::npos)
{
file_id_start_pos = file_id_start_pos + 8;
std::string file_id = path.substr(file_id_start_pos);
size_t file_id_end_pos = file_id.find_first_of("/");
file_id = file_id.substr(0, file_id_end_pos);
first_download_path = "/uc?export=download&id=" + file_id;
}
else if (path.find("/uc?export=download") != std::string::npos)
{
first_download_path = path;
}
else
{
return "";
}
WebDAV::WebDavClient tmp_client;
tmp_client.Connect(host.c_str(), "", "", false);
WebDAV::dict_t headers;
tmp_client.GetHeaders(first_download_path.c_str(), &headers);
std::string content_type = WebDAV::get(headers, "content-type");
if (content_type.find("application/octet-stream") != std::string::npos)
{
return first_download_path;
}
else if (content_type.find("text/html") == std::string::npos)
{
return "";
}
char *buffer_ptr = nullptr;
unsigned long long buffer_size = 0;
tmp_client.GetClient()->download_to(first_download_path, buffer_ptr, buffer_size);
lxb_status_t status;
lxb_dom_element_t *element;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)buffer_ptr, buffer_size);
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"form", 4);
if (status != LXB_STATUS_OK)
return "";
std::string download_url;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
std::string form_id((char *)element->attr_id->value->data, element->attr_id->value->length);
if (form_id == "download-form")
{
size_t value_len;
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"action", 6, &value_len);
download_url = std::string((char *)value, value_len);
break;
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return download_url;
}
void *InstallUrlPkgThread(void *argp)
{
bytes_transfered = 0;
@@ -1008,8 +1078,16 @@ namespace Actions
sprintf(filename, "%s/%lu.pkg", DATA_PATH, tick.mytick);
std::string full_url = std::string(install_pkg_url.url);
if (full_url.find("https://drive.google.com") != std::string::npos)
full_url = GetGoogleDownloadUrl(full_url);
FileHost *filehost = FileHost::getFileHost(full_url);
if (!filehost->IsValidUrl())
{
sprintf(status_message, "%s", lang_strings[STR_FAIL_TO_OBTAIN_GG_DL_MSG]);
activity_inprogess = false;
Windows::SetModalMode(false);
return NULL;
}
full_url = filehost->GetDownloadUrl();
delete(filehost);
if (full_url.empty())
{
@@ -1129,6 +1207,8 @@ namespace Actions
remoteclient = new NginxClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
remoteclient = new NpxServeClient();
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
remoteclient = new RCloneClient();
}
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
{
@@ -1647,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
+6 -2
View File
@@ -6,7 +6,7 @@
class Base64
{
public:
static int Encode(const std::string &input, std::string &out)
static int Encode(unsigned char *input, size_t in_len, std::string &out)
{
static constexpr char sEncodingTable[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
@@ -18,7 +18,6 @@ public:
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
size_t in_len = input.size();
size_t out_len = 4 * ((in_len + 2) / 3);
out.resize(out_len);
size_t i;
@@ -50,6 +49,11 @@ public:
return 1;
}
static int Encode(const std::string &input, std::string &out)
{
return Encode((unsigned char*)input.data(), input.size(), out);
}
static int Decode(const std::string &input, std::string &out)
{
static constexpr unsigned char kDecodingTable[] = {
+5 -25
View File
@@ -12,26 +12,6 @@ using httplib::Client;
using httplib::Headers;
using httplib::Result;
lxb_dom_node_t *nextChildElement(lxb_dom_element_t *element)
{
lxb_dom_node_t *node = element->node.first_child;
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
node = node->next;
}
return node;
}
lxb_dom_node_t *nextElement(lxb_dom_node_t *node)
{
lxb_dom_node_t *next = node->next;
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
next = next->next;
}
return next;
}
std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
@@ -101,7 +81,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
memset(&entry, 0, sizeof(DirEntry));
element = lxb_dom_collection_element(collection, i);
node = nextChildElement(element);
node = NextChildElement(element);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
@@ -114,7 +94,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
if (tmp_string.compare("td") == 0)
{
// get the child img element
lxb_dom_node_t *img = nextChildElement(lxb_dom_interface_element(node));
lxb_dom_node_t *img = NextChildElement(lxb_dom_interface_element(node));
if (img == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(img), &value_len);
@@ -142,7 +122,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
else continue; // invalid record
// file/folder name
node = nextElement(node);
node = NextElement(node);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
tmp_string = std::string((const char *)value, value_len);
@@ -165,7 +145,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
else continue; // not valid record
// datetime
node = nextElement(node);
node = NextElement(node);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
tmp_string = std::string((const char *)value, value_len);
@@ -195,7 +175,7 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
else continue; // invalid record
// filesize
node = nextElement(node);
node = NextElement(node);
if (node == nullptr) continue;
value = lxb_dom_element_local_name(lxb_dom_interface_element(node), &value_len);
tmp_string = std::string((const char *)value, value_len);
+24 -3
View File
@@ -1,5 +1,3 @@
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <fstream>
#include <curl/curl.h>
#include "common.h"
@@ -94,6 +92,29 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
return 0;
}
int BaseClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
char range_header[64];
sprintf(range_header, "bytes=%lu-%lu", offset, offset+size-1);
Headers headers = {{"Range", range_header}};
size_t bytes_read = 0;
if (auto res = client->Get(GetFullPath(path), headers,
[&](const char *data, size_t data_length)
{
bytes_read += data_length;
bool ok = sink.write(data, data_length);
return ok;
}))
{
return bytes_read == size;
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
}
return 0;
}
int BaseClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
char range_header[64];
@@ -259,7 +280,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)
+4
View File
@@ -3,8 +3,11 @@
#include <string>
#include <vector>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include "http/httplib.h"
#include "clients/remote_client.h"
#include "http/httplib.h"
#include "common.h"
class BaseClient : public RemoteClient
@@ -18,6 +21,7 @@ public:
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
+59 -4
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;
@@ -1266,6 +1283,45 @@ int FtpClient::Get(const std::string &outputfile, const std::string &path, uint6
return FtpXfer(outputfile, path, mp_ftphandle, FtpClient::filereadappend, FtpClient::transfermode::image);
}
int FtpClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
ftphandle *nData;
mp_ftphandle->offset = offset;
if (!FtpAccess(path, FtpClient::fileread, FtpClient::transfermode::image, mp_ftphandle, &nData))
{
return 0;
}
char buf[FTP_CLIENT_BUFSIZ];
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);
if (!ok)
{
FtpClose(nData);
mp_ftphandle->offset = 0;
return 0;
}
}
else
{
break;
}
} while (1);
FtpClose(nData);
mp_ftphandle->offset = 0;
return 1;
}
int FtpClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
ftphandle *nData;
@@ -1278,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)
@@ -1297,7 +1353,6 @@ int FtpClient::GetRange(const std::string &path, void *buffer, uint64_t size, ui
mp_ftphandle->offset = 0;
return 1;
}
/*
+3 -1
View File
@@ -7,8 +7,9 @@
#include <string>
#include <vector>
#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);
@@ -79,6 +80,7 @@ public:
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset = 0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
+29
View File
@@ -331,6 +331,35 @@ int GDriveClient::Get(const std::string &outputfile, const std::string &path, ui
return 0;
}
int GDriveClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
size_t bytes_read = 0;
std::string id = GetValue(path_id_map, path);
std::string drive_id = GetDriveId(path);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
if (!drive_id.empty())
url += "&supportsAllDrives=true";
Headers headers;
headers.insert(std::make_pair("Range", "bytes=" + std::to_string(offset) + "-" + std::to_string(offset + size - 1)));
if (auto res = client->Get(url, headers,
[&](const char *data, size_t data_length)
{
bytes_read += data_length;
bool ok = sink.write(data, data_length);
return ok;
}))
{
return bytes_read == size;
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
}
return 0;
}
int GDriveClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
size_t bytes_read = 0;
+2
View File
@@ -6,6 +6,7 @@
#include "http/httplib.h"
#include "clients/remote_client.h"
#include "clients/baseclient.h"
#include "http/httplib.h"
#include "common.h"
static pthread_t refresh_token_thid;
@@ -20,6 +21,7 @@ public:
int Rename(const std::string &src, const std::string &dst);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Head(const std::string &path, void *buffer, uint64_t len);
int Update(const std::string &inputfile, const std::string &path);
+46 -1
View File
@@ -17,7 +17,7 @@
#include "util.h"
#include "system.h"
#define BUF_SIZE 64*1024
#define BUF_SIZE 256*1024
NfsClient::NfsClient()
{
@@ -233,6 +233,51 @@ int NfsClient::Get(const std::string &outputfile, const std::string &ppath, uint
return 1;
}
int NfsClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
struct nfsfh *nfsfh = nullptr;
int ret = nfs_open(nfs, path.c_str(), 0400, &nfsfh);
if (ret != 0)
{
return 0;
}
ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
if (ret != 0)
{
return 0;
}
void *buff = malloc(BUF_SIZE);
int count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(BUF_SIZE, bytes_remaining);
count = nfs_read(nfs, nfsfh, bytes_to_read, buff);
if (count > 0)
{
bytes_remaining -= count;
bool ok = sink.write((char*)buff, count);
if (!ok)
{
free((void *)buff);
nfs_close(nfs, nfsfh);
return 0;
}
}
else
{
break;
}
} while (1);
free((void *)buff);
nfs_close(nfs, nfsfh);
return 1;
}
int NfsClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, uint64_t offset)
{
if (!FileExists(ppath))
+2
View File
@@ -10,6 +10,7 @@
#include "nfsc/libnfs-raw.h"
#include "nfsc/libnfs-raw-mount.h"
#include "clients/remote_client.h"
#include "http/httplib.h"
#include "common.h"
class NfsClient : public RemoteClient
@@ -23,6 +24,7 @@ public:
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
+224
View File
@@ -0,0 +1,224 @@
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <fstream>
#include "common.h"
#include "clients/remote_client.h"
#include "clients/rclone.h"
#include "lang.h"
#include "util.h"
#include "system.h"
#include "windows.h"
using httplib::Client;
using httplib::Headers;
using httplib::Result;
std::vector<DirEntry> RCloneClient::ListDir(const std::string &path)
{
std::vector<DirEntry> out;
DirEntry entry;
Util::SetupPreviousFolder(path, &entry);
out.push_back(entry);
std::string encoded_path = httplib::detail::encode_url(GetFullPath(path)+"/");
if (auto res = client->Get(encoded_path))
{
lxb_status_t status;
lxb_dom_attr_t *attr;
lxb_dom_element_t *tbody_element, *tr_element, *td_element;
lxb_html_document_t *document;
lxb_dom_collection_t *tbody_collection;
lxb_dom_collection_t *tr_collection;
lxb_dom_collection_t *td_collection;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
{
lxb_html_document_destroy(document);
goto finish;
}
tbody_collection = lxb_dom_collection_make(&document->dom_document, 1);
if (tbody_collection == NULL)
{
lxb_html_document_destroy(document);
goto finish;
}
tr_collection = lxb_dom_collection_make(&document->dom_document, 128);
if (tbody_collection == NULL)
{
lxb_html_document_destroy(document);
goto finish;
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
tbody_collection, (const lxb_char_t *)"tbody", 5);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
if (lxb_dom_collection_length(tbody_collection) < 1)
{
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
// Get the first tbody which should only be 1
tbody_element = lxb_dom_collection_element(tbody_collection, 0);
status = lxb_dom_elements_by_tag_name(tbody_element,
tr_collection, (const lxb_char_t *)"tr", 2);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
// skip row 0 , since it has the previous folder header
for (size_t i = 1; i < lxb_dom_collection_length(tr_collection); i++)
{
DirEntry entry;
std::string title, aclass;
memset(&entry.modified, 0, sizeof(DateTime));
const lxb_char_t *value;
size_t value_len;
std::string tmp_string;
tr_element = lxb_dom_collection_element(tr_collection, i);
td_collection = lxb_dom_collection_make(&document->dom_document, 5);
status = lxb_dom_elements_by_tag_name(tr_element,
td_collection, (const lxb_char_t *)"td", 2);
if (status != LXB_STATUS_OK || lxb_dom_collection_length(td_collection) < 0)
{
lxb_dom_collection_destroy(td_collection, true);
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
// td 0 is empty, td 1 is file or folder
td_element = lxb_dom_collection_element(td_collection, 1);
lxb_dom_node_t *use_node = NextChildElement(lxb_dom_interface_element(NextChildElement(td_element)));
value = lxb_dom_element_local_name(lxb_dom_interface_element(use_node), &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string.compare("use") != 0)
{
lxb_dom_collection_destroy(td_collection, true);
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
goto finish;
}
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(use_node), (const lxb_char_t *)"xlink:href", 10, &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string.compare("#folder") == 0)
{
entry.isDir = true;
entry.selectable = true;
entry.file_size = 0;
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
}
else
{
entry.isDir = false;
entry.selectable = true;
}
// <a> element contains the file/folder name
lxb_dom_node_t *a_node = NextChildElement(lxb_dom_interface_element(NextElement(NextChildElement(td_element))));
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(a_node), (const lxb_char_t *)"href", 4, &value_len);
tmp_string = std::string((const char *)value, value_len);
if (tmp_string[tmp_string.length()-1] == '/')
tmp_string = tmp_string.substr(0, tmp_string.length()-1);
tmp_string = BaseClient::DecodeUrl(tmp_string);
sprintf(entry.name, "%s", tmp_string.c_str());
sprintf(entry.directory, "%s", path.c_str());
if (path.length() > 0 && path[path.length() - 1] == '/')
{
sprintf(entry.path, "%s%s", path.c_str(), entry.name);
}
else
{
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
}
// td 3 - filesize
if (!entry.isDir)
{
td_element = lxb_dom_collection_element(td_collection, 2);
lxb_dom_node_t *size_node = NextChildElement(td_element);
value = lxb_dom_node_text_content(size_node->first_child, &value_len);
tmp_string = std::string((const char *)value, value_len);
entry.file_size = atol(tmp_string.c_str());
DirEntry::SetDisplaySize(&entry);
}
// td 4 - datetime
td_element = lxb_dom_collection_element(td_collection, 3);
lxb_dom_node_t *date_node = NextChildElement(td_element);
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(date_node), (const lxb_char_t *)"datetime", 8, &value_len);
tmp_string = std::string((const char *)value, value_len);
std::vector<std::string> date_time = Util::Split(tmp_string, " ");
OrbisDateTime gmt;
OrbisDateTime lt;
if (date_time.size() > 1)
{
std::vector<std::string> adate = Util::Split(date_time[0], "-");
if (adate.size() == 3)
{
gmt.year = atoi(adate[0].c_str());
gmt.month = atoi(adate[1].c_str());
gmt.day = atoi(adate[2].c_str());
}
std::vector<std::string> atime = Util::Split(date_time[1], ":");
if (atime.size() == 3)
{
gmt.hour = atoi(atime[0].c_str());
gmt.minute = atoi(atime[1].c_str());
std::vector<std::string> sec_msec = Util::Split(atime[2], ".");
if (sec_msec.size() > 0)
{
gmt.second = atoi(sec_msec[0].c_str());
}
}
}
convertUtcToLocalTime(&gmt, &lt);
entry.modified.day = lt.day;
entry.modified.month = lt.month;
entry.modified.year = lt.year;
entry.modified.hours = lt.hour;
entry.modified.minutes = lt.minute;
entry.modified.seconds = lt.second;
lxb_dom_collection_destroy(td_collection, true);
out.push_back(entry);
}
lxb_dom_collection_destroy(tr_collection, true);
lxb_dom_collection_destroy(tbody_collection, true);
lxb_html_document_destroy(document);
}
else
{
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
return out;
}
finish:
return out;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef RCLONE_H
#define RCLONE_H
#include <string>
#include <vector>
#include "http/httplib.h"
#include "clients/baseclient.h"
#include "clients/remote_client.h"
#include "common.h"
class RCloneClient : public BaseClient
{
public:
std::vector<DirEntry> ListDir(const std::string &path);
};
#endif
+7 -1
View File
@@ -4,6 +4,7 @@
#include <string>
#include <vector>
#include "common.h"
#include "http/httplib.h"
enum RemoteActions
{
@@ -19,12 +20,14 @@ 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
{
CLIENT_TYPE_FTP,
CLIENT_TYPE_SFTP,
CLIENT_TYPE_SMB,
CLIENT_TYPE_WEBDAV,
CLIENT_TYPE_HTTP_SERVER,
@@ -33,6 +36,8 @@ enum ClientType
CLINET_TYPE_UNKNOWN
};
using namespace httplib;
class RemoteClient
{
public:
@@ -50,6 +55,7 @@ public:
virtual int Move(const std::string &from, const std::string &to) = 0;
virtual int Head(const std::string &path, void *buffer, uint64_t len) = 0;
virtual int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset) = 0;
virtual int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset) = 0;
virtual bool FileExists(const std::string &path) = 0;
virtual std::vector<DirEntry> ListDir(const std::string &path) = 0;
virtual std::string GetPath(std::string path1, std::string path2) = 0;
+44 -1
View File
@@ -255,6 +255,7 @@ int SFTPClient::Size(const std::string &path, int64_t *size)
{
return 0;
}
*size = attrs.filesize;
return 1;
}
@@ -296,12 +297,54 @@ int SFTPClient::Get(const std::string &outputfile, const std::string &path, uint
break;
}
} while (1);
free((char *)buff);
FS::Close(out);
libssh2_sftp_close(sftp_handle);
return 1;
}
int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
if (!sftp_handle)
{
sprintf(response, "Unable to open file with SFTP: %ld", libssh2_sftp_last_error(sftp_session));
return 0;
}
libssh2_sftp_seek64(sftp_handle, offset);
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
int rc, count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(FTP_CLIENT_BUFSIZ, bytes_remaining);
rc = libssh2_sftp_read(sftp_handle, buff, bytes_to_read);
if (rc > 0)
{
bytes_remaining -= rc;
bool ok = sink.write(buff, rc);
if (!ok)
{
free((char *)buff);
libssh2_sftp_close(sftp_handle);
return 0;
}
}
else
{
break;
}
} while (1);
free((char *)buff);
libssh2_sftp_close(sftp_handle);
return 1;
}
int SFTPClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
{
int64_t filesize;
@@ -601,7 +644,7 @@ int SFTPClient::Quit()
ClientType SFTPClient::clientType()
{
return CLIENT_TYPE_FTP;
return CLIENT_TYPE_SFTP;
}
uint32_t SFTPClient::SupportedActions()
+2
View File
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
#include "clients/remote_client.h"
#include "http/httplib.h"
#include "common.h"
class SFTPClient : public RemoteClient
@@ -20,6 +21,7 @@ public:
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
+49
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);
@@ -226,6 +233,48 @@ int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint
return 1;
}
int SmbClient::GetRange(const std::string &ppath, DataSink &sink, uint64_t size, uint64_t offset)
{
std::string path = std::string(ppath);
path = Util::Trim(path, "/");
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
if (in == NULL)
{
return 0;
}
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
uint8_t *buff = (uint8_t*)malloc(max_read_size);
int count = 0;
size_t bytes_remaining = size;
do
{
size_t bytes_to_read = std::min<size_t>(max_read_size, bytes_remaining);
count = smb2_read(smb2, in, buff, bytes_to_read);
if (count > 0)
{
bytes_remaining -= count;
bool ok = sink.write((char*)buff, count);
if (!ok)
{
free((uint8_t *)buff);
smb2_close(smb2, in);
return 0;
}
}
else
{
break;
}
} while (1);
free((char *)buff);
smb2_close(smb2, in);
return 1;
}
int SmbClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, uint64_t offset)
{
std::string path = std::string(ppath);
+2
View File
@@ -8,6 +8,7 @@
#include <vector>
#include <smb2/smb2.h>
#include <smb2/libsmb2.h>
#include "http/httplib.h"
#include "clients/remote_client.h"
#include "common.h"
@@ -24,6 +25,7 @@ public:
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
+5
View File
@@ -215,6 +215,11 @@ namespace WebDAV
return 1;
}
int WebDavClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
{
return client->download_range_to(path, sink, offset, offset+size-1);
}
/*
* Put - issue a PUT command and send data from input
*
+4
View File
@@ -5,10 +5,13 @@
#include <string>
#include <vector>
#include <regex>
#include "http/httplib.h"
#include "webdav/client.hpp"
#include "clients/remote_client.h"
#include "common.h"
using namespace httplib;
namespace WebDAV
{
inline std::string GetHttpUrl(std::string url)
@@ -29,6 +32,7 @@ namespace WebDAV
int Size(const std::string &path, int64_t *size);
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
int Rename(const std::string &src, const std::string &dst);
int Delete(const std::string &path);
+42
View File
@@ -4,6 +4,8 @@
#include <string>
#include <vector>
#include <string.h>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#define HTTP_SUCCESS(x) (x >= 200 && x < 300)
#define MIN(a,b) (((a)<(b))?(a):(b))
@@ -86,4 +88,44 @@ struct DirEntry
}
};
static lxb_dom_node_t *NextChildElement(lxb_dom_element_t *element)
{
lxb_dom_node_t *node = element->node.first_child;
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
node = node->next;
}
return node;
}
static lxb_dom_node_t *NextElement(lxb_dom_node_t *node)
{
lxb_dom_node_t *next = node->next;
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_ELEMENT)
{
next = next->next;
}
return next;
}
static lxb_dom_node_t *NextChildTextNode(lxb_dom_element_t *element)
{
lxb_dom_node_t *node = element->node.first_child;
while (node != nullptr && node->type != LXB_DOM_NODE_TYPE_TEXT)
{
node = node->next;
}
return node;
}
static lxb_dom_node_t *NextTextNode(lxb_dom_node_t *node)
{
lxb_dom_node_t *next = node->next;
while (next != nullptr && next->type != LXB_DOM_NODE_TYPE_TEXT)
{
next = next->next;
}
return next;
}
#endif
+59 -8
View File
@@ -25,6 +25,7 @@ char remote_directory[255];
char app_ver[6];
char last_site[32];
char display_site[32];
std::vector<std::string> langs;
char language[128];
std::vector<std::string> sites;
std::vector<std::string> http_servers;
@@ -37,6 +38,8 @@ bool auto_delete_tmp_pkg;
int max_edit_file_size;
GoogleAppInfo gg_app;
bool show_hidden_files;
char alldebrid_api_key[32];
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'};
@@ -82,10 +85,14 @@ namespace CONFIG
{
setting->type = CLIENT_TYPE_SMB;
}
else if (strncmp(setting->server, "ftp://", 6) == 0 || strncmp(setting->server, "sftp://", 7) == 0)
else if (strncmp(setting->server, "ftp://", 6) == 0)
{
setting->type = CLIENT_TYPE_FTP;
}
else if (strncmp(setting->server, "sftp://", 7) == 0)
{
setting->type = CLIENT_TYPE_SFTP;
}
else if (strncmp(setting->server, "webdav://", 9) == 0 || strncmp(setting->server, "webdavs://", 10) == 0)
{
setting->type = CLIENT_TYPE_WEBDAV;
@@ -147,7 +154,11 @@ namespace CONFIG
sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10",
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE};
langs = { "Default", "Arabic", "Catalan", "Croatian", "Dutch", "English", "Euskera", "French", "Galego", "German", "Greek",
"Hungarian", "Indonesian", "Italiano", "Japanese", "Korean", "Polish", "Portuguese_BR", "Russian", "Romanian", "Ryukyuan", "Spanish", "Turkish",
"Simplified Chinese", "Traditional Chinese", "Thai", "Ukrainian"};
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE};
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
@@ -162,7 +173,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, "/"));
@@ -177,6 +188,30 @@ namespace CONFIG
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
if (!FS::FolderExists(temp_folder))
{
FS::MkDirs(temp_folder);
}
// alldebrid api key
char tmp_api_key[512];
sprintf(tmp_api_key, "%s", ReadString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, ""));
std::string encrypted_api_key;
if (strlen(tmp_api_key) > 0)
{
std::string decrypted__api_key;
int ret = Decrypt(tmp_api_key, decrypted__api_key);
if (ret == 0)
sprintf(alldebrid_api_key, "%s", tmp_api_key);
else
sprintf(alldebrid_api_key, "%s", decrypted__api_key.c_str());
Encrypt(alldebrid_api_key, encrypted_api_key);
}
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
// 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);
@@ -244,10 +279,7 @@ namespace CONFIG
}
WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, encrypted_password.c_str());
setting.http_port = ReadInt(sites[i].c_str(), CONFIG_REMOTE_SERVER_HTTP_PORT, 80);
WriteInt(sites[i].c_str(), CONFIG_REMOTE_SERVER_HTTP_PORT, setting.http_port);
setting.enable_rpi = ReadBool(sites[i].c_str(), CONFIG_ENABLE_RPI, false);
setting.enable_rpi = ReadBool(sites[i].c_str(), CONFIG_ENABLE_RPI, true);
WriteBool(sites[i].c_str(), CONFIG_ENABLE_RPI, setting.enable_rpi);
sprintf(setting.http_server_type, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_HTTP_SERVER_TYPE, HTTP_SERVER_APACHE));
@@ -322,7 +354,6 @@ namespace CONFIG
WriteString(last_site, CONFIG_REMOTE_SERVER_URL, remote_settings->server);
WriteString(last_site, CONFIG_REMOTE_SERVER_USER, remote_settings->username);
WriteString(last_site, CONFIG_REMOTE_SERVER_PASSWORD, encrypted_text.c_str());
WriteInt(last_site, CONFIG_REMOTE_SERVER_HTTP_PORT, remote_settings->http_port);
WriteBool(last_site, CONFIG_ENABLE_RPI, remote_settings->enable_rpi);
WriteString(last_site, CONFIG_REMOTE_HTTP_SERVER_TYPE, remote_settings->http_server_type);
WriteString(last_site, CONFIG_REMOTE_DEFAULT_DIRECTORY, remote_settings->default_directory);
@@ -355,17 +386,37 @@ namespace CONFIG
Encrypt(gg_app.client_secret, encrypted_secret);
else
encrypted_secret = std::string(gg_app.client_secret);
std::string encrypted_api_key;
if (strlen(alldebrid_api_key) > 0)
Encrypt(alldebrid_api_key, encrypted_api_key);
else
encrypted_api_key = std::string(alldebrid_api_key);
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str());
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions);
WriteString(CONFIG_GLOBAL, CONFIG_ALLDEBRID_API_KEY, encrypted_api_key.c_str());
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)
+8 -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"
@@ -57,6 +58,8 @@
#define CONFIG_REMOTE_HTTP_SERVER_TYPE "remote_server_http_server_type"
#define CONFIG_REMOTE_DEFAULT_DIRECTORY "remote_server_default_directory"
#define CONFIG_ALLDEBRID_API_KEY "alldebrid_api_key"
#define CONFIG_VERSION "config_version"
#define CONFIG_VERSION_NUM 1
@@ -68,6 +71,7 @@
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
#define CONFIG_LOCAL_DIRECTORY "local_directory"
#define CONFIG_TMP_FOLDER_PATH "temp_folder"
#define CONFIG_LANGUAGE "language"
@@ -75,6 +79,7 @@
#define HTTP_SERVER_MS_IIS "Microsoft IIS"
#define HTTP_SERVER_NGINX "Nginx"
#define HTTP_SERVER_NPX_SERVE "Serve"
#define HTTP_SERVER_RCLONE "RClone"
#define MAX_EDIT_FILE_SIZE 32768
@@ -98,7 +103,6 @@ struct RemoteSettings
char server[256];
char username[33];
char password[128];
int http_port;
ClientType type;
bool enable_rpi;
uint32_t supported_actions;
@@ -124,6 +128,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;
@@ -135,6 +140,8 @@ extern unsigned char cipher_key[32];
extern unsigned char cipher_iv[16];
extern GoogleAppInfo gg_app;
extern bool show_hidden_files;
extern char alldebrid_api_key[32];
extern char temp_folder[256];
namespace CONFIG
{
+142
View File
@@ -0,0 +1,142 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "1fichier.h"
#define VALIDATION_REGEX "https:\\/\\/1fichier\\.com\\/(.*)"
FichierHost::FichierHost(const std::string &url) : FileHost(url)
{
}
bool FichierHost::IsValidUrl()
{
std::regex regex(VALIDATION_REGEX);
if (std::regex_match(url, regex))
return true;
return false;
}
std::string FichierHost::GetDownloadUrl()
{
std::regex re("https:\\/\\/1fichier\\.com");
std::string path = std::regex_replace(url, re, "");
httplib::Client tmp_client("https://1fichier.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
lxb_status_t status;
lxb_dom_element_t *element;
lxb_dom_node_t *node;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
const lxb_char_t *value;
size_t value_len;
std::string download_url = "";
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"input", 5);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
std::string post_data;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"name", 4, &value_len);
if (value != nullptr)
{
std::string name_attr((char *)value, value_len);
if (name_attr == "adz")
{
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"value", 5, &value_len);
std::string adz_value((char *)value, value_len);
post_data = std::string("adz=") + adz_value + "&did=0&dl_no_ssl=off&dlinline=on";
break;
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
if (auto res = tmp_client.Post(path, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded"))
{
if (HTTP_SUCCESS(res->status))
{
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"a", 1);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"class", 5, &value_len);
if (value != nullptr)
{
std::string class_value((char*) value, value_len);
if (class_value == "ok btn-general btn-orange")
{
value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"href", 4, &value_len);
if (value != nullptr)
{
download_url = std::string((char*) value, value_len);
break;
}
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
}
}
return download_url;
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef FICHIER_HOST_H
#define FICHIER_HOST_H
#include "filehost.h"
class FichierHost : public FileHost
{
public:
FichierHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+64
View File
@@ -0,0 +1,64 @@
#include <http/httplib.h>
#include <json-c/json.h>
#include "config.h"
#include "common.h"
#include "alldebrid.h"
AllDebridHost::AllDebridHost(const std::string &url) : FileHost(url)
{
}
bool AllDebridHost::IsValidUrl()
{
httplib::Client tmp_client("https://api.alldebrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
std::string path = std::string("/v4/link/unlock?agent=ezRemoteClient&apikey=") + alldebrid_api_key + "&link=" + httplib::detail::encode_url(url);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *status = json_object_get_string(json_object_object_get(jobj, "status"));
if (strcmp(status, "success") == 0)
return true;
}
return false;
}
std::string AllDebridHost::GetDownloadUrl()
{
httplib::Client tmp_client("https://api.alldebrid.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
std::string path = std::string("/v4/link/unlock?agent=ezRemoteClient&apikey=") + alldebrid_api_key + "&link=" + httplib::detail::encode_url(url);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
json_object *jobj = json_tokener_parse(res->body.c_str());
const char *status = json_object_get_string(json_object_object_get(jobj, "status"));
if (status != nullptr && strcmp(status, "success") == 0)
{
json_object *data = json_object_object_get(jobj, "data");
const char *link = json_object_get_string(json_object_object_get(data, "link"));
return std::string(link);
}
else
{
return "";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef ALLDEBRID_HOST_H
#define ALLDEBRID_HOST_H
#include "filehost.h"
class AllDebridHost : public FileHost
{
public:
AllDebridHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+28
View File
@@ -0,0 +1,28 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "directhost.h"
#define VALIDATION_REGEX "(.*)"
DirectHost::DirectHost(const std::string &url) : FileHost(url)
{
}
bool DirectHost::IsValidUrl()
{
std::regex regex_1(VALIDATION_REGEX);
if (std::regex_match(url, regex_1))
return true;
return false;
}
std::string DirectHost::GetDownloadUrl()
{
return url;
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef DIRECT_HOST_H
#define DIRECT_HOST_H
#include "filehost.h"
class DirectHost : public FileHost
{
public:
DirectHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+57
View File
@@ -0,0 +1,57 @@
#include <regex>
#include <string>
#include <vector>
#include <map>
#include "filehost.h"
#include "1fichier.h"
#include "filehost/alldebrid.h"
#include "filehost/directhost.h"
#include "filehost/gdrive.h"
#include "filehost/mediafire.h"
#include "filehost/pixeldrain.h"
#include "config.h"
#include "util.h"
#define GDRIVE_REGEX "https:\\/\\/drive\\.google\\.com\\/(.*)"
#define MEDIAFIRE_REGEX "https:\\/\\/www\\.mediafire\\.com\\/(.*)"
#define PIXELDRAIN_REGEX "https:\\/\\/pixeldrain\\.com\\/(.*)"
#define FICHIER_REGEX "https:\\/\\/1fichier\\.com\\/(.*)"
static std::map<std::string, std::string> cache_downloal_urls;
std::string FileHost::GetUrl()
{
return url;
}
FileHost *FileHost::getFileHost(const std::string &url, bool use_alldebrid)
{
std::regex google_re(GDRIVE_REGEX);
std::regex mediafire_re(MEDIAFIRE_REGEX);
std::regex pixeldrain_re(PIXELDRAIN_REGEX);
std::regex fichier_re(FICHIER_REGEX);
if (use_alldebrid)
return new AllDebridHost(url);
else if (std::regex_match(url, google_re))
return new GDriveHost(url);
else if (std::regex_match(url, mediafire_re))
return new MediaFireHost(url);
else if (std::regex_match(url, pixeldrain_re))
return new PixelDrainHost(url);
else
return new DirectHost(url);
}
std::string FileHost::GetCachedDownloadUrl(std::string &hash)
{
return cache_downloal_urls[hash];
}
void FileHost::AddCacheDownloadUrl(std::string &hash, std::string &url)
{
std::pair<std::string, std::string> pair = std::make_pair(hash, url);
cache_downloal_urls.erase(hash);
cache_downloal_urls.insert(pair);
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef FILEHOST_H
#define FILEHOST_H
#include <string>
#include <vector>
class FileHost
{
public:
FileHost(const std::string &url) { this->url = url; };
virtual ~FileHost(){};
virtual bool IsValidUrl() = 0;
virtual std::string GetDownloadUrl() = 0;
std::string GetUrl();
static FileHost *getFileHost(const std::string &url, bool use_alldebrid = false);
static std::string GetCachedDownloadUrl(std::string &hash);
static void AddCacheDownloadUrl(std::string &hash, std::string &url);
protected:
std::string url;
};
#endif
+118
View File
@@ -0,0 +1,118 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "gdrive.h"
#define VALIDATION_REGEX_1 "https:\\/\\/drive\\.google\\.com\\/file\\/d\\/(.*)\\/(edit|view)\\?usp=(.*)"
#define VALIDATION_REGEX_2 "https:\\/\\/drive\\.google\\.com\\/(.*)uc\\?(id=|export=)(.*)&(id=|export=)(.*)"
GDriveHost::GDriveHost(const std::string &url) : FileHost(url)
{
}
bool GDriveHost::IsValidUrl()
{
std::regex regex_1(VALIDATION_REGEX_1);
std::regex regex_2(VALIDATION_REGEX_2);
if (std::regex_match(url, regex_1) || std::regex_match(url, regex_2))
return true;
return false;
}
std::string GDriveHost::GetDownloadUrl()
{
std::regex regex_1(VALIDATION_REGEX_1);
std::smatch matches;
std::string path;
if(std::regex_search(url, matches, regex_1))
{
path = std::string("/uc?export=download&id=") + matches[1].str();
}
else
{
std::regex re("https:\\/\\/drive\\.google\\.com");
path = std::regex_replace(url, re, "");
}
httplib::Client tmp_client("https://drive.google.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
auto res = tmp_client.Head(path);
if (HTTP_SUCCESS(res->status))
{
std::string content_type = res->get_header_value("Content-Type");
if (content_type == "application/octet-stream")
return url;
else if (content_type.find("text/html") == std::string::npos)
return "";
}
else
return "";
res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
lxb_status_t status;
lxb_dom_element_t *element;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
{
lxb_html_document_destroy(document);
return "";
}
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"form", 4);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
std::string download_url;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
if (element->attr_id != nullptr)
{
std::string form_id((char *)element->attr_id->value->data, element->attr_id->value->length);
if (form_id == "download-form")
{
size_t value_len;
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"action", 6, &value_len);
download_url = std::string((char *)value, value_len);
break;
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return download_url;
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef GDRIVE_HOST_H
#define GDRIVE_HOST_H
#include "filehost.h"
class GDriveHost : public FileHost
{
public:
GDriveHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+89
View File
@@ -0,0 +1,89 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "mediafire.h"
#define VALIDATION_REGEX "https:\\/\\/www\\.mediafire\\.com\\/file\\/(.*)\\/(.*)\\/file"
MediaFireHost::MediaFireHost(const std::string &url) : FileHost(url)
{
}
bool MediaFireHost::IsValidUrl()
{
std::regex regex(VALIDATION_REGEX);
if (std::regex_match(url, regex))
return true;
return false;
}
std::string MediaFireHost::GetDownloadUrl()
{
std::regex re("https:\\/\\/www\\.mediafire\\.com");
std::string path = std::regex_replace(url, re, "");
httplib::Client tmp_client("https://www.mediafire.com");
tmp_client.set_keep_alive(true);
tmp_client.set_follow_location(true);
tmp_client.set_connection_timeout(30);
tmp_client.set_read_timeout(30);
tmp_client.enable_server_certificate_verification(false);
auto res = tmp_client.Get(path);
if (HTTP_SUCCESS(res->status))
{
lxb_status_t status;
lxb_dom_element_t *element;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
lxb_dom_attr_t *attr;
document = lxb_html_document_create();
status = lxb_html_document_parse(document, (lxb_char_t *)res->body.c_str(), res->body.length());
if (status != LXB_STATUS_OK)
return "";
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL)
{
lxb_html_document_destroy(document);
return "";
}
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
collection, (const lxb_char_t *)"a", 1);
if (status != LXB_STATUS_OK)
{
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return "";
}
std::string download_url;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++)
{
element = lxb_dom_collection_element(collection, i);
if (element->attr_id != nullptr)
{
std::string a_id((char *)element->attr_id->value->data, element->attr_id->value->length);
if (a_id == "downloadButton")
{
size_t value_len;
const lxb_char_t *value = lxb_dom_element_get_attribute(element, (const lxb_char_t *)"href", 4, &value_len);
download_url = std::string((char *)value, value_len);
break;
}
}
}
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return download_url;
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef MEDIAFIRE_HOST_H
#define MEDIAFIRE_HOST_H
#include "filehost.h"
class MediaFireHost : public FileHost
{
public:
MediaFireHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+38
View File
@@ -0,0 +1,38 @@
#include <regex>
#include <lexbor/html/parser.h>
#include <lexbor/dom/interfaces/element.h>
#include <http/httplib.h>
#include "common.h"
#include "pixeldrain.h"
#define VALIDATION_REGEX "https:\\/\\/pixeldrain\\.com\\/u\\/(.*)"
PixelDrainHost::PixelDrainHost(const std::string &url) : FileHost(url)
{
}
bool PixelDrainHost::IsValidUrl()
{
std::regex re(VALIDATION_REGEX);
if (std::regex_match(url, re))
return true;
return false;
}
std::string PixelDrainHost::GetDownloadUrl()
{
std::regex re(VALIDATION_REGEX);
std::smatch matches;
if(std::regex_search(url, matches, re))
{
if (matches.size() > 1)
{
return std::string("https://pixeldrain.com/api/file/") + matches[1].str() + "?download=";
}
}
return "";
}
+14
View File
@@ -0,0 +1,14 @@
#ifndef PIXELDRAIN_HOST_H
#define PIXELDRAIN_HOST_H
#include "filehost.h"
class PixelDrainHost : public FileHost
{
public:
PixelDrainHost(const std::string &url);
bool IsValidUrl();
std::string GetDownloadUrl();
};
#endif
+2 -1
View File
@@ -353,7 +353,7 @@ private:
} // namespace detail
using Headers = std::multimap<std::string, std::string, detail::ci>;
using Headers = std::map<std::string, std::string, detail::ci>;
using Params = std::multimap<std::string, std::string>;
using Match = std::smatch;
@@ -1900,6 +1900,7 @@ namespace detail {
std::string encode_query_param(const std::string &value);
std::string encode_url(const std::string &s);
std::string decode_url(const std::string &s, bool convert_plus_to_space);
void read_file(const std::string &path, std::string &out);
+2 -2
View File
@@ -10692,7 +10692,7 @@ void ImGui::NavUpdateCreateMoveRequest()
// When using gamepad, we project the reference nav bounding box into window visible area.
// This is to allow resuming navigation inside the visible area after doing a large amount of scrolling, since with gamepad all movements are relative
// (can't focus a visible object like we can with the mouse).
if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
/*if (g.NavMoveSubmitted && g.NavInputSource == ImGuiInputSource_Gamepad && g.NavLayer == ImGuiNavLayer_Main && window != NULL)// && (g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded))
{
bool clamp_x = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopX | ImGuiNavMoveFlags_WrapX)) == 0;
bool clamp_y = (g.NavMoveFlags & (ImGuiNavMoveFlags_LoopY | ImGuiNavMoveFlags_WrapY)) == 0;
@@ -10709,7 +10709,7 @@ void ImGui::NavUpdateCreateMoveRequest()
window->NavRectRel[g.NavLayer].ClipWithFull(inner_rect_rel);
g.NavId = g.NavFocusScopeId = 0;
}
}
}*/
// For scoring we use a single segment on the left side our current item bounding box (not touching the edge to avoid box overlap with zero-spaced items)
ImRect scoring_rect;
+361 -100
View File
@@ -9,9 +9,11 @@
#include <orbis/Bgft.h>
#include <orbis/AppInstUtil.h>
#include <orbis/UserService.h>
#include <orbis/SystemService.h>
#include <curl/curl.h>
#include <web/request.hpp>
#include <web/urn.hpp>
#include "server/http_server.h"
#include "installer.h"
#include "util.h"
#include "config.h"
@@ -19,7 +21,9 @@
#include "lang.h"
#include "system.h"
#include "fs.h"
#include "sfo.h"
#include "clients/webdavclient.h"
#include "clients/remote_client.h"
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
@@ -27,6 +31,8 @@ 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)
@@ -97,11 +103,102 @@ namespace INSTALLER
s_bgft_initialized = false;
}
std::string getRemoteUrl(const std::string filename, bool encodeUrl)
{
if (remoteclient->clientType() == CLIENT_TYPE_WEBDAV || remoteclient->clientType() == CLIENT_TYPE_HTTP_SERVER)
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)
{
std::string full_url = WebDAV::GetHttpUrl(remote_settings->server + filename);
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 &&
(remoteclient->clientType() == CLIENT_TYPE_WEBDAV || remoteclient->clientType() == CLIENT_TYPE_HTTP_SERVER))
{
std::string full_url = WebDAV::GetHttpUrl(remote_settings->server + path);
size_t scheme_pos = full_url.find("://");
if (scheme_pos == std::string::npos)
return "";
@@ -121,24 +218,17 @@ namespace INSTALLER
}
else
{
std::string full_url = std::string(remote_settings->server);
size_t scheme_pos = full_url.find("://");
if (scheme_pos == std::string::npos)
return "";
size_t root_pos = full_url.find("/", scheme_pos + 3);
std::string host = full_url.substr(scheme_pos + 3, (root_pos - (scheme_pos + 3)));
size_t port_pos = host.find(":");
if (port_pos != std::string::npos)
host = host.substr(0, port_pos);
std::string encoded_path = path;
std::string encoded_site_name = remote_settings->site_name;
Web::Urn::Path uri(encoded_path);
Web::Urn::Path site_name(encoded_site_name);
CURL *curl = curl_easy_init();
encoded_path = uri.quote(curl);
encoded_site_name = site_name.quote(curl);
curl_easy_cleanup(curl);
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst" + encoded_site_name + encoded_path;
std::string path = std::string(filename);
if (encodeUrl)
{
Web::Urn::Path uri(path);
CURL *curl = curl_easy_init();
path = uri.quote(curl);
}
return "http://" + host + ":" + std::to_string(remote_settings->http_port) + path;
return full_url;
}
return "";
@@ -146,47 +236,18 @@ namespace INSTALLER
bool canInstallRemotePkg(const std::string &url)
{
if (remoteclient->clientType() == CLIENT_TYPE_WEBDAV)
{
if (strlen(remote_settings->username) > 0)
{
sprintf(confirm_message, "%s %s", lang_strings[STR_REMOTE_NOT_SUPPORT_MSG], lang_strings[STR_DOWNLOAD_INSTALL_MSG]);
return false;
}
else
return true;
}
else
{
size_t scheme_pos = url.find_first_of("://");
size_t path_pos = url.find_first_of("/", scheme_pos + 3);
std::string host = url.substr(0, path_pos);
std::string path = url.substr(path_pos);
WebDAV::WebDavClient tmp_client;
tmp_client.Connect(host.c_str(), "", "", false);
WebDAV::dict_t response_headers{};
int ret = tmp_client.GetHeaders(path.c_str(), &response_headers);
if (!ret)
{
sprintf(confirm_message, "%s %s", lang_strings[STR_CANNOT_CONNECT_REMOTE_MSG], lang_strings[STR_DOWNLOAD_INSTALL_MSG]);
return false;
}
return true;
}
return false;
return true;
}
int InstallRemotePkg(const std::string &filename, pkg_header *header)
int InstallRemotePkg(const std::string &url, pkg_header *header, std::string title, bool prompt)
{
std::string url = getRemoteUrl(filename, true);
if (url.empty())
return 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 = title.length() > 0 ? title : cid;
int user_id;
ret = sceUserServiceGetForegroundUser(&user_id);
const char *package_type;
@@ -222,6 +283,7 @@ namespace INSTALLER
is_patch = true;
}
OrbisBgftTaskProgress progress_info;
OrbisBgftDownloadParam params;
memset(&params, 0, sizeof(params));
{
@@ -229,7 +291,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;
@@ -246,18 +308,30 @@ namespace INSTALLER
ret = sceBgftServiceIntDebugDownloadRegisterPkg(&params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
sprintf(confirm_message, "%s - %s?", filename.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
while (confirm_state == CONFIRM_WAIT)
if (prompt)
{
sceKernelUsleep(100000);
}
activity_inprogess = true;
selected_action = action_to_take;
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
confirm_state = CONFIRM_WAIT;
action_to_take = selected_action;
activity_inprogess = false;
while (confirm_state == CONFIRM_WAIT)
{
sceKernelUsleep(100000);
}
activity_inprogess = true;
selected_action = action_to_take;
if (confirm_state == CONFIRM_YES)
if (confirm_state == CONFIRM_YES)
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
{
goto err;
}
goto retry;
}
}
else
{
ret = sceAppInstUtilAppUnInstall(cid.c_str());
if (ret != 0)
@@ -266,55 +340,74 @@ namespace INSTALLER
}
}
else if (ret > 0)
{
goto err;
}
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
{
goto err;
}
Util::Notify("%s queued", cid.c_str());
return 1;
Util::Notify("%s queued", display_title.c_str());
if (prompt)
{
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (bytes_transfered < 99)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
return 0;
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
sceSystemServicePowerTick();
}
}
return 1;
err:
return 0;
}
int InstallLocalPkg(const std::string &filename)
int InstallLocalPkg(const std::string &path)
{
int ret;
pkg_header header;
memset(&header, 0, sizeof(header));
if (FS::Head(filename.c_str(), (void *)&header, sizeof(header)) == 0)
if (FS::Head(path.c_str(), (void *)&header, sizeof(header)) == 0)
return 0;
if (BE32(header.pkg_magic) != PKG_MAGIC)
return 0;
char filepath[1024];
snprintf(filepath, 1023, "%s", filename.c_str());
if (strncmp(filename.c_str(), "/data/", 6) == 0)
snprintf(filepath, 1023, "/user%s", filename.c_str());
snprintf(filepath, 1023, "%s", path.c_str());
if (strncmp(path.c_str(), "/data/", 6) == 0)
snprintf(filepath, 1023, "/user%s", path.c_str());
char titleId[18];
memset(titleId, 0, sizeof(titleId));
int is_app = -1;
ret = sceAppInstUtilGetTitleIdFromPkg(filename.c_str(), titleId, &is_app);
ret = sceAppInstUtilGetTitleIdFromPkg(path.c_str(), titleId, &is_app);
if (ret)
{
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;
memset(&download_params, 0, sizeof(download_params));
{
download_params.params.entitlementType = 5;
download_params.params.id = (char *)header.pkg_content_id;
download_params.params.contentUrl = filepath;
download_params.params.contentName = (char *)header.pkg_content_id;
download_params.params.contentName = display_title.c_str();
;
download_params.params.iconPath = "";
download_params.params.playgoScenarioId = "0";
@@ -339,15 +432,19 @@ namespace INSTALLER
if (ret)
return 0;
Util::Notify("%s queued", titleId);
Util::Notify("%s queued", display_title.c_str());
while (prog < 99)
file_transfering = true;
bytes_to_download = 100;
bytes_transfered = 0;
while (bytes_transfered < 99)
{
memset(&progress_info, 0, sizeof(progress_info));
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
return 0;
prog = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
bytes_transfered = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
sceSystemServicePowerTick();
}
return 1;
@@ -355,27 +452,31 @@ namespace INSTALLER
return 0;
}
int InstallLocalPkg(const std::string &filename, pkg_header *header, bool remove_after_install)
int InstallLocalPkg(const std::string &path, pkg_header *header, bool remove_after_install)
{
int ret;
if (strncmp(filename.c_str(), "/data/", 6) != 0 &&
strncmp(filename.c_str(), "/user/data/", 11) != 0 &&
strncmp(filename.c_str(), "/mnt/usb", 8) != 0)
if (strncmp(path.c_str(), "/data/", 6) != 0 &&
strncmp(path.c_str(), "/user/data/", 11) != 0 &&
strncmp(path.c_str(), "/mnt/usb", 8) != 0)
return -1;
std::string filename = path.substr(path.find_last_of("/")+1);
char filepath[1024];
snprintf(filepath, 1023, "%s", filename.c_str());
if (strncmp(filename.c_str(), "/data/", 6) == 0)
snprintf(filepath, 1023, "/user%s", filename.c_str());
snprintf(filepath, 1023, "%s", path.c_str());
if (strncmp(path.c_str(), "/data/", 6) == 0)
snprintf(filepath, 1023, "/user%s", path.c_str());
char titleId[18];
memset(titleId, 0, sizeof(titleId));
int is_app = -1;
ret = sceAppInstUtilGetTitleIdFromPkg(filename.c_str(), titleId, &is_app);
ret = sceAppInstUtilGetTitleIdFromPkg(path.c_str(), titleId, &is_app);
if (ret)
{
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;
@@ -384,7 +485,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 = (char *)header->pkg_content_id;
download_params.params.contentName = display_title.c_str();
;
download_params.params.iconPath = "";
download_params.params.playgoScenarioId = "0";
@@ -397,7 +498,7 @@ namespace INSTALLER
ret = sceBgftServiceIntDownloadRegisterTaskByStorageEx(&download_params, &task_id);
if (ret == 0x80990088 || ret == 0x80990015)
{
sprintf(confirm_message, "%s - %s?", filename.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;
@@ -418,7 +519,7 @@ namespace INSTALLER
else
{
if (auto_delete_tmp_pkg)
FS::Rm(filename);
FS::Rm(path);
}
}
else if (ret > 0)
@@ -432,7 +533,7 @@ namespace INSTALLER
if (!remove_after_install)
{
Util::Notify("%s queued", titleId);
Util::Notify("%s queued", display_title.c_str());
return 1;
}
@@ -450,24 +551,24 @@ namespace INSTALLER
bytes_transfered = progress_info.transferred;
}
if (auto_delete_tmp_pkg)
FS::Rm(filename);
FS::Rm(path);
return 1;
err:
return 0;
}
bool ExtractLocalPkg(const std::string &filename, const std::string sfo_path, const std::string icon_path)
bool ExtractLocalPkg(const std::string &path, const std::string sfo_path, const std::string icon_path)
{
pkg_header tmp_hdr;
FS::Head(filename, &tmp_hdr, sizeof(pkg_header));
FS::Head(path, &tmp_hdr, sizeof(pkg_header));
size_t entry_count = BE32(tmp_hdr.pkg_entry_count);
uint32_t entry_table_offset = BE32(tmp_hdr.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(filename);
FILE *fd = FS::OpenRead(path);
FS::Seek(fd, entry_table_offset);
FS::Read(fd, entry_table_data, entry_table_size);
@@ -528,10 +629,10 @@ namespace INSTALLER
return true;
}
bool ExtractRemotePkg(const std::string &filename, 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)
{
pkg_header tmp_hdr;
if (!remoteclient->Head(filename, &tmp_hdr, sizeof(pkg_header)))
if (!remoteclient->Head(path, &tmp_hdr, sizeof(pkg_header)))
return false;
size_t entry_count = BE32(tmp_hdr.pkg_entry_count);
@@ -539,7 +640,7 @@ namespace INSTALLER
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
void *entry_table_data = malloc(entry_table_size);
if (!remoteclient->GetRange(filename, entry_table_data, entry_table_size, entry_table_offset))
if (!remoteclient->GetRange(path, entry_table_data, entry_table_size, entry_table_offset))
return false;
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
@@ -577,7 +678,7 @@ namespace INSTALLER
{
param_sfo_data = malloc(param_sfo_size);
FILE *out = FS::Create(sfo_path);
if (!remoteclient->GetRange(filename, param_sfo_data, param_sfo_size, param_sfo_offset))
if (!remoteclient->GetRange(path, param_sfo_data, param_sfo_size, param_sfo_offset))
{
FS::Close(out);
return false;
@@ -591,7 +692,7 @@ namespace INSTALLER
{
icon0_png_data = malloc(icon0_png_size);
FILE *out = FS::Create(icon_path);
if (!remoteclient->GetRange(filename, icon0_png_data, icon0_png_size, icon0_png_offset))
if (!remoteclient->GetRange(path, icon0_png_data, icon0_png_size, icon0_png_offset))
{
FS::Close(out);
return false;
@@ -603,4 +704,164 @@ namespace INSTALLER
return true;
}
}
ArchivePkgInstallData *GetArchivePkgInstallData(const std::string &hash)
{
return archive_pkg_install_data_list[hash];
}
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data)
{
std::pair<std::string, ArchivePkgInstallData*> pair = std::make_pair(hash, pkg_data);
archive_pkg_install_data_list.erase(hash);
archive_pkg_install_data_list.insert(pair);
}
void RemoveArchivePkgInstallData(const std::string &hash)
{
archive_pkg_install_data_list.erase(hash);
}
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data)
{
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)
{
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 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());
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();
}
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;
}
}
+29 -6
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,16 +121,32 @@ 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);
void Exit(void);
bool canInstallRemotePkg(const std::string &url);
std::string getRemoteUrl(const std::string filename, bool encodeUrl = false);
int InstallRemotePkg(const std::string &filename, pkg_header *header);
int InstallLocalPkg(const std::string &filename);
int InstallLocalPkg(const std::string &filename, pkg_header *header, bool remove_after_install = false);
bool ExtractLocalPkg(const std::string &filename, const std::string sfo_path, const std::string icon_path);
bool ExtractRemotePkg(const std::string &filename, const std::string sfo_path, const std::string icon_path);
std::string getRemoteUrl(const std::string path, bool encodeUrl = 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);
}
+125 -119
View File
@@ -10,124 +10,122 @@ char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE] = {
// This is properly populated so that emulator won't crash if an user launches it without language INI files.
char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"Connection Settings", // STR_CONNECTION_SETTINGS
"Site", // STR_SITE
"Local", // STR_LOCAL
"Remote", // STR_REMOTE
"Messages", // STR_MESSAGES
"Update Software", // STR_UPDATE_SOFTWARE
"Connect", // STR_CONNECT
"Disconnect", // STR_DISCONNECT
"Search", // STR_SEARCH
"Refresh", // STR_REFRESH
"Server", // STR_SERVER
"Username", // STR_USERNAME
"Password", // STR_PASSWORD
"Port", // STR_PORT
"Pasv", // STR_PASV
"Directory", // STR_DIRECTORY
"Filter", // STR_FILTER
"Yes", // STR_YES
"No", // STR_NO
"Cancel", // STR_CANCEL
"Continue", // STR_CONTINUE
"Close", // STR_CLOSE
"Folder", // STR_FOLDER
"File", // STR_FILE
"Type", // STR_TYPE
"Name", // STR_NAME
"Size", // STR_SIZE
"Date", // STR_DATE
"New Folder", // STR_NEW_FOLDER
"Rename", // STR_RENAME
"Delete", // STR_DELETE
"Upload", // STR_UPLOAD
"Download", // STR_DOWNLOAD
"Select All", // STR_SELECT_ALL
"Clear All", // STR_CLEAR_ALL
"Uploading", // STR_UPLOADING
"Downloading", // STR_DOWNLOADING
"Overwrite", // STR_OVERWRITE
"Don't Overwrite", // STR_DONT_OVERWRITE
"Ask for Confirmation", // STR_ASK_FOR_CONFIRM
"Don't Ask for Confirmation", // STR_DONT_ASK_CONFIRM
"Always use this option and don't ask again", // STR_ALLWAYS_USE_OPTION
"Actions", // STR_ACTIONS
"Confirm", // STR_CONFIRM
"Overwrite Options", // STR_OVERWRITE_OPTIONS
"Properties", // STR_PROPERTIES
"Progress", // STR_PROGRESS
"Updates", // STR_UPDATES
"Are you sure you want to delete this file(s)/folder(s)?", // STR_DEL_CONFIRM_MSG
"Canceling. Waiting for last action to complete", // STR_CANCEL_ACTION_MSG
"Failed to upload file", // STR_FAIL_UPLOAD_MSG
"Failed to download file", // STR_FAIL_DOWNLOAD_MSG
"Failed to read contents of directory or folder does not exist.", // STR_FAIL_READ_LOCAL_DIR_MSG
"426 Connection closed.", // STR_CONNECTION_CLOSE_ERR_MSG
"426 Remote Server has terminated the connection.", // STR_REMOTE_TERM_CONN_MSG
"300 Failed Login. Please check your username or password.", // STR_FAIL_LOGIN_MSG
"426 Failed. Connection timeout.", // STR_FAIL_TIMEOUT_MSG
"Failed to delete directory", // STR_FAIL_DEL_DIR_MSG
"Deleting", // STR_DELETING
"Failed to delete file", // STR_FAIL_DEL_FILE_MSG
"Deleted", // STR_DELETED
"Link", // STR_LINK
"Share", // STR_SHARE
"310 Failed", // STR_FAILED
"310 Failed to create file on local", // STR_FAIL_CREATE_LOCAL_FILE_MSG
"Install", // STR_INSTALL
"Installing", // STR_INSTALLING
"Success", // STR_INSTALL_SUCCESS
"Failed", // STR_INSTALL_FAILED
"Skipped", // STR_INSTALL_SKIPPED
"Checking connection to remote HTTP Server", // STR_CHECK_HTTP_MSG
"Failed connecting to HTTP Server", // STR_FAILED_HTTP_CHECK
"Remote is not a HTTP Server", // STR_REMOTE_NOT_HTTP
"Package not in the /data or /mnt/usbX folder", // STR_INSTALL_FROM_DATA_MSG
"Package is already installed", // STR_ALREADY_INSTALLED_MSG
"Install from URL", // STR_INSTALL_FROM_URL
"Could not read package header info", // STR_CANNOT_READ_PKG_HDR_MSG
"Favorite URLs", // STR_FAVORITE_URLS
"Slot", // STR_SLOT
"Edit", // STR_EDIT
"One Time Url", // STR_ONETIME_URL
"Not a valid Package", // STR_NOT_A_VALID_PACKAGE
"Waiting for Package to finish installing", // STR_WAIT_FOR_INSTALL_MSG
"Failed to install pkg file. Please delete the tmp pkg manually", // STR_FAIL_INSTALL_TMP_PKG_MSG
"Failed to obtain google download URL", // STR_FAIL_TO_OBTAIN_GG_DL_MSG
"Auto delete temporary downloaded pkg file after install", // STR_AUTO_DELETE_TMP_PKG
"Protocol not supported", // STR_PROTOCOL_NOT_SUPPORTED
"Could not resolve hostname", // STR_COULD_NOT_RESOLVE_HOST
"Extract", // STR_EXTRACT
"Extracting", // STR_EXTRACTING
"Failed to extract", // STR_FAILED_TO_EXTRACT
"Extract Location", // STR_EXTRACT_LOCATION
"Compress", // STR_COMPRESS
"Zip Filename", // STR_ZIP_FILE_PATH
"Compressing", // STR_COMPRESSING
"Error occured while creating zip", // STR_ERROR_CREATE_ZIP
"Unsupported compressed file format", // STR_UNSUPPORTED_FILE_FORMAT
"Cut", // STR_CUT
"Copy", // STR_COPY
"Paste", // STR_PASTE
"Moving", // STR_MOVING
"Copying", // STR_COPYING
"Failed to move file", // STR_FAIL_MOVE_MSG
"Failed to copy file", // STR_FAIL_COPY_MSG
"Cannot move parent directory to sub subdirectory", // STR_CANT_MOVE_TO_SUBDIR_MSG
"Cannot copy parent directory to sub subdirectory", // STR_CANT_COPY_TO_SUBDIR_MSG
"Operation not supported", // STR_UNSUPPORTED_OPERATION_MSG
"Http Port", // STR_HTTP_PORT
"The content has already been installed. Do you want to continue installing", // STR_REINSTALL_CONFIRM_MSG
"Remote package installation is not supported for protected servers.", // STR_REMOTE_NOT_SUPPORT_MSG
"Remote HTTP Server not reachable.", // STR_CANNOT_CONNECT_REMOTE_MSG
"Remote Package Install not possible. Would you like to download package and install?", // STR_DOWNLOAD_INSTALL_MSG
"Checking remote server for Remote Package Install.", // STR_CHECKING_REMOTE_SERVER_MSG
"RPI", // STR_ENABLE_RPI
"This option enables Remote Package Installation. "
"This requires a HTTP Server setup on the same host sharing the same folder with anonymous access.", // STR_ENABLE_RPI_FTP_SMB_MSG
"This option enables Remote Package Installation. "
"This requires the Server with anonymous access that does not need username/password.", // STR_ENABLE_RPI_WEBDAV_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
@@ -164,6 +162,14 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"Enable", // STR_ENABLE
"Compressed Files Location", // STR_COMPRESSED_FILE_PATH
"Location of where compressed files are stored on the web server", // STR_COMPRESSED_FILE_PATH_MSG
"AllDebrid", // STR_ALLDEBRID
"API Key", // STR_API_KEY
"Couldn't extract download url", // STR_CANT_EXTRACT_URL_MSG
"Failed to install from URL", // STR_FAIL_INSTALL_FROM_URL_MSG
"InValid URL", // STR_INVALID_URL
"To use this function, an API Key needs to be configured in the ezRemote Client settings", // STR_ALLDEBRID_API_KEY_MISSING_MSG
"Language", // STR_LANGUAGE
"Temp Directory", // STR_TEMP_DIRECTORY
};
bool needs_extended_font = false;
@@ -177,7 +183,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());
}
+162 -154
View File
@@ -3,159 +3,167 @@
#include "config.h"
#define FOREACH_STR(FUNC) \
FUNC(STR_CONNECTION_SETTINGS) \
FUNC(STR_SITE) \
FUNC(STR_LOCAL) \
FUNC(STR_REMOTE) \
FUNC(STR_MESSAGES) \
FUNC(STR_UPDATE_SOFTWARE) \
FUNC(STR_CONNECT) \
FUNC(STR_DISCONNECT) \
FUNC(STR_SEARCH) \
FUNC(STR_REFRESH) \
FUNC(STR_SERVER) \
FUNC(STR_USERNAME) \
FUNC(STR_PASSWORD) \
FUNC(STR_PORT) \
FUNC(STR_PASV) \
FUNC(STR_DIRECTORY) \
FUNC(STR_FILTER) \
FUNC(STR_YES) \
FUNC(STR_NO) \
FUNC(STR_CANCEL) \
FUNC(STR_CONTINUE) \
FUNC(STR_CLOSE) \
FUNC(STR_FOLDER) \
FUNC(STR_FILE) \
FUNC(STR_TYPE) \
FUNC(STR_NAME) \
FUNC(STR_SIZE) \
FUNC(STR_DATE) \
FUNC(STR_NEW_FOLDER) \
FUNC(STR_RENAME) \
FUNC(STR_DELETE) \
FUNC(STR_UPLOAD) \
FUNC(STR_DOWNLOAD) \
FUNC(STR_SELECT_ALL) \
FUNC(STR_CLEAR_ALL) \
FUNC(STR_UPLOADING) \
FUNC(STR_DOWNLOADING) \
FUNC(STR_OVERWRITE) \
FUNC(STR_DONT_OVERWRITE) \
FUNC(STR_ASK_FOR_CONFIRM) \
FUNC(STR_DONT_ASK_CONFIRM) \
FUNC(STR_ALLWAYS_USE_OPTION) \
FUNC(STR_ACTIONS) \
FUNC(STR_CONFIRM) \
FUNC(STR_OVERWRITE_OPTIONS) \
FUNC(STR_PROPERTIES) \
FUNC(STR_PROGRESS) \
FUNC(STR_UPDATES) \
FUNC(STR_DEL_CONFIRM_MSG) \
FUNC(STR_CANCEL_ACTION_MSG) \
FUNC(STR_FAIL_UPLOAD_MSG) \
FUNC(STR_FAIL_DOWNLOAD_MSG) \
FUNC(STR_FAIL_READ_LOCAL_DIR_MSG) \
FUNC(STR_CONNECTION_CLOSE_ERR_MSG) \
FUNC(STR_REMOTE_TERM_CONN_MSG) \
FUNC(STR_FAIL_LOGIN_MSG) \
FUNC(STR_FAIL_TIMEOUT_MSG) \
FUNC(STR_FAIL_DEL_DIR_MSG) \
FUNC(STR_DELETING) \
FUNC(STR_FAIL_DEL_FILE_MSG) \
FUNC(STR_DELETED) \
FUNC(STR_LINK) \
FUNC(STR_SHARE) \
FUNC(STR_FAILED) \
FUNC(STR_FAIL_CREATE_LOCAL_FILE_MSG) \
FUNC(STR_INSTALL) \
FUNC(STR_INSTALLING) \
FUNC(STR_INSTALL_SUCCESS) \
FUNC(STR_INSTALL_FAILED) \
FUNC(STR_INSTALL_SKIPPED) \
FUNC(STR_CHECK_HTTP_MSG) \
FUNC(STR_FAILED_HTTP_CHECK) \
FUNC(STR_REMOTE_NOT_HTTP) \
FUNC(STR_INSTALL_FROM_DATA_MSG) \
FUNC(STR_ALREADY_INSTALLED_MSG) \
FUNC(STR_INSTALL_FROM_URL) \
FUNC(STR_CANNOT_READ_PKG_HDR_MSG) \
FUNC(STR_FAVORITE_URLS) \
FUNC(STR_SLOT) \
FUNC(STR_EDIT) \
FUNC(STR_ONETIME_URL) \
FUNC(STR_NOT_A_VALID_PACKAGE) \
FUNC(STR_WAIT_FOR_INSTALL_MSG) \
FUNC(STR_FAIL_INSTALL_TMP_PKG_MSG) \
FUNC(STR_FAIL_TO_OBTAIN_GG_DL_MSG) \
FUNC(STR_AUTO_DELETE_TMP_PKG) \
FUNC(STR_PROTOCOL_NOT_SUPPORTED) \
FUNC(STR_COULD_NOT_RESOLVE_HOST) \
FUNC(STR_EXTRACT) \
FUNC(STR_EXTRACTING) \
FUNC(STR_FAILED_TO_EXTRACT) \
FUNC(STR_EXTRACT_LOCATION) \
FUNC(STR_COMPRESS) \
FUNC(STR_ZIP_FILE_PATH) \
FUNC(STR_COMPRESSING) \
FUNC(STR_ERROR_CREATE_ZIP) \
FUNC(STR_UNSUPPORTED_FILE_FORMAT) \
FUNC(STR_CUT) \
FUNC(STR_COPY) \
FUNC(STR_PASTE) \
FUNC(STR_MOVING) \
FUNC(STR_COPYING) \
FUNC(STR_FAIL_MOVE_MSG) \
FUNC(STR_FAIL_COPY_MSG) \
FUNC(STR_CANT_MOVE_TO_SUBDIR_MSG) \
FUNC(STR_CANT_COPY_TO_SUBDIR_MSG) \
FUNC(STR_UNSUPPORTED_OPERATION_MSG) \
FUNC(STR_HTTP_PORT) \
FUNC(STR_REINSTALL_CONFIRM_MSG) \
FUNC(STR_REMOTE_NOT_SUPPORT_MSG) \
FUNC(STR_CANNOT_CONNECT_REMOTE_MSG) \
FUNC(STR_DOWNLOAD_INSTALL_MSG) \
FUNC(STR_CHECKING_REMOTE_SERVER_MSG) \
FUNC(STR_ENABLE_RPI) \
FUNC(STR_ENABLE_RPI_FTP_SMB_MSG) \
FUNC(STR_ENABLE_RPI_WEBDAV_MSG) \
FUNC(STR_FILES) \
FUNC(STR_EDITOR) \
FUNC(STR_SAVE) \
FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \
FUNC(STR_DELETE_LINE) \
FUNC(STR_INSERT_LINE) \
FUNC(STR_MODIFIED) \
FUNC(STR_FAIL_GET_TOKEN_MSG) \
FUNC(STR_GET_TOKEN_SUCCESS_MSG) \
FUNC(STR_PERM_DRIVE) \
FUNC(STR_PERM_DRIVE_APPDATA) \
FUNC(STR_PERM_DRIVE_FILE) \
FUNC(STR_PERM_DRIVE_METADATA) \
FUNC(STR_PERM_DRIVE_METADATA_RO) \
FUNC(STR_GOOGLE_LOGIN_FAIL_MSG) \
FUNC(STR_GOOGLE_LOGIN_TIMEOUT_MSG) \
FUNC(STR_NEW_FILE) \
FUNC(STR_SETTINGS) \
FUNC(STR_CLIENT_ID) \
FUNC(STR_CLIENT_SECRET) \
FUNC(STR_GLOBAL) \
FUNC(STR_GOOGLE) \
FUNC(STR_COPY_LINE) \
FUNC(STR_PASTE_LINE) \
FUNC(STR_SHOW_HIDDEN_FILES) \
FUNC(STR_SET_DEFAULT_DIRECTORY) \
FUNC(STR_SET_DEFAULT_DIRECTORY_MSG) \
FUNC(STR_VIEW_IMAGE) \
FUNC(STR_VIEW_PKG_INFO) \
FUNC(STR_NFS_EXP_PATH_MISSING_MSG) \
FUNC(STR_FAIL_INIT_NFS_CONTEXT) \
FUNC(STR_FAIL_MOUNT_NFS_MSG) \
FUNC(STR_WEB_SERVER) \
FUNC(STR_ENABLE) \
FUNC(STR_COMPRESSED_FILE_PATH) \
FUNC(STR_COMPRESSED_FILE_PATH_MSG)
#define FOREACH_STR(FUNC) \
FUNC(STR_CONNECTION_SETTINGS) \
FUNC(STR_SITE) \
FUNC(STR_LOCAL) \
FUNC(STR_REMOTE) \
FUNC(STR_MESSAGES) \
FUNC(STR_UPDATE_SOFTWARE) \
FUNC(STR_CONNECT) \
FUNC(STR_DISCONNECT) \
FUNC(STR_SEARCH) \
FUNC(STR_REFRESH) \
FUNC(STR_SERVER) \
FUNC(STR_USERNAME) \
FUNC(STR_PASSWORD) \
FUNC(STR_PORT) \
FUNC(STR_PASV) \
FUNC(STR_DIRECTORY) \
FUNC(STR_FILTER) \
FUNC(STR_YES) \
FUNC(STR_NO) \
FUNC(STR_CANCEL) \
FUNC(STR_CONTINUE) \
FUNC(STR_CLOSE) \
FUNC(STR_FOLDER) \
FUNC(STR_FILE) \
FUNC(STR_TYPE) \
FUNC(STR_NAME) \
FUNC(STR_SIZE) \
FUNC(STR_DATE) \
FUNC(STR_NEW_FOLDER) \
FUNC(STR_RENAME) \
FUNC(STR_DELETE) \
FUNC(STR_UPLOAD) \
FUNC(STR_DOWNLOAD) \
FUNC(STR_SELECT_ALL) \
FUNC(STR_CLEAR_ALL) \
FUNC(STR_UPLOADING) \
FUNC(STR_DOWNLOADING) \
FUNC(STR_OVERWRITE) \
FUNC(STR_DONT_OVERWRITE) \
FUNC(STR_ASK_FOR_CONFIRM) \
FUNC(STR_DONT_ASK_CONFIRM) \
FUNC(STR_ALLWAYS_USE_OPTION) \
FUNC(STR_ACTIONS) \
FUNC(STR_CONFIRM) \
FUNC(STR_OVERWRITE_OPTIONS) \
FUNC(STR_PROPERTIES) \
FUNC(STR_PROGRESS) \
FUNC(STR_UPDATES) \
FUNC(STR_DEL_CONFIRM_MSG) \
FUNC(STR_CANCEL_ACTION_MSG) \
FUNC(STR_FAIL_UPLOAD_MSG) \
FUNC(STR_FAIL_DOWNLOAD_MSG) \
FUNC(STR_FAIL_READ_LOCAL_DIR_MSG) \
FUNC(STR_CONNECTION_CLOSE_ERR_MSG) \
FUNC(STR_REMOTE_TERM_CONN_MSG) \
FUNC(STR_FAIL_LOGIN_MSG) \
FUNC(STR_FAIL_TIMEOUT_MSG) \
FUNC(STR_FAIL_DEL_DIR_MSG) \
FUNC(STR_DELETING) \
FUNC(STR_FAIL_DEL_FILE_MSG) \
FUNC(STR_DELETED) \
FUNC(STR_LINK) \
FUNC(STR_SHARE) \
FUNC(STR_FAILED) \
FUNC(STR_FAIL_CREATE_LOCAL_FILE_MSG) \
FUNC(STR_INSTALL) \
FUNC(STR_INSTALLING) \
FUNC(STR_INSTALL_SUCCESS) \
FUNC(STR_INSTALL_FAILED) \
FUNC(STR_INSTALL_SKIPPED) \
FUNC(STR_CHECK_HTTP_MSG) \
FUNC(STR_FAILED_HTTP_CHECK) \
FUNC(STR_REMOTE_NOT_HTTP) \
FUNC(STR_INSTALL_FROM_DATA_MSG) \
FUNC(STR_ALREADY_INSTALLED_MSG) \
FUNC(STR_INSTALL_FROM_URL) \
FUNC(STR_CANNOT_READ_PKG_HDR_MSG) \
FUNC(STR_FAVORITE_URLS) \
FUNC(STR_SLOT) \
FUNC(STR_EDIT) \
FUNC(STR_ONETIME_URL) \
FUNC(STR_NOT_A_VALID_PACKAGE) \
FUNC(STR_WAIT_FOR_INSTALL_MSG) \
FUNC(STR_FAIL_INSTALL_TMP_PKG_MSG) \
FUNC(STR_FAIL_TO_OBTAIN_GG_DL_MSG) \
FUNC(STR_AUTO_DELETE_TMP_PKG) \
FUNC(STR_PROTOCOL_NOT_SUPPORTED) \
FUNC(STR_COULD_NOT_RESOLVE_HOST) \
FUNC(STR_EXTRACT) \
FUNC(STR_EXTRACTING) \
FUNC(STR_FAILED_TO_EXTRACT) \
FUNC(STR_EXTRACT_LOCATION) \
FUNC(STR_COMPRESS) \
FUNC(STR_ZIP_FILE_PATH) \
FUNC(STR_COMPRESSING) \
FUNC(STR_ERROR_CREATE_ZIP) \
FUNC(STR_UNSUPPORTED_FILE_FORMAT) \
FUNC(STR_CUT) \
FUNC(STR_COPY) \
FUNC(STR_PASTE) \
FUNC(STR_MOVING) \
FUNC(STR_COPYING) \
FUNC(STR_FAIL_MOVE_MSG) \
FUNC(STR_FAIL_COPY_MSG) \
FUNC(STR_CANT_MOVE_TO_SUBDIR_MSG) \
FUNC(STR_CANT_COPY_TO_SUBDIR_MSG) \
FUNC(STR_UNSUPPORTED_OPERATION_MSG) \
FUNC(STR_HTTP_PORT) \
FUNC(STR_REINSTALL_CONFIRM_MSG) \
FUNC(STR_REMOTE_NOT_SUPPORT_MSG) \
FUNC(STR_CANNOT_CONNECT_REMOTE_MSG) \
FUNC(STR_DOWNLOAD_INSTALL_MSG) \
FUNC(STR_CHECKING_REMOTE_SERVER_MSG) \
FUNC(STR_ENABLE_RPI) \
FUNC(STR_ENABLE_RPI_FTP_SMB_MSG) \
FUNC(STR_ENABLE_RPI_WEBDAV_MSG) \
FUNC(STR_FILES) \
FUNC(STR_EDITOR) \
FUNC(STR_SAVE) \
FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \
FUNC(STR_DELETE_LINE) \
FUNC(STR_INSERT_LINE) \
FUNC(STR_MODIFIED) \
FUNC(STR_FAIL_GET_TOKEN_MSG) \
FUNC(STR_GET_TOKEN_SUCCESS_MSG) \
FUNC(STR_PERM_DRIVE) \
FUNC(STR_PERM_DRIVE_APPDATA) \
FUNC(STR_PERM_DRIVE_FILE) \
FUNC(STR_PERM_DRIVE_METADATA) \
FUNC(STR_PERM_DRIVE_METADATA_RO) \
FUNC(STR_GOOGLE_LOGIN_FAIL_MSG) \
FUNC(STR_GOOGLE_LOGIN_TIMEOUT_MSG) \
FUNC(STR_NEW_FILE) \
FUNC(STR_SETTINGS) \
FUNC(STR_CLIENT_ID) \
FUNC(STR_CLIENT_SECRET) \
FUNC(STR_GLOBAL) \
FUNC(STR_GOOGLE) \
FUNC(STR_COPY_LINE) \
FUNC(STR_PASTE_LINE) \
FUNC(STR_SHOW_HIDDEN_FILES) \
FUNC(STR_SET_DEFAULT_DIRECTORY) \
FUNC(STR_SET_DEFAULT_DIRECTORY_MSG) \
FUNC(STR_VIEW_IMAGE) \
FUNC(STR_VIEW_PKG_INFO) \
FUNC(STR_NFS_EXP_PATH_MISSING_MSG) \
FUNC(STR_FAIL_INIT_NFS_CONTEXT) \
FUNC(STR_FAIL_MOUNT_NFS_MSG) \
FUNC(STR_WEB_SERVER) \
FUNC(STR_ENABLE) \
FUNC(STR_COMPRESSED_FILE_PATH) \
FUNC(STR_COMPRESSED_FILE_PATH_MSG) \
FUNC(STR_ALLDEBRID) \
FUNC(STR_API_KEY) \
FUNC(STR_CANT_EXTRACT_URL_MSG) \
FUNC(STR_FAIL_INSTALL_FROM_URL_MSG) \
FUNC(STR_INVALID_URL) \
FUNC(STR_ALLDEBRID_API_KEY_MISSING_MSG) \
FUNC(STR_LANGUAGE) \
FUNC(STR_TEMP_DIRECTORY)
#define GET_VALUE(x) x,
#define GET_STRING(x) #x,
@@ -165,7 +173,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 152
#define LANG_STRINGS_NUM 160
#define LANG_ID_SIZE 64
#define LANG_STR_SIZE 384
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
+61
View File
@@ -2,9 +2,70 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/uio.h>
#include <orbis/libkernel.h>
#include <libjbc.h>
#define SYSCALL(nr, fn) __attribute__((naked)) fn\
{\
asm volatile("mov $" #nr ", %rax\nmov %rcx, %r10\nsyscall\nret");\
}
SYSCALL(22, static int unmount(const char* path, int flags))
SYSCALL(378, static int nmount(struct iovec* iov, unsigned int niov, int flags))
static void build_iovec(struct iovec** iov, int* iovlen, const char* name, const void* val, size_t len) {
int i;
if (*iovlen < 0)
return;
i = *iovlen;
*iov = (struct iovec*)realloc(*iov, sizeof **iov * (i + 2));
if (*iov == NULL) {
*iovlen = -1;
return;
}
(*iov)[i].iov_base = strdup(name);
(*iov)[i].iov_len = strlen(name) + 1;
++i;
(*iov)[i].iov_base = (void*)val;
if (len == (size_t)-1) {
if (val != NULL)
len = strlen((const char*)val) + 1;
else
len = 0;
}
(*iov)[i].iov_len = (int)len;
*iovlen = ++i;
}
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags)
{
struct iovec* iov = NULL;
int iovlen = 0;
unmount(mountpoint, 0);
build_iovec(&iov, &iovlen, "fstype", fstype, -1);
build_iovec(&iov, &iovlen, "fspath", mountpoint, -1);
build_iovec(&iov, &iovlen, "from", device, -1);
build_iovec(&iov, &iovlen, "large", "yes", -1);
build_iovec(&iov, &iovlen, "timezone", "static", -1);
build_iovec(&iov, &iovlen, "async", "", -1);
build_iovec(&iov, &iovlen, "ignoreacl", "", -1);
if (mode) {
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
build_iovec(&iov, &iovlen, "mask", mode, -1);
}
return nmount(iov, iovlen, flags);
}
// Variables for (un)jailbreaking
jbc_cred g_Cred;
jbc_cred g_RootCreds;
+3
View File
@@ -1,7 +1,10 @@
#ifndef __ORBIS_JBC_H__
#define __ORBIS_JBC_H__
#define MNT_UPDATE 0x0000000000010000ULL
int initialize_jbc();
void terminate_jbc();
int mount_large_fs(const char* device, const char* mountpoint, const char* fstype, const char* mode, unsigned int flags);
#endif
+316 -3
View File
@@ -1,14 +1,21 @@
#include <string>
#include <json-c/json.h>
#include <range_parser/range_parser.hpp>
#include "http/httplib.h"
#include "server/http_server.h"
#include "clients/gdrive.h"
#include "clients/sftpclient.h"
#include "clients/smbclient.h"
#include "clients/ftpclient.h"
#include "clients/nfsclient.h"
#include "filehost/filehost.h"
#include "config.h"
#include "fs.h"
#include "windows.h"
#include "lang.h"
#include "system.h"
#include "zip_util.h"
#include "util.h"
#include "installer.h"
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
@@ -19,6 +26,7 @@
#define SUCCESS_MSG_LEN 48
using namespace httplib;
Server *svr;
int http_server_port = 8080;
char compressed_file_path[1024];
@@ -382,7 +390,15 @@ namespace HttpServer
{
const char *src = json_object_get_string(json_object_array_get_idx(items, 0));
std::string dest = std::string(newPath) + "/" + singleFilename;
if (dest.compare(src) != 0 && !FS::Copy(src, dest))
std::string temp = std::string(src);
size_t slash_pos = temp.find_last_of("/");
DirEntry entry;
sprintf(entry.name, "%s", temp.substr(slash_pos+1).c_str());
sprintf(entry.path, "%s", src);
entry.isDir = FS::IsFolder(src);
if (entry.isDir)
if (dest.compare(src) != 0 && !CopyOrMove(entry, dest.c_str(), true))
{
failed_items += src;
}
@@ -699,6 +715,7 @@ namespace HttpServer
size_t chunk_size = 0;
size_t chunk_number = -1;
size_t total_size = 0;
size_t currentChunkSize = 0;
FILE *out = nullptr;
std::string new_file;
content_reader(
@@ -742,6 +759,11 @@ namespace HttpServer
std::stringstream ss(items.back().content);
ss >> total_size;
}
else if (items.back().name == "_currentChunkSize")
{
std::stringstream ss(items.back().content);
ss >> currentChunkSize;
}
else
{
if (out != nullptr)
@@ -900,6 +922,297 @@ namespace HttpServer
res.set_content(str.c_str(), "text/plain");
});
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request & req, Response & res)
{
RemoteClient *tmp_client;
RemoteSettings *tmp_settings;
auto site_idx = std::stoi(req.matches[1])-1;
std::string path;
if (site_idx != 98)
{
path = std::string("/") + std::string(req.matches[3]);
tmp_settings = &site_settings[sites[site_idx]];
if (tmp_settings->type == CLIENT_TYPE_SFTP)
{
tmp_client = new SFTPClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else if (tmp_settings->type == CLIENT_TYPE_SMB)
{
tmp_client = new SmbClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else if (tmp_settings->type == CLIENT_TYPE_FTP)
{
tmp_client = new FtpClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else if (tmp_settings->type == CLIENT_TYPE_NFS)
{
tmp_client = new NfsClient();
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
}
else
{
tmp_client = remoteclient;
}
}
else
{
std::string hash = std::string(req.matches[3]);
std::string url = FileHost::GetCachedDownloadUrl(hash);
size_t scheme_pos = url.find("://");
size_t root_pos = url.find("/", scheme_pos + 3);
std::string host = url.substr(0, root_pos);
path = url.substr(root_pos);
tmp_client = new BaseClient();
tmp_client->Connect(host, "", "");
}
if (tmp_client == nullptr || !tmp_client->IsConnected())
{
res.status = 404;
return;
}
if (req.method == "HEAD")
{
int64_t file_size;
int ret;
ret = tmp_client->Size(path, &file_size);
if (!ret)
{
res.status = 500;
return;
}
res.status = 204;
res.set_header("Content-Length", std::to_string(file_size));
res.set_header("Accept-Ranges", "bytes");
return;
}
if (req.ranges.empty())
{
res.status = 200;
res.set_content_provider(
(1024*128), "application/octet-stream",
[tmp_client, path](size_t offset, size_t length, DataSink &sink) {
int ret = tmp_client->GetRange(path, sink, length, offset);
return (ret == 1);
},
[tmp_client, path, site_idx](bool success) {
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
{
tmp_client->Quit();
delete tmp_client;
}
});
}
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 = 65536ul - 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));
}
std::pair<ssize_t, ssize_t> range = req.ranges[0];
res.set_content_provider(
range_len, "application/octet-stream",
[tmp_client, path, range, range_len](size_t offset, size_t length, DataSink &sink) {
int ret = tmp_client->GetRange(path, sink, range_len, range.first);
return (ret == 1);
},
[tmp_client, site_idx, path, range, range_len](bool success) {
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
{
tmp_client->Quit();
delete tmp_client;
}
});
}
});
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 = 65536ul - 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));
}
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;
json_object *jobj = json_tokener_parse(req.body.c_str());
if (jobj != nullptr)
{
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
if (url_param == nullptr)
{
bad_request(res, "Required url_param, use_alldebrid parameter missing");
return;
}
}
else
{
bad_request(res, "Invalid payload");
return;
}
if (use_alldebrid && strlen(alldebrid_api_key) == 0)
{
failed(res, 200, lang_strings[STR_ALLDEBRID_API_KEY_MISSING_MSG]);
return;
}
url = std::string(url_param);
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid);
if (!filehost->IsValidUrl())
{
failed(res, 200, lang_strings[STR_INVALID_URL]);
return;
}
std::string hash = Util::UrlHash(filehost->GetUrl());
std::string download_url = filehost->GetDownloadUrl();
if (download_url.empty())
{
failed(res, 200, lang_strings[STR_CANT_EXTRACT_URL_MSG]);
return;
}
delete(filehost);
size_t scheme_pos = download_url.find("://");
size_t root_pos = download_url.find("/", scheme_pos + 3);
std::string host = download_url.substr(0, root_pos);
std::string path = download_url.substr(root_pos);
pkg_header header;
BaseClient *baseclient = new BaseClient();
baseclient->Connect(host, "", "");
baseclient->Head(path, &header, sizeof(pkg_header));
if (BE32(header.pkg_magic) == 0x7F434E54)
{
FileHost::AddCacheDownloadUrl(hash, download_url);
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
delete(baseclient);
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title);
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);
free(entry);
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);
});
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
{
svr->stop();
@@ -919,7 +1232,7 @@ namespace HttpServer
dbglogger_log("%s", log(req, res).c_str());
});
*/
svr->set_payload_max_length(1024 * 1024 * 12);
svr->set_tcp_nodelay(true);
svr->set_mount_point("/", "/");
@@ -948,4 +1261,4 @@ namespace HttpServer
if (svr != nullptr)
svr->stop();
}
}
}
+221
View File
@@ -0,0 +1,221 @@
#include <stdio.h>
#include <stdio.h>
#include <string>
#include "common.h"
#include "split_file.h"
SplitFile::SplitFile(const std::string &path, size_t block_size)
{
this->block_size = block_size;
this->path = path;
this->complete = false;
sem_init(&this->block_ready, 0, 0);
}
SplitFile::~SplitFile()
{
for (int i = 0; i < this->file_blocks.size(); i++)
{
if (this->file_blocks[i] != nullptr && this->file_blocks[i]->status != BLOCK_STATUS_DELETED)
{
if (this->file_blocks[i]->fd != nullptr)
{
fclose(this->file_blocks[i]->fd);
}
remove(this->file_blocks[i]->block_file.c_str());
free(this->file_blocks[i]);
}
}
sem_destroy(&this->block_ready);
};
int SplitFile::Open()
{
this->block_in_progress = NewBlock();
this->block_in_progress->fd = fopen(block_in_progress->block_file.c_str(), "w");
return (block_in_progress->fd == nullptr);
}
size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
{
int first_block_num, block_num;
size_t block_offset;
size_t remaining;
size_t bytes_read;
size_t total_bytes_read;
FileBlock *block;
FILE *fd;
char *p;
first_block_num= offset / this->block_size;
block_num = first_block_num;
block_offset = offset % this->block_size;
while ((block_num >= this->file_blocks.size() && !this->complete) ||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
if (block->status == BLOCK_STATUS_DELETED)
{
return -1;
}
if (block_offset > block->size - 1 && this->complete)
{
// requested offset is pass the end of split file
return 0;
}
remaining = buf_size;
bool eof = false;
total_bytes_read = 0;
p = buf;
while (remaining > 0 && !eof)
{
fd = block->fd;
if (fd == nullptr)
{
fd = fopen(block->block_file.c_str(), "rb");
block->fd = fd;
}
fseek(fd, block_offset, SEEK_SET);
bytes_read = fread(p, 1, remaining, fd);
if (bytes_read == remaining)
{
p += bytes_read;
total_bytes_read += bytes_read;
}
else
{
if (feof(fd))
{
p += bytes_read;
total_bytes_read += bytes_read;
if (block->is_last)
{
eof = true;
continue;
}
}
else
return -1;
}
remaining -= bytes_read;
if (remaining == 0)
continue;
block_num++;
block_offset = 0;
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
{
sem_wait(&this->block_ready);
}
block = this->file_blocks[block_num];
}
// delete blocks before the first read offset block. Assumuption, that reads are always
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
for (int j=0; j < first_block_num - 2; j++)
{
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
{
if (this->file_blocks[j]->fd != nullptr)
{
fclose(this->file_blocks[j]->fd);
this->file_blocks[j]->fd = nullptr;
}
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
remove(this->file_blocks[j]->block_file.c_str());
}
}
return total_bytes_read;
}
size_t SplitFile::Write(char *buf, size_t buf_size)
{
size_t bytes_written;
size_t block_space_remaining;
size_t bytes_to_write;
char *p = buf;
size_t total_bytes_written = 0;
size_t remaining_to_write = buf_size;
while (remaining_to_write > 0)
{
block_space_remaining = this->block_size - block_in_progress->size;
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
bytes_written = fwrite(p, 1, bytes_to_write, block_in_progress->fd);
block_in_progress->size += bytes_written;
total_bytes_written += bytes_written;
remaining_to_write -= bytes_written;
block_space_remaining -= bytes_written;
p += bytes_written;
// error if bytes_to_write != bytes_written
if (bytes_written != bytes_to_write)
{
break;
}
if (block_space_remaining == 0)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
block_in_progress->status = BLOCK_STATUS_CREATED;
this->file_blocks.push_back(block_in_progress);
sem_post(&this->block_ready);
block_in_progress = NewBlock();
}
}
return total_bytes_written;
}
int SplitFile::Close()
{
if (block_in_progress->fd != nullptr)
{
fflush(block_in_progress->fd);
fclose(block_in_progress->fd);
block_in_progress->fd = nullptr;
}
block_in_progress->status = BLOCK_STATUS_CREATED;
block_in_progress->is_last = true;
this->file_blocks.push_back(block_in_progress);
this->complete = true;
sem_post(&this->block_ready);
return 0;
}
FileBlock *SplitFile::NewBlock()
{
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
memset(block, 0, sizeof(FileBlock));
block->is_last = false;
block->size = 0;
block->block_file = this->path + "." + std::to_string(this->file_blocks.size());
block->fd = fopen(block->block_file.c_str(), "w");
return block;
}
+48
View File
@@ -0,0 +1,48 @@
#ifndef SPLIT_FILE_H
#define SPLIT_FILE_H
#include <string>
#include <vector>
#include <mutex>
#include <pthread.h>
enum FileBlockStatus
{
BLOCK_STATUS_NOT_EXISTS,
BLOCK_STATUS_CREATED,
BLOCK_STATUS_DELETED
};
typedef struct
{
std::string block_file;
size_t size;
FILE* fd;
bool is_last;
FileBlockStatus status;
} FileBlock;
class SplitFile
{
public:
SplitFile(const std::string& path, size_t block_size);
~SplitFile();
size_t Read(char* buf, size_t buf_size, size_t offset);
size_t Write(char* buf, size_t buf_size);
int Open();
int Close();
private:
std::vector<FileBlock*> file_blocks;
size_t write_offset;
size_t block_size;
std::string path;
int write_error;
bool complete;
FileBlock *block_in_progress;
sem_t block_ready;
FileBlock *NewBlock();
};
#endif
+22
View File
@@ -6,6 +6,8 @@
#include <algorithm>
#include <stdarg.h>
#include <orbis/libkernel.h>
#include "base64.h"
#include "openssl/md5.h"
#include "lang.h"
namespace Util
@@ -47,6 +49,13 @@ namespace Util
return s;
}
static inline bool EndsWith(std::string const &value, std::string const &ending)
{
if (ending.size() > value.size())
return false;
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
static inline std::vector<std::string> Split(const std::string &str, const std::string &delimiter)
{
std::string text = std::string(str);
@@ -66,6 +75,19 @@ namespace Util
return tokens;
}
static inline std::string UrlHash(const std::string &text)
{
std::vector<unsigned char> res(16);
MD5((const unsigned char *)text.c_str(), text.length(), res.data());
std::string out;
Base64::Encode(res.data(), res.size(), out);
Util::ReplaceAll(out, "=", "_");
Util::ReplaceAll(out, "+", "_");
out = out + ".pkg";
return out;
}
static inline void Notify(const char *fmt, ...)
{
OrbisNotificationRequest request;
+11
View File
@@ -23,9 +23,12 @@
#include <algorithm>
#include <fstream>
#include <cstring>
#include "http/httplib.h"
#include "callback.hpp"
using namespace httplib;
namespace Web
{
namespace Callback
@@ -104,6 +107,14 @@ namespace Web
out_stream->write(ptr, write_bytes);
return write_bytes;
}
size_t stream2sink(char* ptr, size_t item_size, size_t item_count, void* sink)
{
auto ostream = reinterpret_cast<DataSink*>(sink);
size_t write_bytes = item_size * item_count;
ostream->write(ptr, write_bytes);
return write_bytes;
}
} // namespace Append
} // namespace Callback
} // namespace Web
+1
View File
@@ -60,6 +60,7 @@ namespace Web
{
size_t stream(char* data, size_t size, size_t count, void* stream);
size_t buffer(char* data, size_t size, size_t count, void* buffer);
size_t stream2sink(char* ptr, size_t item_size, size_t item_count, void* sink);
}
}
} // namespace Web
+64
View File
@@ -29,6 +29,7 @@
#include "web/request.hpp"
#include "web/urn.hpp"
#include "util.h"
#include "http/httplib.h"
#include <algorithm>
#include <thread>
@@ -234,6 +235,57 @@ bool
return true;
}
bool
Client::sync_download_range_to(
const std::string &remote_file,
DataSink &sink,
uint64_t range_from,
uint64_t range_to,
callback_t callback,
progress_data_t progress_data,
progress_t progress)
{
bool is_existed = this->check(remote_file);
if (!is_existed)
return false;
auto root_urn = Path(this->webdav_root, true);
auto file_urn = root_urn + remote_file;
Request request(this->options());
auto url = this->webdav_hostname + file_urn.quote(request.handle);
struct curl_slist *list = NULL;
char range_header[64];
sprintf(range_header, "Range: bytes=%lu-%lu", range_from, range_to);
list = curl_slist_append(list, range_header);
request.set(CURLOPT_CUSTOMREQUEST, "GET");
request.set(CURLOPT_URL, url.c_str());
request.set(CURLOPT_HEADER, 0L);
request.set(CURLOPT_HTTPHEADER, list);
request.set(CURLOPT_WRITEDATA, reinterpret_cast<void*>(&sink));
request.set(CURLOPT_WRITEFUNCTION, reinterpret_cast<size_t>(Web::Callback::Append::stream2sink));
#ifdef WDC_VERBOSE
request.set(CURLOPT_VERBOSE, 1);
#endif
if (progress != nullptr)
{
request.set(CURLOPT_XFERINFODATA, progress_data);
request.set(CURLOPT_XFERINFOFUNCTION, progress);
request.set(CURLOPT_NOPROGRESS, 0L);
}
bool is_performed = request.perform();
this->http_code = request.status_code();
this->result = request.result();
if (callback != nullptr)
callback(is_performed);
if (!is_performed)
return false;
return true;
}
bool
Client::sync_download_to(
const std::string &remote_file,
@@ -777,6 +829,18 @@ bool
return this->sync_download_range_to(remote_file, buffer_ptr, buffer_size, range_from, range_to, nullptr, progress_data, std::move(progress));
}
bool
Client::download_range_to(
const std::string &remote_file,
DataSink &sink,
uint64_t range_from,
uint64_t range_to,
progress_data_t progress_data,
progress_t progress)
{
return this->sync_download_range_to(remote_file, sink, range_from, range_to, nullptr, progress_data, std::move(progress));
}
bool
Client::download_to(
const std::string &remote_file,
+31
View File
@@ -29,6 +29,9 @@
#include <string>
#include <vector>
#include <curl/curl.h>
#include "http/httplib.h"
using namespace httplib;
namespace WebDAV
{
@@ -208,6 +211,24 @@ namespace WebDAV
progress_t progress = nullptr
) -> bool;
///
/// Download a remote file to a buffer for specified range
/// \param[in] remote_file
/// \param[out] sink,
/// \param[in] range_from,
/// \param[in] range_to
/// \param[in] progress
/// \snippet client/download.cpp download_to_buffer
///
auto download_range_to(
const std::string &remote_file,
DataSink &sink,
uint64_t range_from,
uint64_t range_to,
progress_data_t progress_data = nullptr,
progress_t progress = nullptr
) -> bool;
///
/// Download a remote file to a stream
/// \param[in] remote_file
@@ -330,6 +351,16 @@ namespace WebDAV
progress_t progress = nullptr
) -> bool;
auto sync_download_range_to(
const std::string &remote_file,
DataSink &sink,
uint64_t range_from,
uint64_t range_to,
callback_t callback,
progress_data_t progress_data,
progress_t progress
) -> bool;
bool sync_download_to(
const std::string& remote_file,
std::ostream& stream,
+160 -85
View File
@@ -39,7 +39,6 @@ static char *ime_single_field;
static int ime_field_size;
static char txt_http_server_port[6];
static char txt_http_port[6];
bool handle_updates = false;
int64_t bytes_transfered;
@@ -118,7 +117,6 @@ namespace Windows
sprintf(status_message, "");
sprintf(local_filter, "");
sprintf(remote_filter, "");
sprintf(txt_http_port, "%d", remote_settings->http_port);
sprintf(txt_http_server_port, "%d", http_server_port);
dont_prompt_overwrite = false;
confirm_transfer_state = -1;
@@ -245,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
{
@@ -320,7 +331,6 @@ namespace Windows
sprintf(display_site, "%s", site_id);
remote_settings = &site_settings[sites[n]];
sprintf(remote_directory, "%s", remote_settings->default_directory);
sprintf(txt_http_port, "%d", remote_settings->http_port);
}
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
@@ -402,66 +412,42 @@ namespace Windows
ImGui::SameLine();
}
if (remote_settings->type != CLIENT_TYPE_GOOGLE)
if (remote_settings->type != CLIENT_TYPE_NFS && remote_settings->type != CLIENT_TYPE_GOOGLE)
{
if (remote_settings->type != CLIENT_TYPE_NFS)
{
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_PASSWORD]);
ImGui::SameLine();
sprintf(id, "%s##password", hidden_password.c_str());
pos = ImGui::GetCursorPos();
if (ImGui::Button(id, ImVec2(100, 0)))
{
ime_single_field = remote_settings->password;
ResetImeCallbacks();
ime_field_size = 127;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_PASSWORD], remote_settings->password, 127, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y);
gui_mode = GUI_MODE_IME;
}
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_ENABLE_RPI]);
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_PASSWORD]);
ImGui::SameLine();
if (ImGui::Checkbox("###enable_rpi", &remote_settings->enable_rpi))
sprintf(id, "%s##password", hidden_password.c_str());
pos = ImGui::GetCursorPos();
if (ImGui::Button(id, ImVec2(100, 0)))
{
CONFIG::SaveConfig();
}
if (ImGui::IsItemHovered())
{
ImGui::SetNextWindowSize(ImVec2(450, 135));
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 440);
ImGui::Text("%s", (remote_settings->type == CLIENT_TYPE_SMB || remote_settings->type == CLIENT_TYPE_FTP) ? lang_strings[STR_ENABLE_RPI_FTP_SMB_MSG] : lang_strings[STR_ENABLE_RPI_WEBDAV_MSG]);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
ime_single_field = remote_settings->password;
ResetImeCallbacks();
ime_field_size = 127;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_PASSWORD], remote_settings->password, 127, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y);
gui_mode = GUI_MODE_IME;
}
}
if ((remote_settings->type == CLIENT_TYPE_NFS || remote_settings->type == CLIENT_TYPE_SMB || remote_settings->type == CLIENT_TYPE_FTP) && remote_settings->enable_rpi)
{
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_HTTP_PORT]);
ImGui::SameLine();
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_ENABLE_RPI]);
ImGui::SameLine();
sprintf(id, "%s##http_port", txt_http_port);
pos = ImGui::GetCursorPos();
if (ImGui::Button(id, ImVec2(65, 0)))
{
ime_single_field = txt_http_port;
ResetImeCallbacks();
ime_field_size = 24;
ime_callback = SingleValueImeCallback;
ime_after_update = AfterHttpPortChangeCallback;
Dialog::initImeDialog(lang_strings[STR_PASSWORD], txt_http_port, 24, ORBIS_TYPE_NUMBER, pos.x, pos.y);
gui_mode = GUI_MODE_IME;
}
}
if (ImGui::Checkbox("###enable_rpi", &remote_settings->enable_rpi))
{
CONFIG::SaveConfig();
}
if (ImGui::IsItemHovered())
{
ImGui::SetNextWindowSize(ImVec2(450, 70));
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 440);
ImGui::Text("%s", lang_strings[STR_ENABLE_RPI_FTP_SMB_MSG]);
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
ImGui::PopStyleVar();
@@ -1076,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)))
{
@@ -1632,11 +1621,38 @@ namespace Windows
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
ImGui::SetNextWindowPos(ImVec2(1050, 80));
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 500), NULL, NULL);
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 650), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
char id[192];
ImVec2 field_size;
float width;
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_LANGUAGE]);
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::SetNextItemWidth(690);
if (ImGui::BeginCombo("##Language", language, ImGuiComboFlags_PopupAlignLeft | ImGuiComboFlags_HeightLargest))
{
for (int n = 0; n < langs.size(); n++)
{
const bool is_selected = strcmp(langs[n].c_str(), language) == 0;
if (ImGui::Selectable(langs[n].c_str(), is_selected))
{
sprintf(language, "%s", langs[n].c_str());
}
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_AUTO_DELETE_TMP_PKG]);
ImGui::SameLine();
@@ -1650,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();
@@ -1660,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)))
@@ -1701,6 +1735,34 @@ namespace Windows
ImGui::PopStyleVar();
ImGui::Separator();
// Google settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
ImGui::Separator();
field_size = ImGui::CalcTextSize(lang_strings[STR_API_KEY]);
width = field_size.x + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_API_KEY]);
ImGui::SameLine();
ImGui::SetCursorPosX(width);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (strlen(alldebrid_api_key) > 0)
sprintf(id, "%s", "*********************************************##alldebrid_api_key");
else
sprintf(id, "%s", "##client_secret_input");
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = alldebrid_api_key;
ime_field_size = 31;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_API_KEY], alldebrid_api_key, 31, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
// Google settings
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GOOGLE]);
ImGui::Separator();
@@ -1999,10 +2061,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;
@@ -2382,6 +2453,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;
@@ -2399,7 +2475,6 @@ namespace Windows
{
if (ime_result == IME_DIALOG_RESULT_FINISHED)
{
remote_settings->http_port = atoi(txt_http_port);
http_server_port = atoi(txt_http_server_port);
}
}
+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