Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 28c046d5a5 | |||
| 99099a6b82 | |||
| c30a8ab70e | |||
| 046083ccf6 | |||
| 6d36073413 | |||
| b831dd7db4 | |||
| 3ba286a016 | |||
| 7395056a75 | |||
| 81a5143f2f | |||
| 432c0020be | |||
| fd1b9e5d96 | |||
| a3741a0a6c | |||
| ce71f5af9a | |||
| cd42afcb6b | |||
| b6eaef82fd | |||
| 9d0790fccc | |||
| bfe2505efc | |||
| 749a79d8b9 | |||
| c03201c040 | |||
| 7be30e358a | |||
| d58fc0eac2 | |||
| ed3f8a71c4 | |||
| 13279b6040 | |||
| eb465356b6 | |||
| 8602a5353e | |||
| 467a459665 | |||
| b7fe46cb94 | |||
| 3bcf136d2a | |||
| e5d5ddb8bc | |||
| 3e4b5e3ea2 | |||
| c4889ec160 | |||
| 3076f4b179 | |||
| 93fb338ce0 | |||
| 785a073bce | |||
| a71bd1eb28 | |||
| 0a1420dd96 | |||
| dcdc1fc54b | |||
| 5c254589e6 | |||
| 2b25272379 | |||
| 6b66d39eba | |||
| b143c3e3c5 | |||
| c3cc6d5954 | |||
| cfcb420b9d | |||
| 294455c735 | |||
| 4ff119b34d | |||
| 114c1974e1 | |||
| a99bf163d8 | |||
| b9ab71577f | |||
| f80b3112c6 | |||
| e0c72c85e5 | |||
| 01f568feac | |||
| 2046a0e096 | |||
| 49f535dfde | |||
| 5a250a4182 | |||
| 89fa9aba69 | |||
| 0feff205d2 | |||
| 5df5447eb0 | |||
| b87dc91c6f | |||
| 14b32504e0 | |||
| d35345a270 | |||
| f041172768 | |||
| 232a6233ca | |||
| c620478691 |
@@ -11,3 +11,4 @@ CTestTestfile.cmake
|
||||
_deps
|
||||
.vscode
|
||||
build
|
||||
data/daemon
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "ps4-ezremote-server"]
|
||||
path = ps4-ezremote-server
|
||||
url = git@github.com:cy33hc/ps4-ezremote-server.git
|
||||
+17
-6
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(ezremote_client)
|
||||
|
||||
@@ -25,8 +25,11 @@ add_executable(ezremote_client
|
||||
source/http/httplib.cpp
|
||||
source/clients/baseclient.cpp
|
||||
source/clients/apache.cpp
|
||||
source/clients/archiveorg.cpp
|
||||
source/clients/ftpclient.cpp
|
||||
source/clients/gdrive.cpp
|
||||
source/clients/github.cpp
|
||||
source/clients/myrient.cpp
|
||||
source/clients/iis.cpp
|
||||
source/clients/nginx.cpp
|
||||
source/clients/npxserve.cpp
|
||||
@@ -62,13 +65,11 @@ add_executable(ezremote_client
|
||||
source/windows.cpp
|
||||
source/zip_util.cpp
|
||||
source/split_file.cpp
|
||||
source/mem_file.cpp
|
||||
)
|
||||
|
||||
add_self(ezremote_client)
|
||||
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.22" 32 0)
|
||||
|
||||
target_link_libraries(ezremote_client
|
||||
dbglogger
|
||||
c
|
||||
c++
|
||||
png
|
||||
@@ -106,9 +107,19 @@ target_link_libraries(ezremote_client
|
||||
SceUserService
|
||||
ScePad
|
||||
SceAudioOut
|
||||
SceSysUtil
|
||||
SceImeDialog
|
||||
SceNet
|
||||
SceBgft
|
||||
SceAppInstUtil
|
||||
SceLncUtil
|
||||
)
|
||||
|
||||
add_self(ezremote_client)
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "02.00" 32 0)
|
||||
|
||||
add_custom_target(package
|
||||
COMMAND mkdir -p ${PROJECT_SOURCE_DIR}/data/daemon
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/ps4-ezremote-server/data/eboot.bin ${PROJECT_SOURCE_DIR}/data/daemon/daemon.self
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/ps4-ezremote-server/data/eboot.md5 ${PROJECT_SOURCE_DIR}/data/daemon/daemon.md5
|
||||
COMMAND cp ${PROJECT_SOURCE_DIR}/ps4-ezremote-server/data/sce_sys/param.sfo ${PROJECT_SOURCE_DIR}/data/daemon/param
|
||||
)
|
||||
@@ -2,6 +2,24 @@
|
||||
|
||||
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB(Windows Share), NFS, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
|
||||
|
||||
**NEW: As of version 2.00, You can download large file in the background.**
|
||||
- You can enable/disable background download in the Global settings
|
||||
- You can set the minimum file size where background download will use. Default is 1GB
|
||||
- In Global Settings, you can show the background download progress of all requested downloads
|
||||
- Does not support rest mode. Background downloads will stop in rest mode, but will be resumed when ezRemote Server is restarted.
|
||||
- If PS4 is restarted, background downloads will resume when ezRemote Server is restarted.
|
||||
- Updated the Web UI, so you can download files of File shares like mediafire, google shared link, pixeldrain, real-debrid and all-debrid or any direct links
|
||||
|
||||
**NEW: As of version 2.00, PS4 pkgs can be installed in the background. Use ezRemote client to connect to remote server and select pkg to install. You can then close ezRemote Client app and the package will continue installing in background. This is archieved with a new payload called [ezRemote Server](https://github.com/cy33hc/ps4-ezremote-server) that is packaged together with exRemote Client. ezRemote Server runs in the background and acts as a proxy to the remote server. ezRemote Server must be started to enable backgroud installs.**
|
||||
- support background install from all remote servers that ezremote client supports
|
||||
- support background install from file host like mediafire, google shared link, pixeldrain, real-debrid and all-debrid
|
||||
- does not support background install using the options "Disk Cache" or PKGs inside zip files
|
||||
- You can pause and resume installs
|
||||
- After restarting PS4, you can resume installs by first reloading ezRemote Server
|
||||
- From testing, background install continues even in rest mode (This isn't granteed). You may need to restart ezRemote Server payload before you can resume install
|
||||
- ezRemote Server payload can be stop/restarted from ezRemote Client settngs dialog.
|
||||
- Do not submit to many background installs, it can crash ezRemote Server.
|
||||
|
||||
**New: As of version 1.19**
|
||||
- Install PKG inside Zip files from both local hdd and remote servers.
|
||||
- Extact zip files directly from remote servers.
|
||||
@@ -81,7 +99,19 @@ To distinguish between FTP, SMB, NFS, WebDAV or HTTP, the URL must be prefix wit
|
||||
```
|
||||
- For Google Drive use the following URL for the server **https://drive.google.com**
|
||||
<br />[Go to the following wiki for instructions on how to setup the app to connect to Google Drive]( https://github.com/cy33hc/ps4-ezremote-client/wiki/Setup-App-for-use-with-Google-Drive)
|
||||
|
||||
|
||||
- For Internet Archive repos download URLs
|
||||
- Only supports parsing of the download URL (ie the URL where you see a list of files). Example
|
||||
| | | |
|
||||
|----------|-----------|---|
|
||||
|  | |  |
|
||||
|
||||
- For Myrient repos, entry **https://myrient.erista.me/files** in the server field.
|
||||

|
||||
|
||||
- Support for browse and download release artifacts from github repos. Under the server just enter the git repo of the homebrew eg https://github.com/cy33hc/ps4-ezremote-client
|
||||

|
||||
|
||||
Tested with following WebDAV server:
|
||||
- **(Recommeded)** [Dufs](https://github.com/sigoden/dufs) - For hosting your own WebDAV server. (Recommended since this allow anonymous access which is required for Remote Package Install)
|
||||
- [SFTPgo](https://github.com/drakkan/sftpgo) - For local hosted WebDAV server. Can also be used as a webdav frontend for Cloud Storage like AWS S3, Azure Blob or Google Storage.
|
||||
@@ -136,6 +166,7 @@ Circle - Un-Select the file list to navigate to other widgets or Close Dialog wi
|
||||
Square - Mark file(s)/folder(s) for Delete/Rename/Upload/Download
|
||||
R1 - Navigate to the Remote list of files
|
||||
L1 - Navigate to the Local list of files
|
||||
L2 - To go up a directory from current directory
|
||||
TouchPad Button - Exit Application (versions prior to 1.06)
|
||||
Options Button - Exit Application (versions 1.06 and above)
|
||||
```
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 115 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
@@ -42,6 +42,7 @@
|
||||
installUrl: '/__local__/install',
|
||||
uploadResumeSizeUrl: '__local__/uploadResumeSize',
|
||||
installUrlUrl: '/__local__/install_url',
|
||||
downloadUrlUrl: '/__local__/download_url',
|
||||
multipleDownloadFileName: 'ezremote-client.zip',
|
||||
isExtractableFilePattern: /\.(7z|rar|zip)$/i,
|
||||
pickCallback: function (item) {
|
||||
@@ -63,4 +64,4 @@
|
||||
<angular-filemanager></angular-filemanager>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -113,7 +113,7 @@ 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_ENABLE_RPI_WEBDAV_MSG=يتيح هذا الخيار تثبيت الحزمة عن بُعد عبر خادم الويب المضمن.
|
||||
STR_FILES=الملفات
|
||||
STR_EDITOR=المحرر
|
||||
STR_SAVE=حفظ
|
||||
|
||||
@@ -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 via embedded Web Server.
|
||||
STR_ENABLE_RPI_WEBDAV_MSG==This option enables Remote Package Installation via embedded Web Server.
|
||||
STR_ENABLE_RPI_FTP_SMB_MSG=This option enables Remote Package Installation via embedded Web Server proxy.
|
||||
STR_ENABLE_RPI_WEBDAV_MSG=This option enables Remote Package Installation via embedded Web Server proxy.
|
||||
STR_FILES=Files
|
||||
STR_EDITOR=Editor
|
||||
STR_SAVE=Save
|
||||
@@ -160,3 +160,7 @@ STR_LANGUAGE=Language
|
||||
STR_TEMP_DIRECTORY=Temp Directory
|
||||
STR_REALDEBRID=Real-Debrid
|
||||
STR_BACKGROUND_INSTALL_INPROGRESS=Package install is running in the background. Don't close the app while install is in progress
|
||||
STR_ENABLE_DISC_CACHE_MSG=Enable disk caching. Can improve Remote Package Install speed in cases where connection to remote is slow, but breaks resuming of install
|
||||
STR_ENABLE_ALLDEBRID_MSG=Install Via AllDebrid
|
||||
STR_ENABLE_REALDEBRID_MSG=Install Via RealDebrid
|
||||
STR_ENABLE_DISKCACHE_DESC=Enable Disk Cache
|
||||
@@ -25,7 +25,7 @@ STR_FILE=파일
|
||||
STR_TYPE=종류
|
||||
STR_NAME=이름
|
||||
STR_SIZE=크기
|
||||
STR_DATE=일시
|
||||
STR_DATE=날짜
|
||||
STR_NEW_FOLDER=새 폴더
|
||||
STR_RENAME=이름 변경
|
||||
STR_DELETE=삭제
|
||||
@@ -39,7 +39,7 @@ STR_OVERWRITE=덮어쓰기
|
||||
STR_DONT_OVERWRITE=덮어쓰기 금지
|
||||
STR_ASK_FOR_CONFIRM=수락여부를 질문
|
||||
STR_DONT_ASK_CONFIRM=수락여부를 묻지 않음
|
||||
STR_ALLWAYS_USE_OPTION=두번다시 묻지 않고 항상 이 설정을 사용
|
||||
STR_ALLWAYS_USE_OPTION=두 번 다시 묻지 않고 항상 이 설정을 사용
|
||||
STR_ACTIONS=실행
|
||||
STR_CONFIRM=확인
|
||||
STR_OVERWRITE_OPTIONS=덮어쓰기 옵션
|
||||
@@ -59,3 +59,75 @@ 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=URL에서 설치
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=패키지 헤더 정보를 읽을 수 없음
|
||||
STR_FAVORITE_URLS=즐겨찾기 URL
|
||||
STR_SLOT=슬롯
|
||||
STR_EDIT=편집
|
||||
STR_ONETIME_URL=한 번만 Url
|
||||
STR_NOT_A_VALID_PACKAGE=유효하지 않은 패키지
|
||||
STR_WAIT_FOR_INSTALL_MSG=패키지 설치가 완료되기를 기다리는 중
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=pkg 파일을 설치하지 못했습니다. tmp pkg를 수동으로 삭제하세요.
|
||||
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=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 공유를 마운트 실패함
|
||||
STR_VIEW_IMAGE=이미지 보기
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
STR_CONNECTION_SETTINGS=Tilkoblingsinnstillinger
|
||||
STR_SITE=Side
|
||||
STR_LOCAL=Lokal
|
||||
STR_REMOTE=Ekstern
|
||||
STR_MESSAGES=Meldinger
|
||||
STR_UPDATE_SOFTWARE=Oppdater programvare
|
||||
STR_CONNECT=Koble til
|
||||
STR_DISCONNECT=Koble fra
|
||||
STR_SEARCH=Søk
|
||||
STR_REFRESH=Oppdater
|
||||
STR_SERVER=Tjener
|
||||
STR_USERNAME=Brukernavn
|
||||
STR_PASSWORD=Passord
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Mappe
|
||||
STR_FILTER=Filter
|
||||
STR_YES=Ja
|
||||
STR_NO=Nei
|
||||
STR_CANCEL=Avbryt
|
||||
STR_CONTINUE=Fortsett
|
||||
STR_CLOSE=Lukk
|
||||
STR_FOLDER=Mappe
|
||||
STR_FILE=Fil
|
||||
STR_TYPE=Type
|
||||
STR_NAME=Navn
|
||||
STR_SIZE=Størrelse
|
||||
STR_DATE=Dato
|
||||
STR_NEW_FOLDER=Ny mappe
|
||||
STR_RENAME=Gi nytt navn
|
||||
STR_DELETE=Slett
|
||||
STR_UPLOAD=Last opp
|
||||
STR_DOWNLOAD=Last ned
|
||||
STR_SELECT_ALL=Marker alle
|
||||
STR_CLEAR_ALL=Fjern alle
|
||||
STR_UPLOADING=Laster opp
|
||||
STR_DOWNLOADING=Laster ned
|
||||
STR_OVERWRITE=Skriv over
|
||||
STR_DONT_OVERWRITE=Ikke skriv over
|
||||
STR_ASK_FOR_CONFIRM=Spør om bekreftelse
|
||||
STR_DONT_ASK_CONFIRM=Ikke spør om bekreftelse
|
||||
STR_ALLWAYS_USE_OPTION=Bruk alltid dette valget og ikke spør igjen
|
||||
STR_ACTIONS=Handlinger
|
||||
STR_CONFIRM=Bekreft
|
||||
STR_OVERWRITE_OPTIONS=Overskriv innstillinger
|
||||
STR_PROPERTIES=Egenskaper
|
||||
STR_PROGRESS=Framdrift
|
||||
STR_UPDATES=Oppdateringer
|
||||
STR_DEL_CONFIRM_MSG=Er du sikker på at du vil slette filen(e)/mappen(e)?
|
||||
STR_CANCEL_ACTION_MSG=Avbryter. Venter på at siste handling skal fullføres
|
||||
STR_FAIL_UPLOAD_MSG=Opplasting av fil mislykkes
|
||||
STR_FAIL_DOWNLOAD_MSG=Nedlasting av fil mislykkes
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Lesing av mappe mislykkes, eller mappen finnes ikke.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Tilkobling Lukket.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Ekstern Tjener har lukket tilkoblingen.
|
||||
STR_FAIL_LOGIN_MSG=300 Innlogging Mislykkes. Vennligst sjekk ditt brukernavn og passord.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Mislykkes. Tilkoblingen timet ut.
|
||||
STR_FAIL_DEL_DIR_MSG=Sletting av mappe mislykkes
|
||||
STR_DELETING=Sletter
|
||||
STR_FAIL_DEL_FILE_MSG=Sletting av fil mislykkes
|
||||
STR_DELETED=Slettet
|
||||
STR_LINK=Lenke
|
||||
STR_SHARE=Del
|
||||
STR_FAILED=310 Mislykket
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Oppretting av lokal fil mislykkes
|
||||
STR_INSTALL=Installér
|
||||
STR_INSTALLING=Installerer
|
||||
STR_INSTALL_SUCCESS=Vellykket
|
||||
STR_INSTALL_FAILED=Mislykket
|
||||
STR_INSTALL_SKIPPED=Hoppet over
|
||||
STR_CHECK_HTTP_MSG=Sjekker tilkobling til ekstern HTTP-tjener
|
||||
STR_FAILED_HTTP_CHECK=Mislykket tilkobling til HTTP-tjener
|
||||
STR_REMOTE_NOT_HTTP=Ekstern tjener er ikke en HTTP-tjener
|
||||
STR_INSTALL_FROM_DATA_MSG=Pakke finnes ikke i mappene /data eller /mnt/usbX
|
||||
STR_ALREADY_INSTALLED_MSG=Pakken er allerede installert
|
||||
STR_INSTALL_FROM_URL=Installer fra URL
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=Kunne ikke lese pakkens header
|
||||
STR_FAVORITE_URLS=Favoritt-URLer
|
||||
STR_SLOT=Spor
|
||||
STR_EDIT=Redigér
|
||||
STR_ONETIME_URL=Engangs-URL
|
||||
STR_NOT_A_VALID_PACKAGE=Ikke en gyldig pakke
|
||||
STR_WAIT_FOR_INSTALL_MSG=Venter på at pakke skal bli ferdig å installere
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=Installasjon av PKG-fil mislykkes. Vennligst slett den midlertidlige PKG-filen manuelt
|
||||
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Kunne ikke hente nedlastings-URL
|
||||
STR_AUTO_DELETE_TMP_PKG=Automatisk slett midlertidig nedlastet PKG-fil etter installasjon
|
||||
STR_PROTOCOL_NOT_SUPPORTED=Protokollen er ikke støttet
|
||||
STR_COULD_NOT_RESOLVE_HOST=Kunne ikke koble til tjenernavnet
|
||||
STR_EXTRACT=Pakk ut
|
||||
STR_EXTRACTING=Pakker ut
|
||||
STR_FAILED_TO_EXTRACT=Utpakking mislykkes
|
||||
STR_EXTRACT_LOCATION=Utpakkingsbane
|
||||
STR_COMPRESS=Komprimér
|
||||
STR_ZIP_FILE_PATH=ZIP-filnavn
|
||||
STR_COMPRESSING=Komprimerer
|
||||
STR_ERROR_CREATE_ZIP=Oppretting av ZIP mislykket
|
||||
STR_UNSUPPORTED_FILE_FORMAT=Arkivformatet er ikke støttet
|
||||
STR_CUT=Klipp ut
|
||||
STR_COPY=Kopiér
|
||||
STR_PASTE=Lim inn
|
||||
STR_MOVING=Flytter
|
||||
STR_COPYING=Kopierer
|
||||
STR_FAIL_MOVE_MSG=Flytting av fil mislykkes
|
||||
STR_FAIL_COPY_MSG=Kopiering av fil mislykkes
|
||||
STR_CANT_MOVE_TO_SUBDIR_MSG=Kan ikke flytte overordnet mappe til undermappe
|
||||
STR_CANT_COPY_TO_SUBDIR_MSG=Kan ikke kopiere overordnet mappe til undermappe
|
||||
STR_UNSUPPORTED_OPERATION_MSG=Handling ikke støttet
|
||||
STR_HTTP_PORT=HTTP-port
|
||||
STR_REINSTALL_CONFIRM_MSG=Innholdet er allerede installert. Vil du fortsette installasjonen
|
||||
STR_REMOTE_NOT_SUPPORT_MSG=Fjerninstallasjon av pakker er ikke støttet for beskyttede tjenere.
|
||||
STR_CANNOT_CONNECT_REMOTE_MSG=Ekstern HTTP-tjener kan ikke nås.
|
||||
STR_DOWNLOAD_INSTALL_MSG=Fjerninstallasjon er ikke mulig. Vil du laste ned pakken og installere den istedet?
|
||||
STR_CHECKING_REMOTE_SERVER_MSG=Sjekker tjener for fjerninstallasjon av pakke.
|
||||
STR_ENABLE_RPI=FIP
|
||||
STR_ENABLE_RPI_FTP_SMB_MSG=Dette valget skrur på fjerninstallasjon av pakke via innebygd Web-tjenerproxy.
|
||||
STR_ENABLE_RPI_WEBDAV_MSG=Dette valget skrur på fjerninstallasjon av pakke via innebygd Web-tjenerproxy.
|
||||
STR_FILES=Filer
|
||||
STR_EDITOR=Redigeringsprogram
|
||||
STR_SAVE=Lagre
|
||||
STR_MAX_EDIT_FILE_SIZE_MSG=Kan ikke redigere filer større enn
|
||||
STR_DELETE_LINE=Slett markert linje
|
||||
STR_INSERT_LINE=Sett inn under markert linje
|
||||
STR_MODIFIED=Endret
|
||||
STR_FAIL_GET_TOKEN_MSG=Kunne ikke hente en tilgangstoken fra
|
||||
STR_GET_TOKEN_SUCCESS_MSG=Innlogging vellykket. Du kan lukke nettleseren og gå tilbake til applikasjonen
|
||||
STR_PERM_DRIVE=Se, endre, opprette og slette dine Google Drive-filer
|
||||
STR_PERM_DRIVE_APPDATA=Se, opprette og slette dens egen konfigurasjonsdata i din Google Drive
|
||||
STR_PERM_DRIVE_FILE=Se, endre, opprette og slette kun de spesifikke Google Drive-filene du bruker med denne appen
|
||||
STR_PERM_DRIVE_METADATA=Vise og behandle metadataen til filer i din Google Drive
|
||||
STR_PERM_DRIVE_METADATA_RO=Se informasjon om dine Google Drive-filer
|
||||
STR_GOOGLE_LOGIN_FAIL_MSG=Google-innlogging mislykkes
|
||||
STR_GOOGLE_LOGIN_TIMEOUT_MSG=Google-innlogging timet ut
|
||||
STR_NEW_FILE=Ny Fil
|
||||
STR_SETTINGS=Innstillinger
|
||||
STR_CLIENT_ID=Klient-ID
|
||||
STR_CLIENT_SECRET=Klienthemmelighet (Client Secret)
|
||||
STR_GLOBAL=Global
|
||||
STR_GOOGLE=Google
|
||||
STR_COPY_LINE=Kopier markert linje
|
||||
STR_PASTE_LINE=Lim inn i markert linje
|
||||
STR_SHOW_HIDDEN_FILES=Vis skjulte filer
|
||||
STR_SET_DEFAULT_DIRECTORY=Sett oppstartsmappe
|
||||
STR_SET_DEFAULT_DIRECTORY_MSG=har blitt satt som oppstartsmappe
|
||||
STR_VIEW_IMAGE=Vis bilde
|
||||
STR_VIEW_PKG_INFO=Pakkeinformasjon
|
||||
STR_NFS_EXP_PATH_MISSING_MSG=NFS-eksportbane mangler fra URL
|
||||
STR_FAIL_INIT_NFS_CONTEXT=Initialisering av NFS-kontekst mislykkes
|
||||
STR_FAIL_MOUNT_NFS_MSG=Montering av NFS-share mislykkes
|
||||
STR_WEB_SERVER=Web-tjener
|
||||
STR_ENABLE=Skru på
|
||||
STR_COMPRESSED_FILE_PATH=Lokasjon for komprimerte filer
|
||||
STR_COMPRESSED_FILE_PATH_MSG=Lokasjon for komprimerte filer på Web-tjener
|
||||
STR_ALLDEBRID=AllDebrid
|
||||
STR_API_KEY=API-nøkkel
|
||||
STR_CANT_EXTRACT_URL_MSG=Kunne ikke utvinne nedlastings-URL
|
||||
STR_FAIL_INSTALL_FROM_URL_MSG=Installasjon fra URL mislykkes
|
||||
STR_INVALID_URL=Ugyldig URL
|
||||
STR_ALLDEBRID_API_KEY_MISSING_MSG=For å bruke denne funksjonen, må du konfigurere en API-nøkkel i instillingene for ezRemote Client.
|
||||
STR_LANGUAGE=Språk
|
||||
STR_TEMP_DIRECTORY=Midlertidig mappe
|
||||
STR_REALDEBRID=Real-Debrid
|
||||
STR_BACKGROUND_INSTALL_INPROGRESS=Pakkeinstallasjon kjører i bakrunnen. Ikke lykk denne appen mens installasjonen pågår
|
||||
STR_ENABLE_DISC_CACHE_MSG=Skru på disk-caching. Kan gjøre fjerninstallasjon av pakker kjappere når tilkoblingen er treg, men lar deg ikke fortsette en avbrutt installasjon
|
||||
STR_ENABLE_ALLDEBRID_MSG=Installér via AllDebrid
|
||||
STR_ENABLE_REALDEBRID_MSG=Installér via RealDebrid
|
||||
STR_ENABLE_DISKCACHE_DESC=Skru på disk-cache
|
||||
@@ -1,8 +1,8 @@
|
||||
STR_CONNECTION_SETTINGS=连接设置
|
||||
STR_SITE=地点
|
||||
STR_LOCAL=当地的
|
||||
STR_REMOTE=偏僻的
|
||||
STR_MESSAGES=留言
|
||||
STR_SITE=站点
|
||||
STR_LOCAL=本地
|
||||
STR_REMOTE=远程路径
|
||||
STR_MESSAGES=信息
|
||||
STR_UPDATE_SOFTWARE=更新软件
|
||||
STR_CONNECT=连接
|
||||
STR_DISCONNECT=断开
|
||||
@@ -11,51 +11,123 @@ STR_REFRESH=刷新
|
||||
STR_SERVER=服务器
|
||||
STR_USERNAME=用户名
|
||||
STR_PASSWORD=密码
|
||||
STR_PORT=港口
|
||||
STR_PASV=帕夫
|
||||
STR_PORT=端口
|
||||
STR_PASV=被动模式
|
||||
STR_DIRECTORY=目录
|
||||
STR_FILTER=筛选
|
||||
STR_YES=是的
|
||||
STR_NO=不
|
||||
STR_FILTER=过滤器
|
||||
STR_YES=是
|
||||
STR_NO=否
|
||||
STR_CANCEL=取消
|
||||
STR_CONTINUE=继续
|
||||
STR_CLOSE=关闭
|
||||
STR_FOLDER=文件夹
|
||||
STR_FILE=文件
|
||||
STR_TYPE=类型
|
||||
STR_NAME=姓名
|
||||
STR_SIZE=尺寸
|
||||
STR_NAME=名称
|
||||
STR_SIZE=大小
|
||||
STR_DATE=日期
|
||||
STR_NEW_FOLDER=新建文件夹
|
||||
STR_RENAME=改名
|
||||
STR_RENAME=重命名
|
||||
STR_DELETE=删除
|
||||
STR_UPLOAD=上传
|
||||
STR_DOWNLOAD=下载
|
||||
STR_SELECT_ALL=全选
|
||||
STR_CLEAR_ALL=全部清除
|
||||
STR_UPLOADING=上传
|
||||
STR_DOWNLOADING=下载
|
||||
STR_CLEAR_ALL=取消全选
|
||||
STR_UPLOADING=上传中
|
||||
STR_DOWNLOADING=下载中
|
||||
STR_OVERWRITE=覆盖
|
||||
STR_DONT_OVERWRITE=不要覆盖
|
||||
STR_ASK_FOR_CONFIRM=要求确认
|
||||
STR_DONT_ASK_CONFIRM=不要要求确认
|
||||
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_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=426 连接已关闭。
|
||||
STR_REMOTE_TERM_CONN_MSG=426 远程服务器已终止连接。
|
||||
STR_FAIL_LOGIN_MSG=300 登录失败。 请检查您的用户名或密码。
|
||||
STR_FAIL_TIMEOUT_MSG=426 失败。 连接超时。
|
||||
STR_FAIL_LOGIN_MSG=300 登录失败。请检查您的用户名或密码。
|
||||
STR_FAIL_TIMEOUT_MSG=426 失败。连接超时。
|
||||
STR_FAIL_DEL_DIR_MSG=删除目录失败
|
||||
STR_DELETING=删除
|
||||
STR_DELETING=删除中
|
||||
STR_FAIL_DEL_FILE_MSG=删除文件失败
|
||||
STR_DELETED=已删除
|
||||
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=未能安装pkg文件。请手动删除tmp pkg
|
||||
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=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 共享失败
|
||||
STR_VIEW_IMAGE=查看图片
|
||||
@@ -1,75 +1,133 @@
|
||||
STR_CONNECTION_SETTINGS=Bağlantı Ayarları
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Yerel
|
||||
STR_REMOTE=Uzaktan
|
||||
STR_REMOTE=Uzak
|
||||
STR_MESSAGES=Mesajlar
|
||||
STR_UPDATE_SOFTWARE=Yazılımı Güncelle
|
||||
STR_CONNECT=Bağlan
|
||||
STR_DISCONNECT=Bağlantıyı kes
|
||||
STR_SEARCH=Ara
|
||||
STR_DISCONNECT=Bağlantıyı Kes
|
||||
STR_SEARCH=Arama
|
||||
STR_REFRESH=Yenile
|
||||
STR_SERVER=Sunucu
|
||||
STR_USERNAME=Kullanıcı Adı
|
||||
STR_PASSWORD=Şifre
|
||||
STR_PASSWORD=Parola
|
||||
STR_PORT=Port
|
||||
STR_PASV=Pasv
|
||||
STR_PASV=Pasif
|
||||
STR_DIRECTORY=Dizin
|
||||
STR_FILTER=Filtre
|
||||
STR_YES=Evet
|
||||
STR_NO=Hayır
|
||||
STR_CANCEL=İptal
|
||||
STR_CONTINUE=Devam
|
||||
STR_CONTINUE=Devam Et
|
||||
STR_CLOSE=Kapat
|
||||
STR_FOLDER=Klasör
|
||||
STR_FILE=Dosya
|
||||
STR_TYPE=Tip
|
||||
STR_TYPE=Tür
|
||||
STR_NAME=Ad
|
||||
STR_SIZE=Boyut
|
||||
STR_DATE=Tarih
|
||||
STR_NEW_FOLDER=Yeni Klasör
|
||||
STR_RENAME=Yeniden Adlandır
|
||||
STR_DELETE=Sil
|
||||
STR_UPLOAD=Karşıya Yükle
|
||||
STR_UPLOAD=Yükle
|
||||
STR_DOWNLOAD=İndir
|
||||
STR_SELECT_ALL=Tümünü Seç
|
||||
STR_CLEAR_ALL=Tümünü Temizle
|
||||
STR_UPLOADING=Karşıya Yükleniyor
|
||||
STR_SELECT_ALL=Hepsini Seç
|
||||
STR_CLEAR_ALL=Hepsini Temizle
|
||||
STR_UPLOADING=Yükleniyor
|
||||
STR_DOWNLOADING=İndiriliyor
|
||||
STR_OVERWRITE=Üzerine yaz
|
||||
STR_DONT_OVERWRITE=Üzerine yazma
|
||||
STR_ASK_FOR_CONFIRM=Onaylamak için sor
|
||||
STR_DONT_ASK_CONFIRM=Onaylamak için sorma
|
||||
STR_ALLWAYS_USE_OPTION=Daima bu seçeneği kullan ve bir daha sorma
|
||||
STR_ACTIONS=Eylemler
|
||||
STR_OVERWRITE=Üzerine Yaz
|
||||
STR_DONT_OVERWRITE=Üzerine Yazma
|
||||
STR_ASK_FOR_CONFIRM=Onay İste
|
||||
STR_DONT_ASK_CONFIRM=Onay İsteme
|
||||
STR_ALLWAYS_USE_OPTION=Bu seçeneği her zaman kullan ve bir daha sorma
|
||||
STR_ACTIONS=İşlemler
|
||||
STR_CONFIRM=Onayla
|
||||
STR_OVERWRITE_OPTIONS=Ayarların üzerine yaz
|
||||
STR_OVERWRITE_OPTIONS=Üzerine Yazma Seçenekleri
|
||||
STR_PROPERTIES=Özellikler
|
||||
STR_PROGRESS=Durum
|
||||
STR_PROGRESS=İlerleme
|
||||
STR_UPDATES=Güncellemeler
|
||||
STR_DEL_CONFIRM_MSG=Bu dosya(ları)/klasör(leri) silmek istediğinizden emin misiniz?
|
||||
STR_CANCEL_ACTION_MSG=İptal ediliyor. Son işlemin tamamlanması bekleniyor
|
||||
STR_FAIL_UPLOAD_MSG=Dosya karşıya yükleme başarısız
|
||||
STR_FAIL_DOWNLOAD_MSG=Dosya indirme başarısız
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Dizindeki içerikler okunamadı ya da öyle bir klasör yok
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Bağlantı kesildi.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Uzaktan Sunucu bağlantıyı kesti.
|
||||
STR_FAIL_LOGIN_MSG=300 Giriş başarısız. Lütfen kullanıcı adınızı ve şifrenizi kontrol edin.
|
||||
STR_CANCEL_ACTION_MSG=İptal ediliyor. Son eylemin tamamlanması bekleniyor
|
||||
STR_FAIL_UPLOAD_MSG=Dosya yüklenemedi
|
||||
STR_FAIL_DOWNLOAD_MSG=Dosya indirilemedi
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Yerel dizinin içeriği okunamadı veya klasör mevcut değil.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Bağlantı kapatıldı.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Uzak Sunucu bağlantıyı sonlandırdı.
|
||||
STR_FAIL_LOGIN_MSG=300 Giriş Başarısız. Lütfen kullanıcı adınızı veya şifrenizi kontrol edin.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Başarısız. Bağlantı zaman aşımına uğradı.
|
||||
STR_FAIL_DEL_DIR_MSG=Dizin silme başarısız
|
||||
STR_FAIL_DEL_DIR_MSG=Dizin silinemedi
|
||||
STR_DELETING=Siliniyor
|
||||
STR_FAIL_DEL_FILE_MSG=Dosya silme başarısız
|
||||
STR_FAIL_DEL_FILE_MSG=Dosya silinemedi
|
||||
STR_DELETED=Silindi
|
||||
STR_LINK=Link
|
||||
STR_LINK=Bağlantı
|
||||
STR_SHARE=Paylaş
|
||||
STR_FAILED=310 Başarısız
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Yerelde dosya oluşturulumu başarısız
|
||||
STR_INSTALL=Yükle
|
||||
STR_INSTALLING=Yükleniyor
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Yerelde dosya oluşturulamadı
|
||||
STR_INSTALL=Kur
|
||||
STR_INSTALLING=Kuruluyor
|
||||
STR_INSTALL_SUCCESS=Başarılı
|
||||
STR_INSTALL_FAILED=Başarısız
|
||||
STR_INSTALL_SKIPPED=Atlandı
|
||||
STR_CHECK_HTTP_MSG=Uzaktan HTTP Sunucusu bağlantısı kontrol ediliyor
|
||||
STR_FAILED_HTTP_CHECK=HTTP Sunucusuna bağlantı başarısız
|
||||
STR_REMOTE_NOT_HTTP=Uzaktaki HTTP Sunucusu değil
|
||||
STR_INSTALL_FROM_DATA_MSG=Paket /data ya da /mnt/usbX dizininde değil
|
||||
STR_CHECK_HTTP_MSG=Uzak HTTP Sunucusuna bağlantı kontrol ediliyor
|
||||
STR_FAILED_HTTP_CHECK=HTTP Sunucusuna bağlanılamadı
|
||||
STR_REMOTE_NOT_HTTP=Uzak bir HTTP Sunucusu değil
|
||||
STR_INSTALL_FROM_DATA_MSG=Paket /data veya /mnt/usbX klasöründe değil
|
||||
STR_ALREADY_INSTALLED_MSG=Paket zaten kurulu
|
||||
STR_INSTALL_FROM_URL=URL'den Kur
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=Paket başlık bilgisi okunamadı
|
||||
STR_FAVORITE_URLS=Favori URL'ler
|
||||
STR_SLOT=Yuva
|
||||
STR_EDIT=Düzenle
|
||||
STR_ONETIME_URL=Tek Seferlik URL
|
||||
STR_NOT_A_VALID_PACKAGE=Geçerli bir Paket değil
|
||||
STR_WAIT_FOR_INSTALL_MSG=Paketin kurulmasının tamamlanması bekleniyor
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=Geçici paketin kurulumu başarısız. Lütfen geçici paketi manuel olarak silin
|
||||
STR_AUTO_DELETE_TMP_PKG=Kurulumdan sonra geçici indirilen paketi otomatik olarak sil
|
||||
STR_PROTOCOL_NOT_SUPPORTED=Protokol desteklenmiyor
|
||||
STR_COULD_NOT_RESOLVE_HOST=Ana bilgisayar adı çözülemedi
|
||||
STR_EXTRACT=Çıkart
|
||||
STR_EXTRACTING=Çıkartılıyor
|
||||
STR_FAILED_TO_EXTRACT=Çıkartma başarısız oldu
|
||||
STR_EXTRACT_LOCATION=Çıkartılacak Konum
|
||||
STR_COMPRESS=Sıkıştır
|
||||
STR_ZIP_FILE_PATH=Zip Dosya Adı
|
||||
STR_COMPRESSING=Sıkıştırılıyor
|
||||
STR_ERROR_CREATE_ZIP=Zip oluşturulurken hata oluştu
|
||||
STR_UNSUPPORTED_FILE_FORMAT=Desteklenmeyen sıkıştırılmış dosya formatı
|
||||
STR_CUT=Kes
|
||||
STR_COPY=Kopyala
|
||||
STR_PASTE=Yapıştır
|
||||
STR_MOVING=Taşınıyor
|
||||
STR_COPYING=Kopyalanıyor
|
||||
STR_FAIL_MOVE_MSG=Dosya taşınamadı
|
||||
STR_FAIL_COPY_MSG=Dosya kopyalanamadı
|
||||
STR_CANT_MOVE_TO_SUBDIR_MSG=Ana dizin alt dizinine taşınamaz
|
||||
STR_CANT_COPY_TO_SUBDIR_MSG=Ana dizin alt dizinine kopyalanamaz
|
||||
STR_UNSUPPORTED_OPERATION_MSG=Desteklenmeyen işlem
|
||||
STR_HTTP_PORT=Http Portu
|
||||
STR_REINSTALL_CONFIRM_MSG=İçerik zaten kurulu. Kuruluma devam etmek istiyor musunuz?
|
||||
STR_REMOTE_NOT_SUPPORT_MSG=Korunan sunucular için uzak paket kurulumu desteklenmiyor.
|
||||
STR_CANNOT_CONNECT_REMOTE_MSG=Uzak HTTP Sunucusuna bağlanılamıyor.
|
||||
STR_DOWNLOAD_INSTALL_MSG=Uzak Paket Kurulumu mümkün değil. Paketi indirip kurmak ister misiniz?
|
||||
STR_CHECKING_REMOTE_SERVER_MSG=Uzak Paket Kurulumu için uzak sunucu kontrol ediliyor.
|
||||
STR_FILES=Dosyalar
|
||||
STR_EDITOR=Düzenleyici
|
||||
STR_SAVE=Kaydet
|
||||
STR_MAX_EDIT_FILE_SIZE_MSG=Boyutu şu büyüklükten büyük dosyalar düzenlenemez
|
||||
STR_DELETE_LINE=Seçili Satırı Sil
|
||||
STR_INSERT_LINE=Seçili Satırın Altına Ekle
|
||||
STR_MODIFIED=Değiştirildi
|
||||
STR_FAIL_GET_TOKEN_MSG=Erişim token'ı alınamadı
|
||||
STR_GET_TOKEN_SUCCESS_MSG=Giriş Başarılı. Tarayıcıyı kapatıp uygulamaya dönebilirsiniz
|
||||
STR_NEW_FILE=Yeni Dosya
|
||||
STR_SETTINGS=Ayarlar
|
||||
STR_GLOBAL=Genel
|
||||
STR_COPY_LINE=Seçili satırı kopyala
|
||||
STR_PASTE_LINE=Seçili satıra yapıştır
|
||||
STR_SHOW_HIDDEN_FILES=Gizli dosyaları göster
|
||||
STR_SET_DEFAULT_DIRECTORY=Varsayılan Klasörü Ayarla
|
||||
STR_SET_DEFAULT_DIRECTORY_MSG=varsayılan dizin olarak ayarlandı
|
||||
STR_NFS_EXP_PATH_MISSING_MSG=URL'de NFS dışa aktarma yolu eksik
|
||||
STR_FAIL_INIT_NFS_CONTEXT=NFS bağlamı başlatılamadı
|
||||
STR_FAIL_MOUNT_NFS_MSG=NFS paylaşımı bağlanamadı
|
||||
STR_VIEW_IMAGE=Görüntüyü Görüntüle
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
STR_CONNECTION_SETTINGS=Cài đặt kết nối
|
||||
STR_SITE=Vị trí
|
||||
STR_LOCAL=Thiết bị
|
||||
STR_REMOTE=Máy đích
|
||||
STR_MESSAGES=Tin nhắn
|
||||
STR_UPDATE_SOFTWARE=Cập nhật phần mềm
|
||||
STR_CONNECT=Kết nối
|
||||
STR_DISCONNECT=Ngắt kết nối
|
||||
STR_SEARCH=Tìm kiếm
|
||||
STR_REFRESH=Làm mới
|
||||
STR_SERVER=Máy chủ
|
||||
STR_USERNAME=Tên đăng nhập
|
||||
STR_PASSWORD=Mật khẩu
|
||||
STR_PORT=Cổng
|
||||
STR_PASV=Pasv
|
||||
STR_DIRECTORY=Thư mục
|
||||
STR_FILTER=Bộ lọc
|
||||
STR_YES=Đồng ý
|
||||
STR_NO=Không
|
||||
STR_CANCEL=Hủy bỏ
|
||||
STR_CONTINUE=Tiếp tục
|
||||
STR_CLOSE=Đóng
|
||||
STR_FOLDER=Thư mục
|
||||
STR_FILE=Tập tin
|
||||
STR_TYPE=Loại
|
||||
STR_NAME=Tên
|
||||
STR_SIZE=Kích thước
|
||||
STR_DATE=Ngày tháng
|
||||
STR_NEW_FOLDER=Thư mục mới
|
||||
STR_RENAME=Đổi tên
|
||||
STR_DELETE=Xóa
|
||||
STR_UPLOAD=Tải lên
|
||||
STR_DOWNLOAD=Tải xuống
|
||||
STR_SELECT_ALL=Chọn tất cả
|
||||
STR_CLEAR_ALL=Bỏ chọn tất cả
|
||||
STR_UPLOADING=Đang tải lên
|
||||
STR_DOWNLOADING=Đang tải xuống
|
||||
STR_OVERWRITE=Ghi đè
|
||||
STR_DONT_OVERWRITE=Không ghi đè
|
||||
STR_ASK_FOR_CONFIRM=Hỏi xác nhận
|
||||
STR_DONT_ASK_CONFIRM=Không hỏi xác nhận
|
||||
STR_ALLWAYS_USE_OPTION=Luôn dùng tùy chọn này và không hỏi lại
|
||||
STR_ACTIONS=Hành động
|
||||
STR_CONFIRM=Xác nhận
|
||||
STR_OVERWRITE_OPTIONS=Tùy chọn ghi đè
|
||||
STR_PROPERTIES=Thuộc tính
|
||||
STR_PROGRESS=Tiến trình
|
||||
STR_UPDATES=Cập nhật
|
||||
STR_DEL_CONFIRM_MSG=Bạn có chắc chắn muốn xóa (những) tập tin / thư mục này không?
|
||||
STR_CANCEL_ACTION_MSG=Hủy bỏ. Chờ hành động cuối cùng hoàn tất.Canceling.
|
||||
STR_FAIL_UPLOAD_MSG=Không thể tải file lên
|
||||
STR_FAIL_DOWNLOAD_MSG=Không thể tải file
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Không đọc được nội dung của thư mục hoặc thư mục không tồn tại.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Kết nối đã đóng.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 Máy chủ đã ngắt kết nối.
|
||||
STR_FAIL_LOGIN_MSG=300 Đăng nhập thất bại. Vui lòng kiểm tra lại tên đăng nhập hoặc mật khẩu.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Thất bại. Quá thời gian kết nối.
|
||||
STR_FAIL_DEL_DIR_MSG=Không thể xóa thư mục
|
||||
STR_DELETING=Đang xóa
|
||||
STR_FAIL_DEL_FILE_MSG=Không thể xóa tập tin
|
||||
STR_DELETED=Đã xóa
|
||||
STR_LINK=Liên kết
|
||||
STR_SHARE=Chia sẻ
|
||||
STR_FAILED=310 Lỗi
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Không thể tạo file trên máy này
|
||||
STR_INSTALL=Cài đặt
|
||||
STR_INSTALLING=Đang cài đặt
|
||||
STR_INSTALL_SUCCESS=Thành công
|
||||
STR_INSTALL_FAILED=Thất bại
|
||||
STR_INSTALL_SKIPPED=Bỏ qua
|
||||
STR_CHECK_HTTP_MSG=Đang kiểm tra kết nối tới máy chủ HTTP
|
||||
STR_FAILED_HTTP_CHECK=Không thể kết nối tới máy chủ HTTP
|
||||
STR_REMOTE_NOT_HTTP=Máy đích không phải máy chủ HTTP
|
||||
STR_INSTALL_FROM_DATA_MSG=Package không có trong thư mục /data hoặc /mnt/usbX
|
||||
STR_ALREADY_INSTALLED_MSG=Package đã được cài đặt
|
||||
STR_INSTALL_FROM_URL=Cài từ địa chỉ URL
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=Không thể đọc được thông tin header của package
|
||||
STR_FAVORITE_URLS=URLs yêu thích
|
||||
STR_SLOT=Vị trí
|
||||
STR_EDIT=Sửa
|
||||
STR_ONETIME_URL=Url một lần
|
||||
STR_NOT_A_VALID_PACKAGE=Package không đúng
|
||||
STR_WAIT_FOR_INSTALL_MSG=Đợi Package kết thúc cài đặt
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=Không thể cài file pkg. Vui lòng xóa tmp pkg thủ công
|
||||
STR_AUTO_DELETE_TMP_PKG=Tự động xóa file pkg được tải về tạm thời sau khi cài xong
|
||||
STR_PROTOCOL_NOT_SUPPORTED=Protocol không được hỗ trợ
|
||||
STR_COULD_NOT_RESOLVE_HOST=Không thể phân giải tên máy chủ
|
||||
STR_EXTRACT=Giải nén
|
||||
STR_EXTRACTING=Đang giải nén
|
||||
STR_FAILED_TO_EXTRACT=Giải nén thất bại
|
||||
STR_EXTRACT_LOCATION=Vị trí giải nén
|
||||
STR_COMPRESS=Nén
|
||||
STR_ZIP_FILE_PATH=Tên file Zip
|
||||
STR_COMPRESSING=Đang nén
|
||||
STR_ERROR_CREATE_ZIP=Lỗi khi tạo file zip
|
||||
STR_UNSUPPORTED_FILE_FORMAT=Phần mở rộng file không được hỗ trợ
|
||||
STR_CUT=Cắt
|
||||
STR_COPY=Sao chép
|
||||
STR_PASTE=Dán
|
||||
STR_MOVING=Đang di chuyển
|
||||
STR_COPYING=Đang copy
|
||||
STR_FAIL_MOVE_MSG=Không thể di chuyển file
|
||||
STR_FAIL_COPY_MSG=Không thể sao chép file
|
||||
STR_CANT_MOVE_TO_SUBDIR_MSG=Không thể di chuyển thư mục cha vào bên trong thư mục con
|
||||
STR_CANT_COPY_TO_SUBDIR_MSG=Không thể sao chép thư mục cha vào bên trong thư mục con
|
||||
STR_UNSUPPORTED_OPERATION_MSG=Hành động không được hỗ trợ
|
||||
STR_HTTP_PORT=Cổng Http
|
||||
STR_REINSTALL_CONFIRM_MSG=Nội dung đã được cài đặt. Bạn có muốn tiếp tục cài đặt không?
|
||||
STR_REMOTE_NOT_SUPPORT_MSG=Cài đặt gói từ xa không được hỗ trợ cho các máy chủ được bảo vệ.
|
||||
STR_CANNOT_CONNECT_REMOTE_MSG=Máy chủ HTTP đích không thể truy cập được.
|
||||
STR_DOWNLOAD_INSTALL_MSG=Không thể cài đặt package từ xa. Bạn có muốn tải package xuống và cài đặt không?
|
||||
STR_CHECKING_REMOTE_SERVER_MSG=Đang kiểm tra máy chủ đích để cài đặt package từ xa.
|
||||
STR_FILES=Tập tin
|
||||
STR_EDITOR=Trình soạn thảo
|
||||
STR_SAVE=Lưu
|
||||
STR_MAX_EDIT_FILE_SIZE_MSG=Không thể chỉnh sửa các tập tin lớn hơn
|
||||
STR_DELETE_LINE=Xóa dòng đã chọn
|
||||
STR_INSERT_LINE=Chèn bên dưới dòng đã chọn
|
||||
STR_MODIFIED=Đã sửa đổi
|
||||
STR_FAIL_GET_TOKEN_MSG=Không thể lấy được access token từ
|
||||
STR_GET_TOKEN_SUCCESS_MSG=Đăng nhập thành công. Bạn có thể đóng trình duyệt và quay lại ứng dụng
|
||||
STR_NEW_FILE=Tập tin mới
|
||||
STR_SETTINGS=Cài đặt
|
||||
STR_GLOBAL=Toàn cục
|
||||
STR_COPY_LINE=Sao chép dòng đã chọn
|
||||
STR_PASTE_LINE=Dán vào dòng đã chọn
|
||||
STR_SHOW_HIDDEN_FILES=Hiển thị các tập tin ẩn
|
||||
STR_SET_DEFAULT_DIRECTORY=Đặt thư mục mặc định
|
||||
STR_SET_DEFAULT_DIRECTORY_MSG=đã được thiết lập làm thư mục mặc định
|
||||
STR_NFS_EXP_PATH_MISSING_MSG=Đường dẫn NFS bị thiếu trong URL
|
||||
STR_FAIL_INIT_NFS_CONTEXT=Không khởi tạo được ngữ cảnh NFS
|
||||
STR_FAIL_MOUNT_NFS_MSG=Không thể mount NFS share
|
||||
STR_PROMOTING=Promoting
|
||||
+1
-1
File diff suppressed because one or more lines are too long
BIN
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
Submodule
+1
Submodule ps4-ezremote-server added at 7644256a3c
+245
-50
@@ -1,6 +1,7 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <json-c/json.h>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <minizip/unzip.h>
|
||||
@@ -10,6 +11,9 @@
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/apache.h"
|
||||
#include "clients/archiveorg.h"
|
||||
#include "clients/github.h"
|
||||
#include "clients/myrient.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/nfsclient.h"
|
||||
@@ -17,6 +21,7 @@
|
||||
#include "clients/rclone.h"
|
||||
#include "clients/sftpclient.h"
|
||||
#include "filehost/filehost.h"
|
||||
#include "server/http_server.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "config.h"
|
||||
@@ -364,6 +369,7 @@ namespace Actions
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
return remoteclient->Put(src, dest);
|
||||
}
|
||||
|
||||
@@ -409,6 +415,7 @@ namespace Actions
|
||||
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_UPLOADING], entries[i].path);
|
||||
bytes_to_download = entries[i].file_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
ret = UploadFile(entries[i].path, new_path);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -483,9 +490,47 @@ namespace Actions
|
||||
}
|
||||
}
|
||||
|
||||
int BackgroundDownload(const char *src, const char *dest, uint64_t file_size)
|
||||
{
|
||||
uint64_t id = Util::GetTick();
|
||||
json_object *params = json_object_new_object();
|
||||
json_object_object_add(params, "type", json_object_new_int(remote_settings->type));
|
||||
json_object_object_add(params, "url", json_object_new_string(remote_settings->server));
|
||||
json_object_object_add(params, "username", json_object_new_string(remote_settings->username));
|
||||
json_object_object_add(params, "password", json_object_new_string(remote_settings->password));
|
||||
json_object_object_add(params, "src_path", json_object_new_string(src));
|
||||
json_object_object_add(params, "dest_path", json_object_new_string(dest));
|
||||
json_object_object_add(params, "size", json_object_new_uint64(file_size));
|
||||
json_object_object_add(params, "id", json_object_new_uint64(id));
|
||||
if (remote_settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
json_object_object_add(params, "http_server_type", json_object_new_string(remote_settings->http_server_type));
|
||||
}
|
||||
|
||||
const char *params_str = json_object_to_json_string(params);
|
||||
|
||||
httplib::Client tmp_client = httplib::Client("http://127.0.0.1:" + std::to_string(http_int_server_port));
|
||||
if (auto res = tmp_client.Post("/download_url", params_str, strlen(params_str), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
Util::Notify("%s queued for download", src);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Util::Notify("Failed to queue %s for download in background", src);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DownloadFile(const char *src, const char *dest)
|
||||
{
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
if (!remoteclient->Size(src, &bytes_to_download))
|
||||
{
|
||||
remoteclient->Quit();
|
||||
@@ -517,6 +562,11 @@ namespace Actions
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
if (enable_background_download && bytes_to_download > minimum_backgrond_file_size)
|
||||
{
|
||||
return BackgroundDownload(src, dest, bytes_to_download);
|
||||
}
|
||||
return remoteclient->Get(dest, src);
|
||||
}
|
||||
|
||||
@@ -645,39 +695,6 @@ namespace Actions
|
||||
else
|
||||
files.push_back(selected_remote_file);
|
||||
|
||||
bool download_and_install = false;
|
||||
if (remote_settings->enable_rpi)
|
||||
{
|
||||
std::string url = INSTALLER::getRemoteUrl(files.begin()->path);
|
||||
sprintf(activity_message, "%s", lang_strings[STR_CHECKING_REMOTE_SERVER_MSG]);
|
||||
file_transfering = false;
|
||||
if (!INSTALLER::canInstallRemotePkg(url))
|
||||
{
|
||||
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)
|
||||
{
|
||||
download_and_install = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
download_and_install = true;
|
||||
}
|
||||
|
||||
for (std::vector<DirEntry>::iterator it = files.begin(); it != files.end(); ++it)
|
||||
{
|
||||
if (stop_activity)
|
||||
@@ -699,7 +716,7 @@ namespace Actions
|
||||
{
|
||||
if (BE32(header.pkg_magic) == PKG_MAGIC)
|
||||
{
|
||||
if (download_and_install)
|
||||
if (!remote_settings->enable_rpi)
|
||||
{
|
||||
if (DownloadAndInstallPkg(it->path, &header) == 0)
|
||||
failed++;
|
||||
@@ -708,20 +725,51 @@ namespace Actions
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string url = INSTALLER::getRemoteUrl(it->path, true);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
|
||||
if (remote_settings->enable_disk_cache)
|
||||
{
|
||||
SplitPkgInstallData *install_data = (SplitPkgInstallData*) malloc(sizeof(SplitPkgInstallData));
|
||||
memset(install_data, 0, sizeof(SplitPkgInstallData));
|
||||
|
||||
if (INSTALLER::InstallRemotePkg(url, &header, title, true) == 0)
|
||||
failed++;
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
std::string install_pkg_path = std::string(temp_folder) + "/" + std::to_string(tick.mytick) + ".pkg";
|
||||
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE/2);
|
||||
|
||||
install_data->split_file = sp;
|
||||
install_data->remote_client = INSTALLER::GetRemoteClient(remote_settings);
|
||||
install_data->path = it->path;
|
||||
remoteclient->Size(it->path, &install_data->size);
|
||||
install_data->stop_write_thread = false;
|
||||
install_data->delete_client = true;
|
||||
|
||||
int ret = pthread_create(&install_data->thread, NULL, DownloadSplitPkg, install_data);
|
||||
|
||||
if (INSTALLER::InstallSplitPkg(it->path, install_data, false) == 0)
|
||||
failed++;
|
||||
else
|
||||
success++;
|
||||
}
|
||||
else
|
||||
success++;
|
||||
{
|
||||
std::string url = INSTALLER::getRemoteUrl(it->path, true);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(remoteclient, it->path, &header);
|
||||
if (INSTALLER::InstallRemotePkg(url, &header, title) == 0)
|
||||
failed++;
|
||||
else
|
||||
success++;
|
||||
|
||||
if (it != files.end())
|
||||
{
|
||||
sleep(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") ||
|
||||
else if (Util::EndsWith(path,".zip") || Util::EndsWith(path,".rar") || Util::EndsWith(path,".7z") ||
|
||||
Util::EndsWith(path,".tar.xz") || Util::EndsWith(path,".tar.gz"))
|
||||
{
|
||||
ArchiveEntry *entry = ZipUtil::GetPackageEntry(it->path, remoteclient);
|
||||
@@ -729,6 +777,8 @@ namespace Actions
|
||||
{
|
||||
while (entry != nullptr)
|
||||
{
|
||||
snprintf(activity_message, 1023, "%s %s", lang_strings[STR_INSTALLING], entry->filename.c_str());
|
||||
|
||||
ArchivePkgInstallData *install_data = (ArchivePkgInstallData*) malloc(sizeof(ArchivePkgInstallData));
|
||||
memset(install_data, 0, sizeof(ArchivePkgInstallData));
|
||||
|
||||
@@ -817,6 +867,18 @@ namespace Actions
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *DownloadSplitPkg(void *argp)
|
||||
{
|
||||
SplitPkgInstallData *install_data = (SplitPkgInstallData*) argp;
|
||||
SplitFile *sp = install_data->split_file;
|
||||
|
||||
/* loop over file contents and write to fd */
|
||||
sp->Open();
|
||||
install_data->remote_client->Get(sp, install_data->path);
|
||||
sp->Close();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *InstallLocalPkgsThread(void *argp)
|
||||
{
|
||||
int failed = 0;
|
||||
@@ -1064,9 +1126,10 @@ namespace Actions
|
||||
}
|
||||
}
|
||||
|
||||
void *InstallUrlPkgThread(void *argp)
|
||||
void *InstallLocalUrlPkgThread(void *argp)
|
||||
{
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
sprintf(status_message, "%s", "");
|
||||
pkg_header header;
|
||||
char filename[2000];
|
||||
@@ -1074,10 +1137,10 @@ namespace Actions
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentClockLocalTime(&now);
|
||||
sceRtcGetTick(&now, &tick);
|
||||
sprintf(filename, "%s/%lu.pkg", DATA_PATH, tick.mytick);
|
||||
sprintf(filename, "%s/%lu.pkg", TMP_FOLDER_PATH, tick.mytick);
|
||||
|
||||
std::string full_url = std::string(install_pkg_url.url);
|
||||
FileHost *filehost = FileHost::getFileHost(full_url);
|
||||
FileHost *filehost = FileHost::getFileHost(full_url, install_pkg_url.enable_alldebrid, install_pkg_url.enable_realdebrid);
|
||||
if (!filehost->IsValidUrl())
|
||||
{
|
||||
sprintf(status_message, "%s", lang_strings[STR_FAIL_TO_OBTAIN_GG_DL_MSG]);
|
||||
@@ -1100,7 +1163,7 @@ namespace Actions
|
||||
std::string host = full_url.substr(0, path_pos);
|
||||
std::string path = full_url.substr(path_pos);
|
||||
|
||||
WebDAVClient tmp_client;
|
||||
BaseClient tmp_client;
|
||||
tmp_client.Connect(host.c_str(), install_pkg_url.username, install_pkg_url.password);
|
||||
|
||||
sprintf(activity_message, "%s URL to %s", lang_strings[STR_DOWNLOADING], filename);
|
||||
@@ -1108,9 +1171,9 @@ namespace Actions
|
||||
memset(&header, 0, s);
|
||||
|
||||
int ret = tmp_client.Size(path, &bytes_to_download);
|
||||
if (!ret)
|
||||
if (ret == 0)
|
||||
{
|
||||
sprintf(status_message, "%s - %s", lang_strings[STR_FAILED], lang_strings[STR_CANNOT_READ_PKG_HDR_MSG]);
|
||||
sprintf(status_message, "%s", tmp_client.LastResponse());
|
||||
tmp_client.Quit();
|
||||
activity_inprogess = false;
|
||||
Windows::SetModalMode(false);
|
||||
@@ -1118,7 +1181,7 @@ namespace Actions
|
||||
}
|
||||
|
||||
file_transfering = 1;
|
||||
int is_performed = tmp_client.Get(path, filename);
|
||||
int is_performed = tmp_client.Get(filename, path);
|
||||
|
||||
if (is_performed == 0)
|
||||
{
|
||||
@@ -1171,10 +1234,70 @@ namespace Actions
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *InstallRpiUrlPkgThread(void *argp)
|
||||
{
|
||||
json_object *params = json_object_new_object();
|
||||
json_object_object_add(params, "url", json_object_new_string(install_pkg_url.url));
|
||||
json_object_object_add(params, "use_alldebrid", json_object_new_boolean(install_pkg_url.enable_alldebrid));
|
||||
json_object_object_add(params, "use_realdebrid", json_object_new_boolean(install_pkg_url.enable_realdebrid));
|
||||
json_object_object_add(params, "use_disk_cache", json_object_new_boolean(install_pkg_url.enable_disk_cache));
|
||||
|
||||
const char *params_str = json_object_to_json_string(params);
|
||||
|
||||
char host[128];
|
||||
sprintf(host, "http://127.0.0.1:%d", http_server_port);
|
||||
|
||||
httplib::Client tmp_client(host);
|
||||
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.Post("/__local__/install_url", params_str, strlen(params_str), "application/json");
|
||||
if (res != nullptr && HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
if (jobj != nullptr)
|
||||
{
|
||||
json_object *result = json_object_object_get(jobj, "result");
|
||||
if (result != nullptr)
|
||||
{
|
||||
bool success = json_object_get_boolean(json_object_object_get(result, "success"));
|
||||
if (!success)
|
||||
{
|
||||
const char* error_message = json_object_get_string(json_object_object_get(result, "error"));
|
||||
sprintf(status_message, "%s", error_message);
|
||||
activity_inprogess = false;
|
||||
Windows::SetModalMode(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
activity_inprogess = false;
|
||||
Windows::SetModalMode(false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
activity_inprogess = false;
|
||||
Windows::SetModalMode(false);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void InstallUrlPkg()
|
||||
{
|
||||
int res;
|
||||
sprintf(status_message, "%s", "");
|
||||
int res = pthread_create(&bk_activity_thid, NULL, InstallUrlPkgThread, NULL);
|
||||
|
||||
if (!install_pkg_url.enable_rpi)
|
||||
res = pthread_create(&bk_activity_thid, NULL, InstallLocalUrlPkgThread, NULL);
|
||||
else
|
||||
res = pthread_create(&bk_activity_thid, NULL, InstallRpiUrlPkgThread, NULL);
|
||||
|
||||
if (res != 0)
|
||||
{
|
||||
activity_inprogess = false;
|
||||
@@ -1203,6 +1326,12 @@ namespace Actions
|
||||
remoteclient = new NpxServeClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
|
||||
remoteclient = new RCloneClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_ARCHIVEORG) == 0)
|
||||
remoteclient = new ArchiveOrgClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MYRIENT) == 0)
|
||||
remoteclient = new MyrientClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
|
||||
remoteclient = new GithubClient();
|
||||
}
|
||||
else if (strncmp(remote_settings->server, "webdavs://", 10) == 0 || strncmp(remote_settings->server, "webdav://", 9) == 0)
|
||||
{
|
||||
@@ -1337,6 +1466,7 @@ namespace Actions
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
if (isCopy)
|
||||
return FS::Copy(src, dest);
|
||||
else
|
||||
@@ -1355,6 +1485,16 @@ namespace Actions
|
||||
if (src.isDir)
|
||||
{
|
||||
int err;
|
||||
if (!isCopy && !FS::FolderExists(dest))
|
||||
{
|
||||
errno = 0;
|
||||
int ret = rename(src.path, dest);
|
||||
if (ret != 0 && errno != EXDEV && errno != EEXIST)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DirEntry> entries = FS::ListDir(src.path, &err);
|
||||
FS::MkDirs(dest);
|
||||
for (int i = 0; i < entries.size(); i++)
|
||||
@@ -1369,9 +1509,11 @@ namespace Actions
|
||||
if (entries[i].isDir)
|
||||
{
|
||||
if (strcmp(entries[i].name, "..") == 0)
|
||||
{
|
||||
free(new_path);
|
||||
continue;
|
||||
}
|
||||
|
||||
FS::MkDirs(new_path);
|
||||
ret = CopyOrMove(entries[i], new_path, isCopy);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -1384,6 +1526,7 @@ namespace Actions
|
||||
snprintf(activity_message, 1024, "%s %s", isCopy ? lang_strings[STR_COPYING] : lang_strings[STR_MOVING], entries[i].path);
|
||||
bytes_to_download = entries[i].file_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
ret = CopyOrMoveLocalFile(entries[i].path, new_path, isCopy);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -1394,6 +1537,11 @@ namespace Actions
|
||||
}
|
||||
free(new_path);
|
||||
}
|
||||
|
||||
if (!isCopy && FS::FolderExists(src.path))
|
||||
{
|
||||
FS::RmDir(src.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1435,7 +1583,6 @@ namespace Actions
|
||||
char new_dir[512];
|
||||
sprintf(new_dir, "%s%s%s", local_directory, FS::hasEndSlash(local_directory) ? "" : "/", it->name);
|
||||
CopyOrMove(*it, new_dir, false);
|
||||
FS::RmRecursive(it->path);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1538,6 +1685,7 @@ namespace Actions
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
if (isCopy)
|
||||
return remoteclient->Copy(src, dest);
|
||||
else
|
||||
@@ -1633,6 +1781,7 @@ namespace Actions
|
||||
snprintf(activity_message, 1024, "%s %s", lang_strings[STR_COPYING], entries[i].path);
|
||||
bytes_to_download = entries[i].file_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
ret = CopyOrMoveRemoteFile(entries[i].path, new_path, true);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -1726,6 +1875,7 @@ namespace Actions
|
||||
sprintf(activity_message, "%s %s to %s", lang_strings[STR_DOWNLOADING], filename.c_str(), local_file);
|
||||
remoteclient->Size(filename, &bytes_to_download);
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
file_transfering = true;
|
||||
int ret = remoteclient->Get(local_file, filename);
|
||||
if (ret == 0)
|
||||
@@ -1776,4 +1926,49 @@ namespace Actions
|
||||
sprintf(remote_file_to_select, "%s", temp_file.c_str());
|
||||
}
|
||||
|
||||
void RestartServer()
|
||||
{
|
||||
INSTALLER::StopEzRemoteServer();
|
||||
sleep(2);
|
||||
INSTALLER::StartEzRemoteServer();
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
void GetBackgroundDownloadProgress()
|
||||
{
|
||||
httplib::Client client = httplib::Client("http://127.0.0.1:" + std::to_string(http_int_server_port));
|
||||
|
||||
if (auto res = client.Get("/get_download_state"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
bg_download_progress.clear();
|
||||
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
if (jobj != nullptr)
|
||||
{
|
||||
struct array_list *progress_list = json_object_get_array(jobj);
|
||||
|
||||
for (size_t idx = 0; idx < progress_list->length; ++idx)
|
||||
{
|
||||
DownloadProgress progress;
|
||||
|
||||
json_object *progress_obj = (json_object *)array_list_get_idx(progress_list, idx);
|
||||
progress.path = json_object_get_string(json_object_object_get(progress_obj, "path"));
|
||||
progress.bytes_transfered = json_object_get_uint64(json_object_object_get(progress_obj, "bytes_transfered"));
|
||||
progress.file_size = json_object_get_uint64(json_object_object_get(progress_obj, "file_size"));
|
||||
progress.state = state_strings[json_object_get_int(json_object_object_get(progress_obj, "state"))];
|
||||
progress.timestamp = json_object_get_uint64(json_object_object_get(progress_obj, "timestamp"));
|
||||
|
||||
bg_download_progress.push_back(progress);
|
||||
}
|
||||
json_object_put(jobj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(status_message, 1024, "Failed to get the download progress from ezRemote Server");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-4
@@ -1,5 +1,5 @@
|
||||
#ifndef ACTIONS_H
|
||||
#define ACTIONS_H
|
||||
#ifndef EZ_ACTIONS_H
|
||||
#define EZ_ACTIONS_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include "installer.h"
|
||||
@@ -99,7 +99,8 @@ namespace Actions
|
||||
void InstallRemotePkgs();
|
||||
void *InstallLocalPkgsThread(void *argp);
|
||||
void InstallLocalPkgs();
|
||||
void *InstallUrlPkgThread(void *argp);
|
||||
void *InstallLocalUrlPkgThread(void *argp);
|
||||
void *InstallRpiUrlPkgThread(void *argp);
|
||||
void InstallUrlPkg();
|
||||
void *KeepAliveThread(void *argp);
|
||||
void *ExtractZipThread(void *argp);
|
||||
@@ -120,6 +121,9 @@ namespace Actions
|
||||
void CreateLocalFile(char *filename);
|
||||
void CreateRemoteFile(char *filename);
|
||||
void *ExtractArchivePkg(void *argp);
|
||||
void *DownloadSplitPkg(void *argp);
|
||||
void RestartServer();
|
||||
void GetBackgroundDownloadProgress();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef BASE64_H_
|
||||
#define BASE64_H_
|
||||
#ifndef EZ_BASE64_H_
|
||||
#define EZ_BASE64_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
+23
-10
@@ -128,18 +128,31 @@ std::vector<DirEntry> ApacheClient::ListDir(const std::string &path)
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("td") == 0)
|
||||
{
|
||||
value = lxb_dom_node_text_content(node, &value_len);
|
||||
// get the child <a> element
|
||||
lxb_dom_node_t *a_node = NextChildElement(lxb_dom_interface_element(node));
|
||||
if (a_node == nullptr) continue;
|
||||
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(a_node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
tmp_string = Util::Rtrim(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] == '/')
|
||||
if (tmp_string.compare("a") == 0)
|
||||
{
|
||||
sprintf(entry.path, "%s%s", path.c_str(), entry.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
|
||||
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);
|
||||
tmp_string = Util::Rtrim(tmp_string, "/");
|
||||
tmp_string = BaseClient::UnEscape(tmp_string);
|
||||
if (tmp_string.compare("..") != 0)
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
sprintf(entry.name, "%s", tmp_string.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else continue; // not valid record
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef APACHE_H
|
||||
#define APACHE_H
|
||||
#ifndef EZ_APACHE_H
|
||||
#define EZ_APACHE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -0,0 +1,362 @@
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <lexbor/dom/interfaces/node.h>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include "common.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/archiveorg.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "system.h"
|
||||
#include "windows.h"
|
||||
|
||||
using httplib::Client;
|
||||
using httplib::Headers;
|
||||
using httplib::Result;
|
||||
|
||||
struct InsensitiveCompare
|
||||
{
|
||||
bool operator()(const std::string &a, const std::string &b) const
|
||||
{
|
||||
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
static std::map<std::string, int> month_map = {{"Jan", 1}, {"Feb", 2}, {"Mar", 3}, {"Apr", 4}, {"May", 5}, {"Jun", 6}, {"Jul", 7}, {"Aug", 8}, {"Sep", 9}, {"Oct", 10}, {"Nov", 11}, {"Dec", 12}};
|
||||
static std::set<std::string, InsensitiveCompare> ignore_cookie_keys = {"path", "expires", "max-age", "domain", "secure"};
|
||||
|
||||
std::string ArchiveOrgClient::GenerateRandomId(const int len)
|
||||
{
|
||||
static const char alphanum[] = "0123456789abcdef";
|
||||
std::string tmp_s;
|
||||
tmp_s.reserve(len);
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
tmp_s += alphanum[rand() % (sizeof(alphanum) - 1)];
|
||||
}
|
||||
|
||||
return tmp_s;
|
||||
}
|
||||
|
||||
int ArchiveOrgClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
this->host_url = url;
|
||||
size_t scheme_pos = url.find("://");
|
||||
size_t root_pos = url.find("/", scheme_pos + 3);
|
||||
if (root_pos != std::string::npos)
|
||||
{
|
||||
this->host_url = url.substr(0, root_pos);
|
||||
this->base_path = url.substr(root_pos);
|
||||
}
|
||||
client = new httplib::Client(this->host_url);
|
||||
client->set_keep_alive(true);
|
||||
client->set_follow_location(true);
|
||||
client->set_connection_timeout(30);
|
||||
client->set_read_timeout(30);
|
||||
client->enable_server_certificate_verification(false);
|
||||
|
||||
this->cookies = {
|
||||
{"donation-identifier", GenerateRandomId(32)},
|
||||
{"test-cookie", "1"},
|
||||
{"abtest-identifier", GenerateRandomId(32)}
|
||||
};
|
||||
|
||||
if (username.length() > 0)
|
||||
return Login(username, password);
|
||||
else if (!send_ping)
|
||||
this->connected = true;
|
||||
else if (Ping())
|
||||
this->connected = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ArchiveOrgClient::Login(const std::string &username, const std::string &password)
|
||||
{
|
||||
std::string url = std::string("/account/login");
|
||||
Headers headers = {{ "User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0"}};
|
||||
SetCookies(headers);
|
||||
|
||||
MultipartFormDataItems items = {
|
||||
{"username", username, "", ""},
|
||||
{"password", password, "", ""},
|
||||
{"remember", "true", "", ""},
|
||||
{"referer", "https://archive.org/", "", ""},
|
||||
{"login", "true", "", ""},
|
||||
{"submit_by_js", "true", "", ""}};
|
||||
|
||||
if (auto res = client->Post(url, headers, items))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
if (res->has_header("Set-Cookie"))
|
||||
{
|
||||
int cookies_count = res->get_header_value_count("Set-Cookie");
|
||||
|
||||
for (int i = 0; i < cookies_count; i++)
|
||||
{
|
||||
std::string cookie_str = res->get_header_value("Set-Cookie", i);
|
||||
|
||||
std::vector<std::string> cookies = Util::Split(cookie_str, ";");
|
||||
for (std::vector<std::string>::iterator it = cookies.begin(); it != cookies.end();)
|
||||
{
|
||||
std::vector<std::string> cookie = Util::Split(*it, "=");
|
||||
std::string key = Util::Trim(cookie[0], " ");
|
||||
if (ignore_cookie_keys.find(key) == ignore_cookie_keys.end())
|
||||
{
|
||||
if (cookie.size() > 1)
|
||||
this->cookies[key] = Util::Trim(cookie[1], " ");
|
||||
else
|
||||
this->cookies[key] = "";
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
this->connected = true;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DirEntry> ArchiveOrgClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
Headers headers;
|
||||
SetCookies(headers);
|
||||
|
||||
std::string encoded_path = httplib::detail::encode_url(GetFullPath(path) + "/");
|
||||
if (auto res = client->Get(encoded_path, headers))
|
||||
{
|
||||
lxb_status_t status;
|
||||
lxb_dom_attr_t *attr;
|
||||
lxb_dom_element_t *table_element, *tr_element, *td_element;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *table_collection;
|
||||
lxb_dom_collection_t *tr_collection;
|
||||
lxb_dom_collection_t *td_collection;
|
||||
std::string tmp_string;
|
||||
const lxb_char_t *value;
|
||||
size_t value_len;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
table_collection = lxb_dom_collection_make(&document->dom_document, 1);
|
||||
if (table_collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
tr_collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (tr_collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
table_collection, (const lxb_char_t *)"table", 5);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (lxb_dom_collection_length(table_collection) < 1)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(table_collection); i++)
|
||||
{
|
||||
table_element = lxb_dom_collection_element(table_collection, i);
|
||||
value = lxb_dom_element_class(table_element, &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("directory-listing-table") == 0)
|
||||
break;
|
||||
table_element = nullptr;
|
||||
}
|
||||
|
||||
if (table_element == nullptr)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(table_element,
|
||||
tr_collection, (const lxb_char_t *)"tr", 2);
|
||||
if (status != LXB_STATUS_OK && lxb_dom_collection_length(tr_collection) < 2)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// skip row 0 , since it has the previous folder header
|
||||
for (size_t i = 2; i < lxb_dom_collection_length(tr_collection); i++)
|
||||
{
|
||||
DirEntry entry;
|
||||
std::string title, aclass;
|
||||
memset(&entry.modified, 0, sizeof(DateTime));
|
||||
|
||||
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) < 3)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// td0 contains the <a> tag
|
||||
td_element = lxb_dom_collection_element(td_collection, 0);
|
||||
lxb_dom_node_t *a_node = NextChildElement(td_element);
|
||||
// there is no a_node in protected links
|
||||
if (a_node == nullptr)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(a_node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("a") != 0)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
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::UnEscape(tmp_string);
|
||||
sprintf(entry.name, "%s", tmp_string.c_str());
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
if (path.length() > 0 && path[path.length() - 1] == '/')
|
||||
{
|
||||
sprintf(entry.path, "%s%s", path.c_str(), entry.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
|
||||
}
|
||||
|
||||
// next td contains the date
|
||||
td_element = lxb_dom_collection_element(td_collection, 1);
|
||||
value = lxb_dom_node_text_content(NextChildTextNode(td_element), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
std::vector<std::string> date_time = Util::Split(tmp_string, " ");
|
||||
|
||||
if (date_time.size() > 1)
|
||||
{
|
||||
std::vector<std::string> adate = Util::Split(date_time[0], "-");
|
||||
if (adate.size() == 3)
|
||||
{
|
||||
entry.modified.day = atoi(adate[0].c_str());
|
||||
entry.modified.month = month_map[adate[1]];
|
||||
entry.modified.year = atoi(adate[2].c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> atime = Util::Split(date_time[1], ":");
|
||||
if (atime.size() == 2)
|
||||
{
|
||||
entry.modified.hours = atoi(atime[0].c_str());
|
||||
entry.modified.minutes = atoi(atime[1].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// next td contains file size, if fize size is "-", then it's a directory
|
||||
td_element = lxb_dom_collection_element(td_collection, 2);
|
||||
value = lxb_dom_node_text_content(NextChildTextNode(td_element), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
|
||||
if (tmp_string.compare("-") == 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;
|
||||
uint64_t multiplier = 0;
|
||||
std::string size_formatted = tmp_string.substr(0, tmp_string.size()-1);
|
||||
Util::ReplaceAll(size_formatted, ",", "");
|
||||
float fsize = std::stof(size_formatted);
|
||||
switch (tmp_string[tmp_string.size()-1]) {
|
||||
case 'B':
|
||||
multiplier = 1;
|
||||
break;
|
||||
case 'K':
|
||||
multiplier = 1024;
|
||||
break;
|
||||
case 'M':
|
||||
multiplier = 1048576;
|
||||
break;
|
||||
case 'G':
|
||||
multiplier = 1073741824;
|
||||
break;
|
||||
default:
|
||||
multiplier = 1;
|
||||
}
|
||||
entry.file_size = fsize * multiplier;
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
out.push_back(entry);
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
return out;
|
||||
}
|
||||
|
||||
finish:
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef EZ_ARCHIVEORG_H
|
||||
#define EZ_ARCHIVEORG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
|
||||
class ArchiveOrgClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
|
||||
private:
|
||||
int Login(const std::string &username, const std::string &password);
|
||||
std::string GenerateRandomId(const int len);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -20,7 +20,27 @@ BaseClient::~BaseClient()
|
||||
delete client;
|
||||
};
|
||||
|
||||
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
int BaseClient::SetCookies(Headers &headers)
|
||||
{
|
||||
if (this->cookies.size() > 0)
|
||||
{
|
||||
std::string cookie;
|
||||
for (std::map<std::string, std::string>::iterator it = this->cookies.begin(); it != this->cookies.end();)
|
||||
{
|
||||
cookie.append(it->first).append("=").append(it->second);
|
||||
if (std::next(it, 1) != this->cookies.end())
|
||||
{
|
||||
cookie.append("; ");
|
||||
}
|
||||
++it;
|
||||
}
|
||||
headers.emplace("Cookie", cookie);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int BaseClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
this->host_url = url;
|
||||
size_t scheme_pos = url.find("://");
|
||||
@@ -38,8 +58,12 @@ int BaseClient::Connect(const std::string &url, const std::string &username, con
|
||||
client->set_connection_timeout(30);
|
||||
client->set_read_timeout(30);
|
||||
client->enable_server_certificate_verification(false);
|
||||
if (Ping())
|
||||
|
||||
if (!send_ping)
|
||||
this->connected = true;
|
||||
else if (Ping())
|
||||
this->connected = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -81,7 +105,10 @@ int BaseClient::Rmdir(const std::string &path, bool recursive)
|
||||
|
||||
int BaseClient::Size(const std::string &path, int64_t *size)
|
||||
{
|
||||
if (auto res = client->Head(GetFullPath(path)))
|
||||
Headers headers;
|
||||
SetCookies(headers);
|
||||
|
||||
if (auto res = client->Head(GetFullPath(path), headers))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
@@ -90,6 +117,33 @@ int BaseClient::Size(const std::string &path, int64_t *size)
|
||||
*size = atoll(content_length.c_str());
|
||||
return 1;
|
||||
}
|
||||
else if (res->status == 405)// Server doesn't support HEAD request. Try get range with 0 bytes and grab size from the response header
|
||||
// example: Content-Range: bytes 0-10/4372785
|
||||
{
|
||||
Headers headers = {{"Range", "bytes=0-1"}};
|
||||
SetCookies(headers);
|
||||
|
||||
if (auto range_res = client->Get(GetFullPath(path), headers))
|
||||
{
|
||||
if (HTTP_SUCCESS(range_res->status))
|
||||
{
|
||||
if (range_res->has_header("Content-Range"))
|
||||
{
|
||||
std::string range = range_res->get_header_value("Content-Range");
|
||||
std::vector<std::string> range_parts = Util::Split(range, "/");
|
||||
if (range_parts.size() == 2)
|
||||
{
|
||||
*size = atoll(range_parts[1].c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%d - %s", res->status, detail::status_message(res->status));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -102,7 +156,11 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
|
||||
{
|
||||
std::ofstream file_stream(outputfile, std::ios::binary);
|
||||
bytes_transfered = 0;
|
||||
if (auto res = client->Get(GetFullPath(path),
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
Headers headers;
|
||||
SetCookies(headers);
|
||||
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
file_stream.write(data, data_length);
|
||||
@@ -120,11 +178,39 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BaseClient::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
|
||||
{
|
||||
Headers headers;
|
||||
SetCookies(headers);
|
||||
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
if (!split_file->IsClosed())
|
||||
{
|
||||
split_file->Write((char*)data, data_length);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
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}};
|
||||
SetCookies(headers);
|
||||
|
||||
size_t bytes_read = 0;
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
@@ -148,6 +234,8 @@ int BaseClient::GetRange(const std::string &path, void *buffer, uint64_t size, u
|
||||
char range_header[64];
|
||||
sprintf(range_header, "bytes=%lu-%lu", offset, offset + size - 1);
|
||||
Headers headers = {{"Range", range_header}};
|
||||
SetCookies(headers);
|
||||
|
||||
size_t bytes_read = 0;
|
||||
std::vector<char> body;
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
@@ -207,6 +295,8 @@ int BaseClient::Head(const std::string &path, void *buffer, uint64_t len)
|
||||
char range_header[64];
|
||||
sprintf(range_header, "bytes=%lu-%lu", 0L, len - 1);
|
||||
Headers headers = {{"Range", range_header}};
|
||||
SetCookies(headers);
|
||||
|
||||
size_t bytes_read = 0;
|
||||
std::vector<char> body;
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
@@ -345,3 +435,26 @@ std::string BaseClient::UnEscape(const std::string &url)
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void *BaseClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void BaseClient::Close(void *fp)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
}
|
||||
|
||||
int BaseClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int BaseClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef BASESERVER_H
|
||||
#define BASESERVER_H
|
||||
#ifndef EZ_BASESERVER_H
|
||||
#define EZ_BASESERVER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "http/httplib.h"
|
||||
#include "split_file.h"
|
||||
#include "common.h"
|
||||
|
||||
class BaseClient : public RemoteClient
|
||||
@@ -15,14 +16,17 @@ class BaseClient : public RemoteClient
|
||||
public:
|
||||
BaseClient();
|
||||
~BaseClient();
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
int Connect(const std::string &url, const std::string &api_key);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
@@ -33,6 +37,8 @@ public:
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
std::string GetPath(std::string path1, std::string path2);
|
||||
std::string GetFullPath(std::string path1);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
@@ -43,11 +49,14 @@ public:
|
||||
static std::string UnEscape(const std::string &url);
|
||||
|
||||
protected:
|
||||
int SetCookies(httplib::Headers &headers);
|
||||
|
||||
httplib::Client *client;
|
||||
std::string base_path;
|
||||
std::string host_url;
|
||||
char response[512];
|
||||
bool connected = false;
|
||||
std::map<std::string, std::string> cookies;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+142
-61
@@ -24,8 +24,6 @@
|
||||
#define FTP_CLIENT_READ 1
|
||||
#define FTP_CLIENT_WRITE 2
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
|
||||
FtpClient::FtpClient()
|
||||
{
|
||||
mp_ftphandle = static_cast<ftphandle *>(calloc(1, sizeof(ftphandle)));
|
||||
@@ -48,7 +46,7 @@ FtpClient::~FtpClient()
|
||||
free(mp_ftphandle);
|
||||
}
|
||||
|
||||
int FtpClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int FtpClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
int port = 21;
|
||||
std::string host = url.substr(6);
|
||||
@@ -125,7 +123,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
|
||||
}
|
||||
mp_ftphandle->handle = sControl;
|
||||
|
||||
if (ReadResponse('2', mp_ftphandle) == 0)
|
||||
if (ReadResponse("2", mp_ftphandle) == 0)
|
||||
{
|
||||
close(mp_ftphandle->handle);
|
||||
mp_ftphandle->handle = 0;
|
||||
@@ -142,7 +140,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
|
||||
cmd = "USER anonymous";
|
||||
}
|
||||
|
||||
if (!FtpSendCmd(cmd, '3', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "3", mp_ftphandle))
|
||||
{
|
||||
if (mp_ftphandle->ctrl != NULL)
|
||||
return 1;
|
||||
@@ -161,7 +159,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
|
||||
|
||||
cmd = "PASS " + pass;
|
||||
int ret;
|
||||
if ((ret = FtpSendCmd(cmd, '2', mp_ftphandle)))
|
||||
if ((ret = FtpSendCmd(cmd, "2", mp_ftphandle)))
|
||||
{
|
||||
mp_ftphandle->is_connected = true;
|
||||
}
|
||||
@@ -179,7 +177,7 @@ int FtpClient::Connect(const std::string &url, const std::string &user, const st
|
||||
*
|
||||
* return 1 if proper response received, 0 otherwise
|
||||
*/
|
||||
int FtpClient::FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle *nControl)
|
||||
int FtpClient::FtpSendCmd(const std::string &cmd, const std::string &expected_resp, ftphandle *nControl)
|
||||
{
|
||||
char buf[512];
|
||||
int x;
|
||||
@@ -205,7 +203,7 @@ int FtpClient::FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle
|
||||
* return 0 if first char doesn't match
|
||||
* return 1 if first char matches
|
||||
*/
|
||||
int FtpClient::ReadResponse(char c, ftphandle *nControl)
|
||||
int FtpClient::ReadResponse(const std::string &c, ftphandle *nControl)
|
||||
{
|
||||
char match[5];
|
||||
|
||||
@@ -228,7 +226,7 @@ int FtpClient::ReadResponse(char c, ftphandle *nControl)
|
||||
} while (strncmp(nControl->response, match, 4));
|
||||
}
|
||||
|
||||
if (nControl->response[0] == c)
|
||||
if (c.find(nControl->response[0]) != std::string::npos)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -368,7 +366,7 @@ int FtpClient::FtpAccess(const std::string &path, accesstype type, transfermode
|
||||
return 0;
|
||||
}
|
||||
sprintf(buf, "TYPE %c", mode);
|
||||
if (!FtpSendCmd(buf, '2', nControl))
|
||||
if (!FtpSendCmd(buf, "2", nControl))
|
||||
return 0;
|
||||
|
||||
switch (type)
|
||||
@@ -477,7 +475,7 @@ int FtpClient::FtpAcceptConnection(ftphandle *nData, ftphandle *nControl)
|
||||
{
|
||||
close(nData->handle);
|
||||
nData->handle = 0;
|
||||
ReadResponse('2', nControl);
|
||||
ReadResponse("2", nControl);
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
@@ -521,7 +519,7 @@ int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode
|
||||
|
||||
memset(&sin, 0, l);
|
||||
sin.in.sin_family = AF_INET;
|
||||
if (!FtpSendCmd("PASV", '2', nControl))
|
||||
if (!FtpSendCmd("PASV", "2", nControl))
|
||||
return -1;
|
||||
cp = strchr(nControl->response, '(');
|
||||
if (cp == NULL)
|
||||
@@ -542,7 +540,7 @@ int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode
|
||||
{
|
||||
char buf[512];
|
||||
sprintf(buf, "REST %lld", mp_ftphandle->offset);
|
||||
if (!FtpSendCmd(buf, '3', nControl))
|
||||
if (!FtpSendCmd(buf, "3", nControl))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -592,7 +590,7 @@ int FtpClient::FtpOpenPasv(ftphandle *nControl, ftphandle **nData, transfermode
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!ReadResponse('1', nControl))
|
||||
if (!ReadResponse("1", nControl))
|
||||
{
|
||||
close(sData);
|
||||
return -1;
|
||||
@@ -717,7 +715,7 @@ int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode
|
||||
(unsigned char)sin.sa.sa_data[5],
|
||||
(unsigned char)sin.sa.sa_data[0],
|
||||
(unsigned char)sin.sa.sa_data[1]);
|
||||
if (!FtpSendCmd(buf, '2', nControl))
|
||||
if (!FtpSendCmd(buf, "2", nControl))
|
||||
{
|
||||
close(sData);
|
||||
return -1;
|
||||
@@ -727,7 +725,7 @@ int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode
|
||||
{
|
||||
char buf[512];
|
||||
sprintf(buf, "REST %lld", mp_ftphandle->offset);
|
||||
if (!FtpSendCmd(buf, '3', nControl))
|
||||
if (!FtpSendCmd(buf, "3", nControl))
|
||||
{
|
||||
close(sData);
|
||||
return 0;
|
||||
@@ -747,7 +745,7 @@ int FtpClient::FtpOpenPort(ftphandle *nControl, ftphandle **nData, transfermode
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!FtpSendCmd(cmd, '1', nControl))
|
||||
if (!FtpSendCmd(cmd, "1", nControl))
|
||||
{
|
||||
FtpClose(*nData);
|
||||
*nData = NULL;
|
||||
@@ -880,6 +878,33 @@ int FtpClient::FtpXfer(const std::string &localfile, const std::string &path, ft
|
||||
return FtpClose(nData);
|
||||
}
|
||||
|
||||
/*
|
||||
* FtpXfer - issue a command and transfer data
|
||||
*
|
||||
* return 1 if successful, 0 otherwise
|
||||
*/
|
||||
int FtpClient::FtpXfer(SplitFile *split_file, const std::string &path, ftphandle *nControl, accesstype type, transfermode mode)
|
||||
{
|
||||
int l, c;
|
||||
char *dbuf;
|
||||
ftphandle *nData;
|
||||
|
||||
if (!FtpAccess(path, type, mode, nControl, &nData))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
dbuf = static_cast<char *>(malloc(FTP_CLIENT_BUFSIZ));
|
||||
while ((l = FtpRead(dbuf, FTP_CLIENT_BUFSIZ, nData)) > 0)
|
||||
{
|
||||
if (split_file->Write(dbuf, l) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
free(dbuf);
|
||||
return FtpClose(nData);
|
||||
}
|
||||
|
||||
/*
|
||||
* FtpWrite - write to a data connection
|
||||
*/
|
||||
@@ -1019,7 +1044,7 @@ int FtpClient::FtpClose(ftphandle *nData)
|
||||
ctrl = nData->ctrl;
|
||||
free(nData);
|
||||
if (ctrl)
|
||||
return ReadResponse('2', ctrl);
|
||||
return ReadResponse("2", ctrl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1035,7 +1060,7 @@ int FtpClient::Quit()
|
||||
strcpy(mp_ftphandle->response, "error: no anwser from server\n");
|
||||
return 0;
|
||||
}
|
||||
FtpSendCmd("QUIT", '2', mp_ftphandle);
|
||||
FtpSendCmd("QUIT", "2", mp_ftphandle);
|
||||
shutdown(mp_ftphandle->handle, SHUT_WR);
|
||||
struct linger lng = {1, 0};
|
||||
setsockopt(mp_ftphandle->handle, SOL_SOCKET, SO_LINGER, &lng, sizeof(lng));
|
||||
@@ -1079,7 +1104,7 @@ int FtpClient::RawRead(void *buf, int max, ftphandle *handle)
|
||||
int FtpClient::Site(const std::string &cmd)
|
||||
{
|
||||
std::string tmp = "SITE " + cmd;
|
||||
if (!FtpSendCmd(tmp, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(tmp, "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1092,7 +1117,7 @@ int FtpClient::Site(const std::string &cmd)
|
||||
|
||||
int FtpClient::Raw(const std::string &cmd)
|
||||
{
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1111,7 +1136,7 @@ int FtpClient::SysType(char *buf, int max)
|
||||
int l = max;
|
||||
char *b = buf;
|
||||
char *s;
|
||||
if (!FtpSendCmd("SYST", '2', mp_ftphandle))
|
||||
if (!FtpSendCmd("SYST", "2", mp_ftphandle))
|
||||
return 0;
|
||||
s = &mp_ftphandle->response[4];
|
||||
while ((--l) && (*s != ' '))
|
||||
@@ -1128,7 +1153,7 @@ int FtpClient::SysType(char *buf, int max)
|
||||
int FtpClient::Mkdir(const std::string &path)
|
||||
{
|
||||
std::string cmd = "MKD " + path;
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1141,7 +1166,7 @@ int FtpClient::Mkdir(const std::string &path)
|
||||
int FtpClient::Chdir(const std::string &path)
|
||||
{
|
||||
std::string cmd = "CWD " + path;
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1153,7 +1178,7 @@ int FtpClient::Chdir(const std::string &path)
|
||||
*/
|
||||
int FtpClient::Cdup()
|
||||
{
|
||||
if (!FtpSendCmd("CDUP", '2', mp_ftphandle))
|
||||
if (!FtpSendCmd("CDUP", "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1165,7 +1190,7 @@ int FtpClient::Cdup()
|
||||
*/
|
||||
bool FtpClient::Noop()
|
||||
{
|
||||
if (!FtpSendCmd("NOOP", '2', mp_ftphandle))
|
||||
if (!FtpSendCmd("NOOP", "25", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1183,7 +1208,7 @@ bool FtpClient::Ping()
|
||||
int FtpClient::Rmdir(const std::string &path)
|
||||
{
|
||||
std::string cmd = "RMD " + path;
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1246,11 +1271,11 @@ int FtpClient::Size(const std::string &path, int64_t *size)
|
||||
return 0;
|
||||
|
||||
sprintf(cmd, "TYPE %c", FtpClient::transfermode::image);
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
|
||||
sprintf(cmd, "SIZE %s", path.c_str());
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
rv = 0;
|
||||
else
|
||||
{
|
||||
@@ -1283,6 +1308,15 @@ 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::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
|
||||
{
|
||||
mp_ftphandle->offset = offset;
|
||||
if (offset == 0)
|
||||
return FtpXfer(split_file, path, mp_ftphandle, FtpClient::fileread, FtpClient::transfermode::image);
|
||||
else
|
||||
return FtpXfer(split_file, 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;
|
||||
@@ -1373,10 +1407,10 @@ int FtpClient::Put(const std::string &inputfile, const std::string &path, uint64
|
||||
int FtpClient::Rename(const std::string &src, const std::string &dst)
|
||||
{
|
||||
std::string cmd = "RNFR " + src;
|
||||
if (!FtpSendCmd(cmd, '3', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "3", mp_ftphandle))
|
||||
return 0;
|
||||
cmd = "RNTO " + dst;
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
@@ -1385,7 +1419,7 @@ int FtpClient::Rename(const std::string &src, const std::string &dst)
|
||||
int FtpClient::Delete(const std::string &path)
|
||||
{
|
||||
std::string cmd = "DELE " + path;
|
||||
if (!FtpSendCmd(cmd, '2', mp_ftphandle))
|
||||
if (!FtpSendCmd(cmd, "2", mp_ftphandle))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -1466,9 +1500,16 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
dirEntry->modified.minutes = (uint8_t)strtoul(token + 3, NULL, 10);
|
||||
|
||||
// The PM period covers the 12 hours from noon to midnight
|
||||
// Correct 12-hour clock: 12:xx AM = 00:xx, 12:xx PM = 12:xx
|
||||
if (strstr(token, "PM") != NULL)
|
||||
{
|
||||
dirEntry->modified.hours += 12;
|
||||
if (dirEntry->modified.hours != 12)
|
||||
dirEntry->modified.hours += 12;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dirEntry->modified.hours == 12)
|
||||
dirEntry->modified.hours = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1492,7 +1533,7 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
else
|
||||
{
|
||||
// Save the size of the file
|
||||
dirEntry->file_size = strtoul(token, NULL, 10);
|
||||
dirEntry->file_size = strtoull(token, NULL, 10);
|
||||
}
|
||||
|
||||
// Read filename field
|
||||
@@ -1514,8 +1555,8 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
// Unix listing format?
|
||||
else
|
||||
{
|
||||
// Check file permissions
|
||||
if (strchr(token, 'd') != NULL)
|
||||
// Check file permissions — 'd' must be at position 0 of the permissions field
|
||||
if (token[0] == 'd')
|
||||
{
|
||||
dirEntry->isDir = true;
|
||||
}
|
||||
@@ -1545,7 +1586,7 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
return -1;
|
||||
|
||||
// Save the size of the file
|
||||
dirEntry->file_size = strtoul(token, NULL, 10);
|
||||
dirEntry->file_size = strtoull(token, NULL, 10);
|
||||
|
||||
// Read modification time (month)
|
||||
token = strtok_r(NULL, " ", &p);
|
||||
@@ -1586,12 +1627,13 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
// The format of the year is yyyy
|
||||
dirEntry->modified.year = (uint16_t)strtoul(token, NULL, 10);
|
||||
}
|
||||
else if (strlen(token) == 5)
|
||||
else if (strchr(token, ':') != NULL)
|
||||
{
|
||||
// The format of the time hh:mm
|
||||
token[2] = '\0';
|
||||
// The format of the time is hh:mm or h:mm
|
||||
char *colon = strchr(token, ':');
|
||||
*colon = '\0';
|
||||
dirEntry->modified.hours = (uint8_t)strtoul(token, NULL, 10);
|
||||
dirEntry->modified.minutes = (uint8_t)strtoul(token + 3, NULL, 10);
|
||||
dirEntry->modified.minutes = (uint8_t)strtoul(colon + 1, NULL, 10);
|
||||
dirEntry->modified.year = cur_time.tm_year + 1900;
|
||||
}
|
||||
else
|
||||
@@ -1606,6 +1648,11 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
if (token == NULL)
|
||||
return -1;
|
||||
|
||||
// For symlinks, strip the " -> target" suffix (e.g. "linkname -> /some/target")
|
||||
char *arrow = strstr(token, " -> ");
|
||||
if (arrow != NULL)
|
||||
*arrow = '\0';
|
||||
|
||||
// Retrieve the length of the filename
|
||||
n = strlen(token);
|
||||
// Limit the number of characters to copy
|
||||
@@ -1617,6 +1664,10 @@ int FtpClient::ParseDirEntry(char *line, DirEntry *dirEntry)
|
||||
dirEntry->name[n] = '\0';
|
||||
}
|
||||
|
||||
// Exclude hidden files and folders (names starting with '.')
|
||||
if (!show_hidden_files && dirEntry->name[0] == '.')
|
||||
return -1;
|
||||
|
||||
// The directory entry is valid
|
||||
return 1;
|
||||
}
|
||||
@@ -1627,37 +1678,48 @@ int FtpClient::ParseMLSDDirEntry(char *line, DirEntry *dirEntry)
|
||||
char *token;
|
||||
char *facts;
|
||||
char *keypair;
|
||||
char *factsSave;
|
||||
char key[128];
|
||||
char value[128];
|
||||
|
||||
// Spilt string by space
|
||||
// Split string by first space: facts portion and name portion
|
||||
facts = strtok_r(line, " ", &p);
|
||||
|
||||
// path is the rest of the line after space
|
||||
// path is the rest of the line after the space, strip trailing CR/LF
|
||||
token = strtok_r(p, "\r\n", &p);
|
||||
snprintf(dirEntry->name, 256, "%s", token);
|
||||
|
||||
// split properties by semi-colon and get the key value pair
|
||||
while ((keypair = strtok_r(facts, ";", &facts)))
|
||||
// Split facts by semicolon and parse each key=value pair
|
||||
factsSave = NULL;
|
||||
keypair = strtok_r(facts, ";", &factsSave);
|
||||
while (keypair != NULL)
|
||||
{
|
||||
sscanf(keypair, "%[^=]=%s", key, value);
|
||||
if (strcasecmp(key, "type") == 0)
|
||||
key[0] = '\0';
|
||||
value[0] = '\0';
|
||||
if (sscanf(keypair, "%127[^=]=%127s", key, value) == 2)
|
||||
{
|
||||
dirEntry->isDir = false;
|
||||
if (strcasecmp(value, "dir") == 0)
|
||||
if (strcasecmp(key, "type") == 0)
|
||||
{
|
||||
dirEntry->isDir = true;
|
||||
dirEntry->isDir = false;
|
||||
// dir, cdir (current dir), and pdir (parent dir) are all directory types
|
||||
if (strcasecmp(value, "dir") == 0 ||
|
||||
strcasecmp(value, "cdir") == 0 ||
|
||||
strcasecmp(value, "pdir") == 0)
|
||||
{
|
||||
dirEntry->isDir = true;
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(key, "size") == 0)
|
||||
{
|
||||
dirEntry->file_size = atoll(value);
|
||||
}
|
||||
else if (strcasecmp(key, "modify") == 0)
|
||||
{
|
||||
sscanf(value, "%4d%2d%2d%2d%2d%2d", &dirEntry->modified.year, &dirEntry->modified.month, &dirEntry->modified.day,
|
||||
&dirEntry->modified.hours, &dirEntry->modified.minutes, &dirEntry->modified.seconds);
|
||||
}
|
||||
}
|
||||
else if (strcasecmp(key, "size") == 0)
|
||||
{
|
||||
dirEntry->file_size = atoll(value);
|
||||
}
|
||||
else if (strcasecmp(key, "modify") == 0)
|
||||
{
|
||||
sscanf(value, "%4d%2d%2d%2d%2d%2d", &dirEntry->modified.year, &dirEntry->modified.month, &dirEntry->modified.day,
|
||||
&dirEntry->modified.hours, &dirEntry->modified.minutes, &dirEntry->modified.seconds);
|
||||
}
|
||||
keypair = strtok_r(NULL, ";", &factsSave);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -1744,7 +1806,7 @@ ClientType FtpClient::clientType()
|
||||
|
||||
uint32_t FtpClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
|
||||
std::string FtpClient::GetPath(std::string ppath1, std::string ppath2)
|
||||
@@ -1783,4 +1845,23 @@ int FtpClient::Head(const std::string &path, void *buffer, uint64_t len)
|
||||
if (l != len)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void *FtpClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FtpClient::Close(void *fp)
|
||||
{
|
||||
}
|
||||
|
||||
int FtpClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int FtpClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef FTPCLIENT_H
|
||||
#define FTPCLIENT_H
|
||||
#ifndef EZ_FTPCLIENT_H
|
||||
#define EZ_FTPCLIENT_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -67,7 +67,7 @@ public:
|
||||
|
||||
FtpClient();
|
||||
~FtpClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
void SetConnmode(connmode mode);
|
||||
int Site(const std::string &cmd);
|
||||
int Raw(const std::string &cmd);
|
||||
@@ -79,14 +79,19 @@ public:
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset = 0);
|
||||
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
int Copy(const std::string &from, const std::string &to);
|
||||
int Move(const std::string &from, const std::string &to);
|
||||
int Head(const std::string &path, void *buffer, uint64_t len);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void SetCallbackXferFunction(FtpCallbackXfer pointer);
|
||||
void SetCallbackArg(void *arg);
|
||||
@@ -109,12 +114,12 @@ private:
|
||||
char server[128];
|
||||
int server_port;
|
||||
|
||||
int FtpSendCmd(const std::string &cmd, char expected_resp, ftphandle *nControl);
|
||||
int FtpSendCmd(const std::string &cmd, const std::string &expected_resp, ftphandle *nControl);
|
||||
ftphandle *RawOpen(const std::string &path, accesstype type, transfermode mode);
|
||||
int RawClose(ftphandle *handle);
|
||||
int RawWrite(void *buf, int len, ftphandle *handle);
|
||||
int RawRead(void *buf, int max, ftphandle *handle);
|
||||
int ReadResponse(char c, ftphandle *nControl);
|
||||
int ReadResponse(const std::string &c, ftphandle *nControl);
|
||||
int Readline(char *buf, int max, ftphandle *nControl);
|
||||
int Writeline(char *buf, int len, ftphandle *nData);
|
||||
void ClearHandle();
|
||||
@@ -124,6 +129,7 @@ private:
|
||||
int CorrectPasvResponse(int *v);
|
||||
int FtpAccess(const std::string &path, accesstype type, transfermode mode, ftphandle *nControl, ftphandle **nData);
|
||||
int FtpXfer(const std::string &localfile, const std::string &path, ftphandle *nControl, accesstype type, transfermode mode);
|
||||
int FtpXfer(SplitFile *split_file, const std::string &path, ftphandle *nControl, accesstype type, transfermode mode);
|
||||
int FtpWrite(void *buf, int len, ftphandle *nData);
|
||||
int FtpRead(void *buf, int max, ftphandle *nData);
|
||||
int FtpClose(ftphandle *nData);
|
||||
@@ -131,4 +137,4 @@ private:
|
||||
int ParseMLSDDirEntry(char *line, DirEntry *dirEntry);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+231
-18
@@ -159,7 +159,7 @@ GDriveClient::GDriveClient()
|
||||
path_id_map.insert(std::make_pair("/" + shared_with_me, shared_with_me));
|
||||
}
|
||||
|
||||
int GDriveClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int GDriveClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
if (strlen(remote_settings->gg_account.refresh_token) > 0)
|
||||
{
|
||||
@@ -307,6 +307,7 @@ int GDriveClient::Get(const std::string &outputfile, const std::string &path, ui
|
||||
{
|
||||
std::ofstream file_stream(outputfile, std::ios::binary);
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
@@ -331,6 +332,34 @@ int GDriveClient::Get(const std::string &outputfile, const std::string &path, ui
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GDriveClient::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
|
||||
{
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::Escape(id) + "?alt=media";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
if (auto res = client->Get(url,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
if (!split_file->IsClosed())
|
||||
{
|
||||
split_file->Write((char*)data, data_length);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GDriveClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
@@ -399,10 +428,9 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
|
||||
{
|
||||
bytes_to_download = FS::GetSize(inputfile);
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
std::ifstream file_stream(inputfile, std::ios::binary);
|
||||
bytes_transfered = 0;
|
||||
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
|
||||
@@ -413,6 +441,7 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
|
||||
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
|
||||
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
|
||||
char *buf = new char[GOOGLE_BUF_SIZE];
|
||||
|
||||
if (auto res = client->Patch(url))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
@@ -428,8 +457,8 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
|
||||
upload_uri, bytes_to_download,
|
||||
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
uint64_t count = 0;
|
||||
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
do
|
||||
{
|
||||
file_stream.read(buf, bytes_to_transfer);
|
||||
@@ -442,7 +471,84 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
|
||||
},
|
||||
"application/octet-stream"))
|
||||
{
|
||||
// success
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
else if (res->status == 503)
|
||||
{
|
||||
// retry interrupted uploads
|
||||
int retries = 5;
|
||||
while (res->status == 503 && retries > 0)
|
||||
{
|
||||
// Send empty PUT request to get resume position
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Content-Range", "*/*"));
|
||||
auto resume_res = client->Put(upload_uri, headers, "", 0, "application/octet-stream");
|
||||
retries--;
|
||||
|
||||
if (HTTP_SUCCESS(resume_res->status))
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
else if (resume_res->status == 308)
|
||||
{
|
||||
std::string range_val = resume_res->get_header_value("Range");
|
||||
uint64_t resume_offset = std::stol(Util::Split(Util::Split(range_val, "=")[1], "-")[1]);
|
||||
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download-resume_offset)));
|
||||
std::string range_value = "bytes " + std::to_string(resume_offset + 1) + "_" + std::to_string(bytes_to_download-1);
|
||||
headers.insert(std::make_pair("Content-Range", range_value));
|
||||
file_stream.seekg(resume_offset+1);
|
||||
|
||||
|
||||
if (res = client->Put(upload_uri, bytes_to_download-resume_offset,
|
||||
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
do
|
||||
{
|
||||
file_stream.read(buf, bytes_to_transfer);
|
||||
if (sink.write(buf, bytes_to_transfer))
|
||||
{
|
||||
count += bytes_to_transfer;
|
||||
bytes_transfered += bytes_to_transfer;
|
||||
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (count < length);
|
||||
return true;
|
||||
},
|
||||
"application/octet-stream"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pause 5s before retrying
|
||||
sceKernelUsleep(5000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -473,10 +579,9 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
|
||||
|
||||
bytes_to_download = FS::GetSize(inputfile);
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
std::ifstream file_stream(inputfile, std::ios::binary);
|
||||
bytes_transfered = 0;
|
||||
|
||||
size_t path_pos = path.find_last_of("/");
|
||||
std::string parent_dir;
|
||||
if (path_pos == 0)
|
||||
@@ -499,7 +604,9 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
|
||||
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
|
||||
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
|
||||
char *buf = new char[GOOGLE_BUF_SIZE];
|
||||
if (auto res = client->Post(url, headers, post_data.c_str(), post_data.length(), "application/json"))
|
||||
|
||||
httplib::Result res;
|
||||
if (res = client->Post(url, headers, post_data.c_str(), post_data.length(), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
@@ -514,21 +621,104 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
|
||||
upload_uri, bytes_to_download,
|
||||
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
|
||||
{
|
||||
uint32_t count = 0;
|
||||
uint32_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
uint64_t count = 0;
|
||||
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
do
|
||||
{
|
||||
file_stream.read(buf, bytes_to_transfer);
|
||||
sink.write(buf, bytes_to_transfer);
|
||||
count += bytes_to_transfer;
|
||||
bytes_transfered += bytes_to_transfer;
|
||||
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
if (sink.write(buf, bytes_to_transfer))
|
||||
{
|
||||
count += bytes_to_transfer;
|
||||
bytes_transfered += bytes_to_transfer;
|
||||
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (count < length);
|
||||
return true;
|
||||
},
|
||||
"application/octet-stream"))
|
||||
{
|
||||
// success
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
else if (res->status == 503)
|
||||
{
|
||||
// retry interrupted uploads
|
||||
int retries = 5;
|
||||
while (res->status == 503)
|
||||
{
|
||||
// Send empty PUT request to get resume position
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Content-Range", "*/*"));
|
||||
retries--;
|
||||
|
||||
auto resume_res = client->Put(upload_uri, headers, "", 0, "application/octet-stream");
|
||||
|
||||
if (HTTP_SUCCESS(resume_res->status))
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
else if (resume_res->status == 308)
|
||||
{
|
||||
std::string range_val = resume_res->get_header_value("Range");
|
||||
uint64_t resume_offset = std::stol(Util::Split(Util::Split(range_val, "=")[1], "-")[1]);
|
||||
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download-resume_offset)));
|
||||
std::string range_value = "bytes " + std::to_string(resume_offset + 1) + "_" + std::to_string(bytes_to_download-1);
|
||||
headers.insert(std::make_pair("Content-Range", range_value));
|
||||
file_stream.seekg(resume_offset+1);
|
||||
|
||||
if (res = client->Put(upload_uri, bytes_to_download-resume_offset,
|
||||
[&file_stream, &buf](size_t offset, size_t length, DataSink &sink)
|
||||
{
|
||||
uint64_t count = 0;
|
||||
uint64_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
do
|
||||
{
|
||||
file_stream.read(buf, bytes_to_transfer);
|
||||
if (sink.write(buf, bytes_to_transfer))
|
||||
{
|
||||
count += bytes_to_transfer;
|
||||
bytes_transfered += bytes_to_transfer;
|
||||
bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (count < length);
|
||||
return true;
|
||||
},
|
||||
"application/octet-stream"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// pause 5s before retrying
|
||||
sceKernelUsleep(5000000);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -887,7 +1077,7 @@ ClientType GDriveClient::clientType()
|
||||
|
||||
uint32_t GDriveClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
|
||||
void *GDriveClient::RefreshTokenThread(void *argp)
|
||||
@@ -941,4 +1131,27 @@ void GDriveClient::SetAccessToken(const std::string &token)
|
||||
{
|
||||
if (this->client != nullptr)
|
||||
this->client->set_bearer_token_auth(token);
|
||||
}
|
||||
}
|
||||
|
||||
void *GDriveClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GDriveClient::Close(void *fp)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
}
|
||||
|
||||
int GDriveClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int GDriveClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef GDRIVE_H
|
||||
#define GDRIVE_H
|
||||
#ifndef EZ_GDRIVE_H
|
||||
#define EZ_GDRIVE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -17,11 +17,14 @@ class GDriveClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
GDriveClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
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 Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Head(const std::string &path, void *buffer, uint64_t len);
|
||||
int Update(const std::string &inputfile, const std::string &path);
|
||||
@@ -32,6 +35,8 @@ public:
|
||||
bool FileExists(const std::string &path);
|
||||
void SetAccessToken(const std::string &token);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
static void *RefreshTokenThread(void *argp);
|
||||
static void StartRefreshToken();
|
||||
static void StopRefreshToken();
|
||||
@@ -46,4 +51,4 @@ private:
|
||||
std::map<std::string, std::string> shared_drive_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
#include <json-c/json.h>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include "common.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/github.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
|
||||
using httplib::Client;
|
||||
using httplib::Headers;
|
||||
using httplib::Result;
|
||||
|
||||
int GithubClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
if (url.find("https://github.com") == std::string::npos)
|
||||
return 0;
|
||||
|
||||
this->host_url = "https://api.github.com";
|
||||
this->base_path = "/repos" + url.substr(18);
|
||||
Util::Rtrim(this->base_path, "/");
|
||||
this->base_path += "/releases";
|
||||
this->m_download_url = "https://github.com";
|
||||
|
||||
client = new httplib::Client(this->host_url);
|
||||
if (username.length() > 0)
|
||||
client->set_basic_auth(username, password);
|
||||
client->set_follow_location(true);
|
||||
client->set_connection_timeout(10);
|
||||
client->set_read_timeout(30);
|
||||
client->enable_server_certificate_verification(false);
|
||||
m_client.Connect("https://github.com", username, password);
|
||||
|
||||
if (!send_ping)
|
||||
this->connected = true;
|
||||
else if (Ping())
|
||||
this->connected = true;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<DirEntry> GithubClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
if (!ParseReleases())
|
||||
return out;
|
||||
|
||||
if (path.compare("/") == 0) // return releases as folders
|
||||
{
|
||||
for (std::vector<GitRelease>::iterator release = m_releases.begin(); release != m_releases.end();)
|
||||
{
|
||||
DirEntry entry;
|
||||
entry.isDir = true;
|
||||
entry.selectable = true;
|
||||
entry.file_size = 0;
|
||||
snprintf(entry.directory, 512, "%s", "/");
|
||||
snprintf(entry.name, 256, "%s", release->name.c_str());
|
||||
snprintf(entry.path, 768, "/%s", release->name.c_str());
|
||||
snprintf(entry.display_size, 48, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.modified = release->modified;
|
||||
|
||||
out.push_back(entry);
|
||||
release++;
|
||||
}
|
||||
}
|
||||
else // return assets in the releases matching the path
|
||||
{
|
||||
std::string tag_name = path.substr(1);
|
||||
std::map<std::string, GitAsset> assets = m_assets[tag_name];
|
||||
for (std::map<std::string, GitAsset>::iterator asset = assets.begin(); asset != assets.end();)
|
||||
{
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
entry.isDir = false;
|
||||
entry.selectable = true;
|
||||
snprintf(entry.directory, 512, "%s", path.c_str());
|
||||
snprintf(entry.name, 256, "%s", asset->second.name.c_str());
|
||||
snprintf(entry.path, 768, "%s/%s", path.c_str(), asset->second.name.c_str());
|
||||
entry.file_size = asset->second.size;
|
||||
entry.modified = asset->second.modified;
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
|
||||
out.push_back(entry);
|
||||
asset++;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int GithubClient::Size(const std::string &path, int64_t *size)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return 0;
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
*size = m_assets[path_parts[0]][path_parts[1]].size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GithubClient::Head(const std::string &path, void *buffer, uint64_t len)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return 0;
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_client.Head(m_assets[path_parts[0]][path_parts[1]].url, buffer, len);
|
||||
}
|
||||
|
||||
int GithubClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return 0;
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_client.Get(outputfile, m_assets[path_parts[0]][path_parts[1]].url, offset);
|
||||
}
|
||||
|
||||
int GithubClient::Get(SplitFile *split_file, const std::string &path, uint64_t offset)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return 0;
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_client.Get(split_file, m_assets[path_parts[0]][path_parts[1]].url, offset);
|
||||
}
|
||||
|
||||
int GithubClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return 0;
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_client.GetRange(m_assets[path_parts[0]][path_parts[1]].url, buffer, size, offset);
|
||||
}
|
||||
|
||||
int GithubClient::GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return 0;
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_client.GetRange(m_assets[path_parts[0]][path_parts[1]].url, sink, size, offset);
|
||||
}
|
||||
|
||||
bool GithubClient::ParseReleases()
|
||||
{
|
||||
if (!releases_parsed)
|
||||
{
|
||||
if (auto res = client->Get(this->base_path + "?per_page=100&page=1"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
struct array_list *areleases = json_object_get_array(jobj);
|
||||
|
||||
for (size_t release_idx = 0; release_idx < areleases->length; ++release_idx)
|
||||
{
|
||||
GitRelease release_entry;
|
||||
|
||||
json_object *release = (json_object *)array_list_get_idx(areleases, release_idx);
|
||||
release_entry.name = std::string(json_object_get_string(json_object_object_get(release, "tag_name")));
|
||||
std::string date_time = std::string(json_object_get_string(json_object_object_get(release, "published_at")));
|
||||
|
||||
auto date_time_array = Util::Split(date_time, "T");
|
||||
auto date_array = Util::Split(date_time_array[0], "-");
|
||||
auto time_array = Util::Split(date_time_array[1], ":");
|
||||
release_entry.modified.year = std::atoi(date_array[0].c_str());
|
||||
release_entry.modified.month = std::atoi(date_array[1].c_str());
|
||||
release_entry.modified.day = std::atoi(date_array[2].c_str());
|
||||
release_entry.modified.hours = std::atoi(time_array[0].c_str());
|
||||
release_entry.modified.minutes = std::atoi(time_array[1].c_str());
|
||||
release_entry.modified.seconds = std::atoi(time_array[2].substr(0,2).c_str());
|
||||
|
||||
json_object *obj_assets = json_object_object_get(release, "assets");
|
||||
if (json_object_get_type(obj_assets) == json_type_array)
|
||||
{
|
||||
struct array_list *aassets = json_object_get_array(obj_assets);
|
||||
std::map<std::string, GitAsset> assets;
|
||||
|
||||
for (size_t asset_idx = 0; asset_idx < aassets->length; ++asset_idx)
|
||||
{
|
||||
GitAsset asset_entry;
|
||||
|
||||
json_object *asset = (json_object *)array_list_get_idx(aassets, asset_idx);
|
||||
asset_entry.name = std::string(json_object_get_string(json_object_object_get(asset, "name")));
|
||||
asset_entry.size = json_object_get_uint64(json_object_object_get(asset, "size"));
|
||||
std::string date_time = std::string(json_object_get_string(json_object_object_get(asset, "updated_at")));
|
||||
asset_entry.url = std::string(json_object_get_string(json_object_object_get(asset, "browser_download_url")));
|
||||
Util::ReplaceAll(asset_entry.url, "https://github.com", "");
|
||||
|
||||
auto date_time_array = Util::Split(date_time, "T");
|
||||
auto date_array = Util::Split(date_time_array[0], "-");
|
||||
auto time_array = Util::Split(date_time_array[1], ":");
|
||||
asset_entry.modified.year = std::atoi(date_array[0].c_str());
|
||||
asset_entry.modified.month = std::atoi(date_array[1].c_str());
|
||||
asset_entry.modified.day = std::atoi(date_array[2].c_str());
|
||||
asset_entry.modified.hours = std::atoi(time_array[0].c_str());
|
||||
asset_entry.modified.minutes = std::atoi(time_array[1].c_str());
|
||||
asset_entry.modified.seconds = std::atoi(time_array[2].substr(0,2).c_str());
|
||||
|
||||
assets.insert(std::make_pair(asset_entry.name, asset_entry));
|
||||
}
|
||||
|
||||
m_assets.insert(std::make_pair(release_entry.name, assets));
|
||||
}
|
||||
|
||||
m_releases.push_back(release_entry);
|
||||
}
|
||||
|
||||
releases_parsed = true;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string GithubClient::GetDownloadUrl(const std::string &path)
|
||||
{
|
||||
if (!ParseReleases())
|
||||
return "";
|
||||
|
||||
std::vector<std::string> path_parts = Util::Split(path, "/");
|
||||
|
||||
if (path_parts.size() != 2)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return this->m_download_url + Escape(m_assets[path_parts[0]][path_parts[1]].url);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef EZ_GITHUB_H
|
||||
#define EZ_GITHUB_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
|
||||
class GithubClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int Get(SplitFile *split_file, 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 Head(const std::string &path, void *buffer, uint64_t len);
|
||||
std::string GetDownloadUrl(const std::string &path);
|
||||
|
||||
private:
|
||||
struct GitAsset
|
||||
{
|
||||
std::string name;
|
||||
std::string url;
|
||||
DateTime modified;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
struct GitRelease
|
||||
{
|
||||
std::string name;
|
||||
DateTime modified;
|
||||
};
|
||||
|
||||
std::vector<GitRelease> m_releases;
|
||||
std::map<std::string, std::map<std::string, GitAsset>> m_assets;
|
||||
bool releases_parsed = false;
|
||||
std::string m_download_url;
|
||||
BaseClient m_client;
|
||||
|
||||
bool ParseReleases();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef IIS_H
|
||||
#define IIS_H
|
||||
#ifndef EZ_IIS_H
|
||||
#define EZ_IIS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <lexbor/dom/interfaces/node.h>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include "common.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/myrient.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "system.h"
|
||||
#include "windows.h"
|
||||
|
||||
using httplib::Client;
|
||||
using httplib::Headers;
|
||||
using httplib::Result;
|
||||
|
||||
static std::map<std::string, int> month_map = {{"Jan", 1}, {"Feb", 2}, {"Mar", 3}, {"Apr", 4}, {"May", 5}, {"Jun", 6}, {"Jul", 7}, {"Aug", 8}, {"Sep", 9}, {"Oct", 10}, {"Nov", 11}, {"Dec", 12}};
|
||||
|
||||
std::vector<DirEntry> MyrientClient::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 *table_element, *tr_element, *td_element;
|
||||
lxb_html_document_t *document;
|
||||
lxb_dom_collection_t *table_collection;
|
||||
lxb_dom_collection_t *tr_collection;
|
||||
lxb_dom_collection_t *td_collection;
|
||||
std::string tmp_string;
|
||||
const lxb_char_t *value;
|
||||
size_t value_len;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
table_collection = lxb_dom_collection_make(&document->dom_document, 1);
|
||||
if (table_collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
tr_collection = lxb_dom_collection_make(&document->dom_document, 128);
|
||||
if (tr_collection == NULL)
|
||||
{
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(lxb_dom_interface_element(document->body),
|
||||
table_collection, (const lxb_char_t *)"table", 5);
|
||||
if (status != LXB_STATUS_OK)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (lxb_dom_collection_length(table_collection) < 1)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < lxb_dom_collection_length(table_collection); i++)
|
||||
{
|
||||
table_element = lxb_dom_collection_element(table_collection, i);
|
||||
value = lxb_dom_element_id(table_element, &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("list") == 0)
|
||||
break;
|
||||
table_element = nullptr;
|
||||
}
|
||||
|
||||
if (table_element == nullptr)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
status = lxb_dom_elements_by_tag_name(table_element,
|
||||
tr_collection, (const lxb_char_t *)"tr", 2);
|
||||
if (status != LXB_STATUS_OK && lxb_dom_collection_length(tr_collection) < 2)
|
||||
{
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// skip row 0 , since it has the previous folder header
|
||||
for (size_t i = 2; i < lxb_dom_collection_length(tr_collection); i++)
|
||||
{
|
||||
DirEntry entry;
|
||||
std::string title, aclass;
|
||||
memset(&entry.modified, 0, sizeof(DateTime));
|
||||
|
||||
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) < 3)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
// td0 contains the <a> tag
|
||||
td_element = lxb_dom_collection_element(td_collection, 0);
|
||||
lxb_dom_node_t *a_node = NextChildElement(td_element);
|
||||
value = lxb_dom_element_local_name(lxb_dom_interface_element(a_node), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
if (tmp_string.compare("a") != 0)
|
||||
{
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
goto finish;
|
||||
}
|
||||
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::UnEscape(tmp_string);
|
||||
sprintf(entry.name, "%s", tmp_string.c_str());
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
if (path.length() > 0 && path[path.length() - 1] == '/')
|
||||
{
|
||||
sprintf(entry.path, "%s%s", path.c_str(), entry.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
|
||||
}
|
||||
|
||||
// next td contains file size, if fize size is "-", then it's a directory
|
||||
td_element = lxb_dom_collection_element(td_collection, 1);
|
||||
value = lxb_dom_node_text_content(NextChildTextNode(td_element), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
|
||||
if (tmp_string.compare("-") == 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;
|
||||
uint64_t multiplier = 1;
|
||||
std::vector<std::string> fsize_parts = Util::Split(tmp_string, " ");
|
||||
|
||||
float fsize = std::stof(fsize_parts[0]);
|
||||
|
||||
if (fsize_parts.size() > 1)
|
||||
{
|
||||
switch (fsize_parts[1][0])
|
||||
{
|
||||
case 'K':
|
||||
multiplier = 1024;
|
||||
break;
|
||||
case 'M':
|
||||
multiplier = 1048576;
|
||||
break;
|
||||
case 'G':
|
||||
multiplier = 1073741824;
|
||||
break;
|
||||
default:
|
||||
multiplier = 1;
|
||||
}
|
||||
}
|
||||
entry.file_size = fsize * multiplier;
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
}
|
||||
|
||||
// next td contains the date
|
||||
td_element = lxb_dom_collection_element(td_collection, 2);
|
||||
value = lxb_dom_node_text_content(NextChildTextNode(td_element), &value_len);
|
||||
tmp_string = std::string((const char *)value, value_len);
|
||||
std::vector<std::string> date_time = Util::Split(tmp_string, " ");
|
||||
|
||||
if (date_time.size() > 1)
|
||||
{
|
||||
std::vector<std::string> adate = Util::Split(date_time[0], "-");
|
||||
if (adate.size() == 3)
|
||||
{
|
||||
entry.modified.day = atoi(adate[0].c_str());
|
||||
entry.modified.month = month_map[adate[1]];
|
||||
entry.modified.year = atoi(adate[2].c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> atime = Util::Split(date_time[1], ":");
|
||||
if (atime.size() == 2)
|
||||
{
|
||||
entry.modified.hours = atoi(atime[0].c_str());
|
||||
entry.modified.minutes = atoi(atime[1].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(td_collection, true);
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0)
|
||||
{
|
||||
out.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
lxb_dom_collection_destroy(tr_collection, true);
|
||||
lxb_dom_collection_destroy(table_collection, true);
|
||||
lxb_html_document_destroy(document);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
return out;
|
||||
}
|
||||
|
||||
finish:
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef EZ_MYRIENT_H
|
||||
#define EZ_MYRIENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
|
||||
class MyrientClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
};
|
||||
|
||||
#endif
|
||||
+125
-45
@@ -17,7 +17,7 @@
|
||||
#include "util.h"
|
||||
#include "system.h"
|
||||
|
||||
#define BUF_SIZE 256*1024
|
||||
#define BUF_SIZE 256 * 1024
|
||||
|
||||
NfsClient::NfsClient()
|
||||
{
|
||||
@@ -27,7 +27,7 @@ NfsClient::~NfsClient()
|
||||
{
|
||||
}
|
||||
|
||||
int NfsClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int NfsClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
nfs = nfs_init_context();
|
||||
if (nfs == nullptr)
|
||||
@@ -37,7 +37,8 @@ int NfsClient::Connect(const std::string &url, const std::string &user, const st
|
||||
}
|
||||
|
||||
struct nfs_url *nfsurl = nfs_parse_url_full(nfs, url.c_str());
|
||||
if (nfsurl == nullptr) {
|
||||
if (nfsurl == nullptr)
|
||||
{
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
nfs_destroy_context(nfs);
|
||||
return 0;
|
||||
@@ -203,7 +204,7 @@ int NfsClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE* out = FS::Create(outputfile);
|
||||
FILE *out = FS::Create(outputfile);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
@@ -213,6 +214,7 @@ int NfsClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
void *buff = malloc(BUF_SIZE);
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
while ((count = nfs_read(nfs, nfsfh, BUF_SIZE, buff)) > 0)
|
||||
{
|
||||
if (count < 0)
|
||||
@@ -220,7 +222,7 @@ int NfsClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
FS::Close(out);
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void*)buff);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
FS::Write(out, buff, count);
|
||||
@@ -228,7 +230,42 @@ int NfsClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
}
|
||||
FS::Close(out);
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void*)buff);
|
||||
free((void *)buff);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NfsClient::Get(SplitFile *split_file, const std::string &ppath, uint64_t offset)
|
||||
{
|
||||
struct nfsfh *nfsfh = nullptr;
|
||||
int ret = nfs_open(nfs, ppath.c_str(), 0400, &nfsfh);
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *buff = malloc(BUF_SIZE);
|
||||
int count = 0;
|
||||
while ((count = nfs_read(nfs, nfsfh, BUF_SIZE, buff)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
ret = split_file->Write((char *)buff, count);
|
||||
if (ret < 0)
|
||||
{
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
nfs_close(nfs, nfsfh);
|
||||
free((void *)buff);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -242,49 +279,51 @@ int NfsClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
ret = this->GetRange((void *)nfsfh, sink, size, offset);
|
||||
nfs_close(nfs, nfsfh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NfsClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct nfsfh *nfsfh = (struct nfsfh *)fp;
|
||||
|
||||
int ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
free((void *)buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NfsClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
if (!FileExists(ppath))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nfsfh *nfsfh = nullptr;
|
||||
int ret = nfs_open(nfs, ppath.c_str(), 0400, &nfsfh);
|
||||
if (ret != 0)
|
||||
@@ -293,18 +332,45 @@ int NfsClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
ret = this->GetRange(nfsfh, buffer, size, offset);
|
||||
nfs_close(nfs, nfsfh);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NfsClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct nfsfh *nfsfh = (struct nfsfh *)fp;
|
||||
|
||||
int ret = nfs_lseek(nfs, nfsfh, offset, SEEK_SET, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = nfs_read(nfs, nfsfh, size, buffer);
|
||||
nfs_close(nfs, nfsfh);
|
||||
if (count != size)
|
||||
return 0;
|
||||
size_t bytes_remaining = size;
|
||||
char *buff = (char*)buffer;
|
||||
int total = 0;
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
count = nfs_read(nfs, nfsfh, bytes_remaining, buff);
|
||||
if (count > 0)
|
||||
{
|
||||
bytes_remaining -= count;
|
||||
buff += count;
|
||||
total += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (total != size)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -346,13 +412,13 @@ int NfsClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE* in = FS::OpenRead(inputfile);
|
||||
FILE *in = FS::OpenRead(inputfile);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct nfsfh *nfsfh = nullptr;
|
||||
int ret;
|
||||
if (!FileExists(ppath))
|
||||
@@ -368,14 +434,15 @@ int NfsClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* buff = malloc(BUF_SIZE);
|
||||
uint64_t count = 0;
|
||||
void *buff = malloc(BUF_SIZE);
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
while ((count = FS::Read(in, buff, BUF_SIZE)) > 0)
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
while ((count = FS::Read(in, buff, BUF_SIZE)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
nfs_close(nfs, nfsfh);
|
||||
free(buff);
|
||||
@@ -446,7 +513,8 @@ std::vector<DirEntry> NfsClient::ListDir(const std::string &path)
|
||||
struct nfsdirent *nfsdirent;
|
||||
|
||||
int ret = nfs_opendir(nfs, path.c_str(), &nfsdir);
|
||||
if (ret != 0) {
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", nfs_get_error(nfs));
|
||||
return out;
|
||||
}
|
||||
@@ -513,7 +581,6 @@ std::vector<DirEntry> NfsClient::ListDir(const std::string &path)
|
||||
}
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0)
|
||||
out.push_back(entry);
|
||||
|
||||
}
|
||||
nfs_closedir(nfs, nfsdir);
|
||||
|
||||
@@ -553,6 +620,19 @@ int NfsClient::Head(const std::string &ppath, void *buffer, uint64_t len)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *NfsClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
struct nfsfh *nfsfh = nullptr;
|
||||
nfs_open(nfs, path.c_str(), 0400, &nfsfh);
|
||||
;
|
||||
return nfsfh;
|
||||
}
|
||||
|
||||
void NfsClient::Close(void *fp)
|
||||
{
|
||||
nfs_close(nfs, (struct nfsfh *)fp);
|
||||
}
|
||||
|
||||
ClientType NfsClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_NFS;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef NFSCLIENT_H
|
||||
#define NFSCLIENT_H
|
||||
#ifndef EZ_NFSCLIENT_H
|
||||
#define EZ_NFSCLIENT_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -18,13 +18,16 @@ class NfsClient : public RemoteClient
|
||||
public:
|
||||
NfsClient();
|
||||
~NfsClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
@@ -32,6 +35,8 @@ public:
|
||||
int Copy(const std::string &from, const std::string &to);
|
||||
int Move(const std::string &from, const std::string &to);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
@@ -48,4 +53,4 @@ private:
|
||||
bool connected = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef NGINX_H
|
||||
#define NGINX_H
|
||||
#ifndef EZ_NGINX_H
|
||||
#define EZ_NGINX_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef NPXSERVE_H
|
||||
#define NPXSERVE_H
|
||||
#ifndef EZ_NPXSERVE_H
|
||||
#define EZ_NPXSERVE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef RCLONE_H
|
||||
#define RCLONE_H
|
||||
#ifndef EZ_RCLONE_H
|
||||
#define EZ_RCLONE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#ifndef REMOTECLIENT_H
|
||||
#define REMOTECLIENT_H
|
||||
#ifndef EZ_REMOTECLIENT_H
|
||||
#define EZ_REMOTECLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common.h"
|
||||
#include "http/httplib.h"
|
||||
#include "split_file.h"
|
||||
|
||||
enum RemoteActions
|
||||
{
|
||||
@@ -21,7 +22,8 @@ enum RemoteActions
|
||||
REMOTE_ACTION_EDIT = 512,
|
||||
REMOTE_ACTION_NEW_FILE = 1024,
|
||||
REMOTE_ACTION_EXTRACT = 2048,
|
||||
REMOTE_ACTION_ALL = 4095
|
||||
REMOTE_ACTION_RAW_READ = 4096,
|
||||
REMOTE_ACTION_ALL = 8191
|
||||
};
|
||||
|
||||
enum ClientType
|
||||
@@ -33,6 +35,7 @@ enum ClientType
|
||||
CLIENT_TYPE_HTTP_SERVER,
|
||||
CLIENT_TYPE_GOOGLE,
|
||||
CLIENT_TYPE_NFS,
|
||||
CLIENT_TYPE_FILEHOST,
|
||||
CLINET_TYPE_UNKNOWN
|
||||
};
|
||||
|
||||
@@ -43,11 +46,12 @@ class RemoteClient
|
||||
public:
|
||||
RemoteClient(){};
|
||||
virtual ~RemoteClient(){};
|
||||
virtual int Connect(const std::string &url, const std::string &username, const std::string &password) = 0;
|
||||
virtual int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false) = 0;
|
||||
virtual int Mkdir(const std::string &path) = 0;
|
||||
virtual int Rmdir(const std::string &path, bool recursive) = 0;
|
||||
virtual int Size(const std::string &path, int64_t *size) = 0;
|
||||
virtual int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0) = 0;
|
||||
virtual int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0) = 0;
|
||||
virtual int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0) = 0;
|
||||
virtual int Rename(const std::string &src, const std::string &dst) = 0;
|
||||
virtual int Delete(const std::string &path) = 0;
|
||||
@@ -56,8 +60,12 @@ public:
|
||||
virtual int Head(const std::string &path, void *buffer, uint64_t len) = 0;
|
||||
virtual int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset) = 0;
|
||||
virtual int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset) = 0;
|
||||
virtual int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset) = 0;
|
||||
virtual int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset) = 0;
|
||||
virtual bool FileExists(const std::string &path) = 0;
|
||||
virtual std::vector<DirEntry> ListDir(const std::string &path) = 0;
|
||||
virtual void *Open(const std::string &path, int flags) = 0;
|
||||
virtual void Close(void *fp) = 0;
|
||||
virtual std::string GetPath(std::string path1, std::string path2) = 0;
|
||||
virtual bool IsConnected() = 0;
|
||||
virtual bool Ping() = 0;
|
||||
@@ -67,4 +75,4 @@ public:
|
||||
virtual uint32_t SupportedActions() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -23,7 +23,7 @@ SFTPClient::SFTPClient()
|
||||
|
||||
SFTPClient::~SFTPClient(){};
|
||||
|
||||
int SFTPClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
int SFTPClient::Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping)
|
||||
{
|
||||
int port = 22;
|
||||
std::string host = url.substr(7);
|
||||
@@ -284,6 +284,8 @@ int SFTPClient::Get(const std::string &outputfile, const std::string &path, uint
|
||||
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
int rc, count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
do
|
||||
{
|
||||
rc = libssh2_sftp_read(sftp_handle, buff, FTP_CLIENT_BUFSIZ);
|
||||
@@ -304,6 +306,36 @@ int SFTPClient::Get(const std::string &outputfile, const std::string &path, uint
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Get(SplitFile *split_file, const std::string &path, 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;
|
||||
}
|
||||
|
||||
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
int rc, count = 0;
|
||||
|
||||
do
|
||||
{
|
||||
rc = libssh2_sftp_read(sftp_handle, buff, FTP_CLIENT_BUFSIZ);
|
||||
if (rc > 0)
|
||||
{
|
||||
split_file->Write(buff, rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
free((char *)buff);
|
||||
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);
|
||||
@@ -313,6 +345,16 @@ int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange((void *)sftp_handle, sink, size, offset);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SFTPClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = (LIBSSH2_SFTP_HANDLE *)fp;
|
||||
|
||||
libssh2_sftp_seek64(sftp_handle, offset);
|
||||
|
||||
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
@@ -329,7 +371,6 @@ int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
if (!ok)
|
||||
{
|
||||
free((char *)buff);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -340,9 +381,8 @@ int SFTPClient::GetRange(const std::string &path, DataSink &sink, uint64_t size,
|
||||
} while (1);
|
||||
|
||||
free((char *)buff);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
@@ -359,9 +399,18 @@ int SFTPClient::GetRange(const std::string &path, void *buffer, uint64_t size, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange(sftp_handle, buffer, size, offset);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SFTPClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = (LIBSSH2_SFTP_HANDLE *)fp;
|
||||
|
||||
libssh2_sftp_seek64(sftp_handle, offset);
|
||||
int count = libssh2_sftp_read(sftp_handle, (char *)buffer, size);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
if (count != size)
|
||||
return 0;
|
||||
|
||||
@@ -401,6 +450,8 @@ int SFTPClient::Put(const std::string &inputfile, const std::string &path, uint6
|
||||
buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
int nread, count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
do
|
||||
{
|
||||
nread = FS::Read(in, buff, FTP_CLIENT_BUFSIZ);
|
||||
@@ -642,6 +693,16 @@ int SFTPClient::Quit()
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *SFTPClient::Open(const std::string &path, int flags)
|
||||
{
|
||||
return libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
|
||||
}
|
||||
|
||||
void SFTPClient::Close(void *fp)
|
||||
{
|
||||
libssh2_sftp_close((LIBSSH2_SFTP_HANDLE *)fp);
|
||||
}
|
||||
|
||||
ClientType SFTPClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_SFTP;
|
||||
@@ -650,4 +711,4 @@ ClientType SFTPClient::clientType()
|
||||
uint32_t SFTPClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SFTPCLIENT_H
|
||||
#define SFTPCLIENT_H
|
||||
#ifndef EZ_SFTPCLIENT_H
|
||||
#define EZ_SFTPCLIENT_H
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
@@ -14,14 +14,17 @@ class SFTPClient : public RemoteClient
|
||||
public:
|
||||
SFTPClient();
|
||||
~SFTPClient();
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Rmdir(const std::string &path);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
@@ -30,6 +33,8 @@ public:
|
||||
int Head(const std::string &path, void *buffer, uint64_t len);
|
||||
bool FileExists(const std::string &path);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
std::string GetPath(std::string path1, std::string path2);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
@@ -46,4 +51,4 @@ protected:
|
||||
bool connected = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+180
-54
@@ -24,34 +24,43 @@ SmbClient::~SmbClient()
|
||||
{
|
||||
}
|
||||
|
||||
int SmbClient::Connect(const std::string &url, const std::string &user, const std::string &pass)
|
||||
int SmbClient::Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
struct smb2_url *smb_url;
|
||||
|
||||
smb2 = smb2_init_context();
|
||||
if (smb2 == NULL)
|
||||
{
|
||||
sprintf(response, "Failed to init SMB context");
|
||||
snprintf(response, sizeof(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");
|
||||
if (smb_url != NULL)
|
||||
smb2_destroy_url(smb_url);
|
||||
smb2_destroy_context(smb2);
|
||||
smb2 = NULL;
|
||||
snprintf(response, sizeof(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);
|
||||
smb2_set_version(smb2, SMB2_VERSION_ANY);
|
||||
smb2_set_timeout(smb2, 30);
|
||||
|
||||
if (smb2_connect_share(smb2, smb_url->server, smb_url->share, user.c_str()) < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
smb2_destroy_url(smb_url);
|
||||
smb2_destroy_context(smb2);
|
||||
smb2 = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
smb2_destroy_url(smb_url);
|
||||
max_read_size = smb2_get_max_read_size(smb2);
|
||||
max_write_size = smb2_get_max_write_size(smb2);
|
||||
@@ -109,7 +118,7 @@ int SmbClient::Mkdir(const std::string &ppath)
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_mkdir(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -126,7 +135,7 @@ int SmbClient::_Rmdir(const std::string &ppath)
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_rmdir(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -193,32 +202,42 @@ int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
path = Util::Trim(path, "/");
|
||||
if (!Size(path.c_str(), &bytes_to_download))
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE* out = FS::Create(outputfile);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t*)malloc(max_read_size);
|
||||
if (buff == NULL)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
FS::Close(out);
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
@@ -233,44 +252,94 @@ int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SmbClient::Get(SplitFile *split_file, const std::string &ppath, 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)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t *)malloc(max_read_size);
|
||||
if (buff == NULL)
|
||||
{
|
||||
smb2_close(smb2, in);
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) != 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
if (split_file->Write((char*)buff, count) < 0)
|
||||
{
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
smb2_close(smb2, in);
|
||||
free((void *)buff);
|
||||
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);
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
|
||||
int ret = this->GetRange((void *)in, sink, size, offset);
|
||||
smb2_close(smb2, in);
|
||||
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SmbClient::GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct smb2fh *in = (struct smb2fh *)fp;
|
||||
|
||||
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
|
||||
|
||||
uint8_t *buff = (uint8_t *)malloc(max_read_size);
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
free((char *)buff);
|
||||
smb2_close(smb2, in);
|
||||
free((char *)buff);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -285,19 +354,45 @@ int SmbClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, u
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ret = this->GetRange(in, buffer, size, offset);
|
||||
smb2_close(smb2, in);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SmbClient::GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
struct smb2fh *in = (struct smb2fh *)fp;
|
||||
|
||||
smb2_lseek(smb2, in, offset, SEEK_SET, NULL);
|
||||
|
||||
int count = smb2_read(smb2, in, (uint8_t*)buffer, size);
|
||||
smb2_close(smb2, in);
|
||||
if (count != size)
|
||||
size_t bytes_remaining = size;
|
||||
uint8_t *buff = (uint8_t*)buffer;
|
||||
int count = 0;
|
||||
uint64_t total = 0;
|
||||
do
|
||||
{
|
||||
count = smb2_read(smb2, in, buff, bytes_remaining);
|
||||
if (count > 0)
|
||||
{
|
||||
bytes_remaining -= count;
|
||||
buff += count;
|
||||
total += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
if (total != size)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -323,14 +418,14 @@ int SmbClient::CopyToSocket(const std::string &ppath, int socket_fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), O_RDONLY);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t *buff = (uint8_t*)malloc(max_read_size);
|
||||
uint8_t *buff = (uint8_t *)malloc(max_read_size);
|
||||
int count = 0;
|
||||
while ((count = smb2_read(smb2, in, buff, max_read_size)) > 0)
|
||||
{
|
||||
@@ -338,7 +433,7 @@ int SmbClient::CopyToSocket(const std::string &ppath, int socket_fd)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
free((void *)buff);
|
||||
return 0;
|
||||
}
|
||||
int ret = sceNetSend(socket_fd, buff, count, 0);
|
||||
@@ -348,7 +443,7 @@ int SmbClient::CopyToSocket(const std::string &ppath, int socket_fd)
|
||||
}
|
||||
}
|
||||
smb2_close(smb2, in);
|
||||
free((void*)buff);
|
||||
free((void *)buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -360,7 +455,7 @@ bool SmbClient::FileExists(const std::string &ppath)
|
||||
int ret = smb2_stat(smb2, path.c_str(), &st);
|
||||
if (ret != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -387,31 +482,48 @@ int SmbClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
FILE* in = FS::OpenRead(inputfile);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct smb2fh* out = smb2_open(smb2, path.c_str(), O_WRONLY | O_CREAT | O_TRUNC);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
FS::Close(in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* buff = (uint8_t*)malloc(max_write_size);
|
||||
if (buff == NULL)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
return 0;
|
||||
}
|
||||
int count = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while ((count = FS::Read(in, buff, max_write_size)) > 0)
|
||||
{
|
||||
if (count < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
snprintf(response, sizeof(response), "%s", lang_strings[STR_FAILED]);
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
if (smb2_write(smb2, out, buff, count) < 0)
|
||||
{
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
FS::Close(in);
|
||||
smb2_close(smb2, out);
|
||||
free(buff);
|
||||
return 0;
|
||||
}
|
||||
smb2_write(smb2, out, buff, count);
|
||||
bytes_transfered += count;
|
||||
}
|
||||
FS::Close(in);
|
||||
@@ -419,7 +531,6 @@ int SmbClient::Put(const std::string &inputfile, const std::string &ppath, uint6
|
||||
free(buff);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int SmbClient::Rename(const std::string &src, const std::string &dst)
|
||||
@@ -430,7 +541,7 @@ int SmbClient::Rename(const std::string &src, const std::string &dst)
|
||||
path2 = Util::Trim(path2, "/");
|
||||
if (smb2_rename(smb2, path1.c_str(), path2.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -443,7 +554,7 @@ int SmbClient::Delete(const std::string &ppath)
|
||||
path = Util::Trim(path, "/");
|
||||
if (smb2_unlink(smb2, path.c_str()) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -457,7 +568,7 @@ int SmbClient::Size(const std::string &ppath, int64_t *size)
|
||||
smb2_stat_64 st;
|
||||
if (smb2_stat(smb2, path.c_str(), &st) != 0)
|
||||
{
|
||||
sprintf(response, "%s", smb2_get_error(smb2));
|
||||
snprintf(response, sizeof(response), "%s", smb2_get_error(smb2));
|
||||
return 0;
|
||||
}
|
||||
*size = st.smb2_size;
|
||||
@@ -526,7 +637,8 @@ std::vector<DirEntry> SmbClient::ListDir(const std::string &path)
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
break;
|
||||
}
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0)
|
||||
if (strcmp(entry.name, "..") != 0 && strcmp(entry.name, ".") != 0 &&
|
||||
(show_hidden_files || entry.name[0] != '.'))
|
||||
out.push_back(entry);
|
||||
}
|
||||
smb2_closedir(smb2, dir);
|
||||
@@ -559,14 +671,28 @@ int SmbClient::Head(const std::string &ppath, void *buffer, uint64_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = smb2_read(smb2, in, (uint8_t*)buffer, len);
|
||||
uint64_t count = smb2_read(smb2, in, (uint8_t*)buffer, len);
|
||||
smb2_close(smb2, in);
|
||||
if (count != len)
|
||||
if (count < 0 || count != len)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *SmbClient::Open(const std::string &ppath, int flags)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
|
||||
struct smb2fh *in = smb2_open(smb2, path.c_str(), flags);
|
||||
return in;
|
||||
}
|
||||
|
||||
void SmbClient::Close(void *fp)
|
||||
{
|
||||
smb2_close(smb2, (struct smb2fh *)fp);
|
||||
}
|
||||
|
||||
ClientType SmbClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_SMB;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SMBCLIENT_H
|
||||
#define SMBCLIENT_H
|
||||
#ifndef EZ_SMBCLIENT_H
|
||||
#define EZ_SMBCLIENT_H
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -19,13 +19,16 @@ class SmbClient : public RemoteClient
|
||||
public:
|
||||
SmbClient();
|
||||
~SmbClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int Get(SplitFile *split_file, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(const std::string &path, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, void *buffer, uint64_t size, uint64_t offset);
|
||||
int GetRange(void *fp, DataSink &sink, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
@@ -34,6 +37,8 @@ public:
|
||||
int Move(const std::string &from, const std::string &to);
|
||||
int CopyToSocket(const std::string &path, int socket_fd);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
void *Open(const std::string &path, int flags);
|
||||
void Close(void *fp);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
@@ -52,4 +57,4 @@ private:
|
||||
uint32_t max_write_size = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+58
-17
@@ -10,10 +10,10 @@
|
||||
#include "windows.h"
|
||||
|
||||
using httplib::Client;
|
||||
using httplib::ContentProvider;
|
||||
using httplib::Headers;
|
||||
using httplib::Progress;
|
||||
using httplib::Result;
|
||||
using httplib::ContentProvider;
|
||||
|
||||
static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
@@ -24,10 +24,10 @@ std::string WebDAVClient::GetHttpUrl(std::string url)
|
||||
return http_url;
|
||||
}
|
||||
|
||||
int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass)
|
||||
int WebDAVClient::Connect(const std::string &host, const std::string &user, const std::string &pass, bool send_ping)
|
||||
{
|
||||
std::string url = GetHttpUrl(host);
|
||||
return BaseClient::Connect(url, user, pass);
|
||||
return BaseClient::Connect(url, user, pass, send_ping);
|
||||
}
|
||||
|
||||
Result WebDAVClient::PropFind(const std::string &path, int depth)
|
||||
@@ -43,6 +43,50 @@ Result WebDAVClient::PropFind(const std::string &path, int depth)
|
||||
return client->send(req);
|
||||
}
|
||||
|
||||
int WebDAVClient::Size(const std::string &path, int64_t *size)
|
||||
{
|
||||
std::string encoded_path = httplib::detail::encode_url(GetFullPath(path));
|
||||
if (auto res = PropFind(encoded_path, 0))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
pugi::xml_document document;
|
||||
document.load_buffer(res->body.c_str(), res->body.length());
|
||||
auto multistatus = document.select_node("*[local-name()='multistatus']").node();
|
||||
auto responses = multistatus.select_nodes("*[local-name()='response']");
|
||||
for (auto response : responses)
|
||||
{
|
||||
pugi::xml_node href = response.node().select_node("*[local-name()='href']").node();
|
||||
std::string resource_path = httplib::detail::decode_url(href.first_child().value(), true);
|
||||
|
||||
auto target_path_without_sep = GetFullPath(path);
|
||||
if (!target_path_without_sep.empty() && target_path_without_sep.back() == '/')
|
||||
target_path_without_sep.resize(target_path_without_sep.length() - 1);
|
||||
auto resource_path_without_sep = resource_path.erase(resource_path.find_last_not_of('/') + 1);
|
||||
size_t pos = resource_path_without_sep.find(this->host_url);
|
||||
if (pos != std::string::npos)
|
||||
resource_path_without_sep.erase(pos, this->host_url.length());
|
||||
|
||||
if (resource_path_without_sep != target_path_without_sep)
|
||||
continue;
|
||||
|
||||
auto propstat = response.node().select_node("*[local-name()='propstat']").node();
|
||||
auto prop = propstat.select_node("*[local-name()='prop']").node();
|
||||
std::string content_length = prop.select_node("*[local-name()='getcontentlength']").node().first_child().value();
|
||||
|
||||
*size = std::strtoll(content_length.c_str(), nullptr, 10);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<DirEntry> WebDAVClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
@@ -151,12 +195,12 @@ int WebDAVClient::Put(const std::string &inputfile, const std::string &path, uin
|
||||
{
|
||||
size_t bytes_remaining = FS::GetSize(inputfile);
|
||||
bytes_transfered = 0;
|
||||
|
||||
FILE* in = FS::OpenRead(inputfile);
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
if (auto res = client->Put(GetFullPath(path),
|
||||
[&](size_t offset, DataSink &sink)
|
||||
{
|
||||
FILE *in = FS::OpenRead(inputfile);
|
||||
|
||||
if (auto res = client->Put(GetFullPath(path), [&](size_t offset, DataSink &sink)
|
||||
{
|
||||
size_t buf_size = MIN(bytes_remaining, CPPHTTPLIB_RECV_BUFSIZ);
|
||||
char* buf = (char*) malloc(buf_size);
|
||||
FS::Seek(in, offset);
|
||||
@@ -170,9 +214,7 @@ int WebDAVClient::Put(const std::string &inputfile, const std::string &path, uin
|
||||
}
|
||||
sink.done();
|
||||
free(buf);
|
||||
return true;
|
||||
},
|
||||
"application/octet-stream"))
|
||||
return true; }, "application/octet-stream"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
@@ -229,15 +271,14 @@ int WebDAVClient::Delete(const std::string &path)
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebDAVClient::Copy(const std::string &from, const std::string &to)
|
||||
{
|
||||
Request req;
|
||||
Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to)) }};
|
||||
Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to))}};
|
||||
|
||||
req.method = "COPY";
|
||||
req.path = httplib::detail::encode_url(GetFullPath(from));
|
||||
@@ -256,7 +297,7 @@ int WebDAVClient::Copy(const std::string &from, const std::string &to)
|
||||
int WebDAVClient::Move(const std::string &from, const std::string &to)
|
||||
{
|
||||
Request req;
|
||||
Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to)) }};
|
||||
Headers header = {{"Accept", "*/*"}, {"Destination", httplib::detail::encode_url(GetFullPath(to))}};
|
||||
|
||||
req.method = "MOVE";
|
||||
req.path = httplib::detail::encode_url(GetFullPath(from));
|
||||
@@ -279,5 +320,5 @@ ClientType WebDAVClient::clientType()
|
||||
|
||||
uint32_t WebDAVClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL;
|
||||
}
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_RAW_READ;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef WEBDAV_H
|
||||
#define WEBDAV_H
|
||||
#ifndef EZ_WEBDAV_H
|
||||
#define EZ_WEBDAV_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -11,7 +11,7 @@
|
||||
class WebDAVClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass, bool send_ping=false);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
@@ -19,6 +19,7 @@ public:
|
||||
int Copy(const std::string &from, const std::string &to);
|
||||
int Move(const std::string &from, const std::string &to);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset = 0);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
ClientType clientType();
|
||||
uint32_t SupportedActions();
|
||||
@@ -28,4 +29,4 @@ private:
|
||||
Result PropFind(const std::string &path, int depth);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+16
-3
@@ -1,5 +1,5 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
#ifndef EZ_COMMON_H
|
||||
#define EZ_COMMON_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -11,6 +11,10 @@
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
enum DownloadState { STATE_PENDING, STATE_DOWNLOADING, STATE_RESUMED, STATE_FAILED, STATE_SUCCESS };
|
||||
|
||||
static const char* state_strings[] = {"Pending", "Downloading", "Resumed", "Failed", "Success"};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t year;
|
||||
@@ -88,6 +92,15 @@ struct DirEntry
|
||||
}
|
||||
};
|
||||
|
||||
struct DownloadProgress
|
||||
{
|
||||
std::string path;
|
||||
std::string state;
|
||||
uint64_t bytes_transfered;
|
||||
uint64_t file_size;
|
||||
time_t timestamp;
|
||||
};
|
||||
|
||||
static lxb_dom_node_t *NextChildElement(lxb_dom_element_t *element)
|
||||
{
|
||||
lxb_dom_node_t *node = element->node.first_child;
|
||||
@@ -128,4 +141,4 @@ static lxb_dom_node_t *NextTextNode(lxb_dom_node_t *node)
|
||||
return next;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+23
-4
@@ -41,6 +41,9 @@ bool show_hidden_files;
|
||||
char alldebrid_api_key[64];
|
||||
char realdebrid_api_key[64];
|
||||
char temp_folder[256];
|
||||
std::string ezremote_server_version;
|
||||
bool enable_background_download;
|
||||
uint64_t minimum_backgrond_file_size;
|
||||
|
||||
unsigned char cipher_key[32] = {'s', '5', 'v', '8', 'y', '/', 'B', '?', 'E', '(', 'H', '+', 'M', 'b', 'Q', 'e', 'T', 'h', 'W', 'm', 'Z', 'q', '4', 't', '7', 'w', '9', 'z', '$', 'C', '&', 'F'};
|
||||
unsigned char cipher_iv[16] = {'Y', 'p', '3', 's', '6', 'v', '9', 'y', '$', 'B', '&', 'E', ')', 'H', '@', 'M'};
|
||||
@@ -152,14 +155,18 @@ namespace CONFIG
|
||||
FS::MkDirs(DATA_PATH);
|
||||
}
|
||||
|
||||
memset(&install_pkg_url, 0, sizeof(install_pkg_url));
|
||||
install_pkg_url.enable_rpi = true;
|
||||
|
||||
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"};
|
||||
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20",
|
||||
"Site 21", "Site 22", "Site 23", "Site 24", "Site 25", "Site 26", "Site 27", "Site 28", "Site 29", "Site 30"};
|
||||
|
||||
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"};
|
||||
"Hungarian", "Indonesian", "Italiano", "Japanese", "Korean", "Norwegian", "Polish", "Portuguese_BR", "Russian",
|
||||
"Romanian", "Ryukyuan", "Spanish", "Turkish", "Simplified Chinese", "Traditional Chinese", "Thai", "Ukrainian", "Vietnamese"};
|
||||
|
||||
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE};
|
||||
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE, HTTP_SERVER_RCLONE, HTTP_SERVER_ARCHIVEORG, HTTP_SERVER_MYRIENT, HTTP_SERVER_GITHUB};
|
||||
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
|
||||
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
|
||||
|
||||
@@ -192,6 +199,12 @@ namespace CONFIG
|
||||
sprintf(temp_folder, ReadString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, TMP_FOLDER_PATH));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_TMP_FOLDER_PATH, temp_folder);
|
||||
|
||||
enable_background_download = ReadBool(CONFIG_GLOBAL, CONFIG_ENABLE_BG_DOWNLOAD, true);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_ENABLE_BG_DOWNLOAD, enable_background_download);
|
||||
|
||||
minimum_backgrond_file_size = ReadLong(CONFIG_GLOBAL, CONFIG_BG_DOWNLOAD_SIZE, 1024*1024*1024);
|
||||
WriteLong(CONFIG_GLOBAL, CONFIG_BG_DOWNLOAD_SIZE, minimum_backgrond_file_size);
|
||||
|
||||
if (!FS::FolderExists(temp_folder))
|
||||
{
|
||||
FS::MkDirs(temp_folder);
|
||||
@@ -298,6 +311,9 @@ namespace CONFIG
|
||||
setting.enable_rpi = ReadBool(sites[i].c_str(), CONFIG_ENABLE_RPI, true);
|
||||
WriteBool(sites[i].c_str(), CONFIG_ENABLE_RPI, setting.enable_rpi);
|
||||
|
||||
setting.enable_disk_cache = ReadBool(sites[i].c_str(), CONFIG_REMOTE_ENABLE_DISK_CACHE, false);
|
||||
WriteBool(sites[i].c_str(), CONFIG_REMOTE_ENABLE_DISK_CACHE, setting.enable_disk_cache);
|
||||
|
||||
sprintf(setting.http_server_type, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_HTTP_SERVER_TYPE, HTTP_SERVER_APACHE));
|
||||
WriteString(sites[i].c_str(), CONFIG_REMOTE_HTTP_SERVER_TYPE, setting.http_server_type);
|
||||
|
||||
@@ -371,6 +387,7 @@ namespace CONFIG
|
||||
WriteString(last_site, CONFIG_REMOTE_SERVER_USER, remote_settings->username);
|
||||
WriteString(last_site, CONFIG_REMOTE_SERVER_PASSWORD, encrypted_text.c_str());
|
||||
WriteBool(last_site, CONFIG_ENABLE_RPI, remote_settings->enable_rpi);
|
||||
WriteBool(last_site, CONFIG_REMOTE_ENABLE_DISK_CACHE, remote_settings->enable_disk_cache);
|
||||
WriteString(last_site, CONFIG_REMOTE_HTTP_SERVER_TYPE, remote_settings->http_server_type);
|
||||
WriteString(last_site, CONFIG_REMOTE_DEFAULT_DIRECTORY, remote_settings->default_directory);
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LAST_SITE, last_site);
|
||||
@@ -426,6 +443,8 @@ namespace CONFIG
|
||||
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);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_ENABLE_BG_DOWNLOAD, enable_background_download);
|
||||
WriteLong(CONFIG_GLOBAL, CONFIG_BG_DOWNLOAD_SIZE, minimum_backgrond_file_size);
|
||||
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
|
||||
+19
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef LAUNCHER_CONFIG_H
|
||||
#define LAUNCHER_CONFIG_H
|
||||
#ifndef EZ_CONFIG_H
|
||||
#define EZ_CONFIG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -57,6 +57,7 @@
|
||||
#define CONFIG_ENABLE_RPI "remote_server_enable_rpi"
|
||||
#define CONFIG_REMOTE_HTTP_SERVER_TYPE "remote_server_http_server_type"
|
||||
#define CONFIG_REMOTE_DEFAULT_DIRECTORY "remote_server_default_directory"
|
||||
#define CONFIG_REMOTE_ENABLE_DISK_CACHE "remote_server_enable_disk_cache"
|
||||
|
||||
#define CONFIG_ALLDEBRID_API_KEY "alldebrid_api_key"
|
||||
#define CONFIG_REALDEBRID_API_KEY "realdebrid_api_key"
|
||||
@@ -76,11 +77,19 @@
|
||||
|
||||
#define CONFIG_LANGUAGE "language"
|
||||
|
||||
#define CONFIG_ENABLE_BG_DOWNLOAD "enable_background_download"
|
||||
#define CONFIG_BG_DOWNLOAD_SIZE "minimum_backgrond_file_size"
|
||||
|
||||
#define HTTP_SERVER_APACHE "Apache"
|
||||
#define HTTP_SERVER_MS_IIS "Microsoft IIS"
|
||||
#define HTTP_SERVER_NGINX "Nginx"
|
||||
#define HTTP_SERVER_NPX_SERVE "Serve"
|
||||
#define HTTP_SERVER_RCLONE "RClone"
|
||||
#define HTTP_SERVER_ARCHIVEORG "Archive.org"
|
||||
#define HTTP_SERVER_MYRIENT "Myrient"
|
||||
#define HTTP_SERVER_GITHUB "Github"
|
||||
|
||||
#define EZREMOTE_SERVER_REQUIRED_VERSION "1.00"
|
||||
|
||||
#define MAX_EDIT_FILE_SIZE 32768
|
||||
|
||||
@@ -110,6 +119,7 @@ struct RemoteSettings
|
||||
char http_server_type[24];
|
||||
GoogleAccountInfo gg_account;
|
||||
char default_directory[256];
|
||||
bool enable_disk_cache;
|
||||
};
|
||||
|
||||
struct PackageUrlInfo
|
||||
@@ -117,6 +127,10 @@ struct PackageUrlInfo
|
||||
char url[512];
|
||||
char username[33];
|
||||
char password[25];
|
||||
bool enable_alldebrid;
|
||||
bool enable_realdebrid;
|
||||
bool enable_disk_cache;
|
||||
bool enable_rpi;
|
||||
};
|
||||
|
||||
extern std::vector<std::string> sites;
|
||||
@@ -144,6 +158,9 @@ extern bool show_hidden_files;
|
||||
extern char alldebrid_api_key[64];
|
||||
extern char realdebrid_api_key[64];
|
||||
extern char temp_folder[256];
|
||||
extern std::string ezremote_server_version;
|
||||
extern bool enable_background_download;
|
||||
extern uint64_t minimum_backgrond_file_size;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef FICHIER_HOST_H
|
||||
#define FICHIER_HOST_H
|
||||
#ifndef EZ_FICHIER_HOST_H
|
||||
#define EZ_FICHIER_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef ALLDEBRID_HOST_H
|
||||
#define ALLDEBRID_HOST_H
|
||||
#ifndef EZ_ALLDEBRID_HOST_H
|
||||
#define EZ_ALLDEBRID_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include <regex>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <http/httplib.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef DIRECT_HOST_H
|
||||
#define DIRECT_HOST_H
|
||||
#ifndef EZ_DIRECT_HOST_H
|
||||
#define EZ_DIRECT_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef FILEHOST_H
|
||||
#define FILEHOST_H
|
||||
#ifndef EZ_FILEHOST_H
|
||||
#define EZ_FILEHOST_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef GDRIVE_HOST_H
|
||||
#define GDRIVE_HOST_H
|
||||
#ifndef EZ_GDRIVE_HOST_H
|
||||
#define EZ_GDRIVE_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef MEDIAFIRE_HOST_H
|
||||
#define MEDIAFIRE_HOST_H
|
||||
#ifndef EZ_MEDIAFIRE_HOST_H
|
||||
#define EZ_MEDIAFIRE_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef PIXELDRAIN_HOST_H
|
||||
#define PIXELDRAIN_HOST_H
|
||||
#ifndef EZ_PIXELDRAIN_HOST_H
|
||||
#define EZ_PIXELDRAIN_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef REALDEBRID_HOST_H
|
||||
#define REALDEBRID_HOST_H
|
||||
#ifndef EZ_REALDEBRID_HOST_H
|
||||
#define EZ_REALDEBRID_HOST_H
|
||||
|
||||
#include "filehost.h"
|
||||
|
||||
|
||||
+16
-6
@@ -50,7 +50,7 @@ namespace FS
|
||||
|
||||
void RmDir(const std::string &path)
|
||||
{
|
||||
remove(path.c_str());
|
||||
rmdir(path.c_str());
|
||||
}
|
||||
|
||||
int64_t GetSize(const std::string &path)
|
||||
@@ -85,6 +85,7 @@ namespace FS
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Rename(const std::string &from, const std::string &to)
|
||||
{
|
||||
int res = rename(from.c_str(), to.c_str());
|
||||
@@ -269,6 +270,7 @@ namespace FS
|
||||
if (dirent == NULL)
|
||||
{
|
||||
closedir(fd);
|
||||
fd = NULL;
|
||||
return out;
|
||||
}
|
||||
else
|
||||
@@ -344,6 +346,7 @@ namespace FS
|
||||
}
|
||||
}
|
||||
closedir(fd);
|
||||
fd = NULL;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -510,6 +513,8 @@ namespace FS
|
||||
|
||||
size_t bytes_read = 0;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
const size_t buf_size = 0x10000;
|
||||
unsigned char *buf = new unsigned char[buf_size];
|
||||
|
||||
@@ -547,11 +552,16 @@ namespace FS
|
||||
if (from.compare(to) == 0)
|
||||
return true;
|
||||
|
||||
bool res = Copy(from, to);
|
||||
if (res)
|
||||
Rm(from);
|
||||
else
|
||||
return res;
|
||||
errno = 0;
|
||||
int ret = rename(from.c_str(), to.c_str());
|
||||
if (ret != 0 && (errno == EXDEV || errno == EEXIST))
|
||||
{
|
||||
bool res = Copy(from, to);
|
||||
if (res)
|
||||
Rm(from);
|
||||
else
|
||||
return res;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef LAUNCHER_FS_H
|
||||
#define LAUNCHER_FS_H
|
||||
#ifndef EZ_FS_H
|
||||
#define EZ_FS_H
|
||||
|
||||
#pragma once
|
||||
#include <string.h>
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef LAUNCHER_GUI_H
|
||||
#define LAUNCHER_GUI_H
|
||||
#ifndef EZ_GUI_H
|
||||
#define EZ_GUI_H
|
||||
|
||||
#include <string>
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
@@ -3954,6 +3954,10 @@ bool Server::listen_internal() {
|
||||
#endif
|
||||
}
|
||||
|
||||
int const size = 1048576;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||
|
||||
task_queue->enqueue([this, sock]() { process_and_close_socket(sock); });
|
||||
}
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ private:
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using Headers = std::map<std::string, std::string, detail::ci>;
|
||||
using Headers = std::multimap<std::string, std::string, detail::ci>;
|
||||
|
||||
using Params = std::multimap<std::string, std::string>;
|
||||
using Match = std::smatch;
|
||||
@@ -1898,6 +1898,8 @@ make_basic_authentication_header(const std::string &username,
|
||||
|
||||
namespace detail {
|
||||
|
||||
const char *status_message(int status);
|
||||
|
||||
std::string encode_query_param(const std::string &value);
|
||||
|
||||
std::string encode_url(const std::string &s);
|
||||
|
||||
+2
-2
@@ -16,8 +16,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __IME_DIALOG_H__
|
||||
#define __IME_DIALOG_H__
|
||||
#ifndef __EZ_IME_DIALOG_H__
|
||||
#define __EZ_IME_DIALOG_H__
|
||||
|
||||
#define IME_DIALOG_RESULT_NONE 0
|
||||
#define IME_DIALOG_RESULT_RUNNING 1
|
||||
|
||||
@@ -84,6 +84,8 @@
|
||||
#define BUTTON_RIGHT 0x00000020
|
||||
#define BUTTON_UP 0x00000040
|
||||
#define BUTTON_DOWN 0x00000080
|
||||
#define BUTTON_C 0x00000100
|
||||
#define BUTTON_D 0x00000200
|
||||
|
||||
static uint32_t previous_down = 0;
|
||||
static int repeat_count = 0;
|
||||
@@ -531,8 +533,15 @@ static void ImGui_ImplSDL2_UpdateGamepads()
|
||||
down |= BUTTON_DOWN;
|
||||
else if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_LEFTY) < -ANALOG_THRESHOLD)
|
||||
down |= BUTTON_UP;
|
||||
else if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) > ANALOG_THRESHOLD)
|
||||
down |= BUTTON_C;
|
||||
else if (SDL_GameControllerGetAxis(game_controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) > ANALOG_THRESHOLD)
|
||||
down |= BUTTON_D;
|
||||
|
||||
uint32_t pressed = down & ~previous_down;
|
||||
io.AddKeyEvent(ImGuiKey_C, (pressed & BUTTON_C) != 0);
|
||||
io.AddKeyEvent(ImGuiKey_D, (pressed & BUTTON_D) != 0);
|
||||
|
||||
if (previous_down == down)
|
||||
{
|
||||
uint64_t delay = 300;
|
||||
|
||||
+546
-49
@@ -5,6 +5,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <json-c/json.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Bgft.h>
|
||||
#include <orbis/AppInstUtil.h>
|
||||
@@ -12,6 +13,21 @@
|
||||
#include <orbis/SystemService.h>
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/sftpclient.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "clients/github.h"
|
||||
#include "clients/nfsclient.h"
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/apache.h"
|
||||
#include "clients/archiveorg.h"
|
||||
#include "clients/iis.h"
|
||||
#include "clients/github.h"
|
||||
#include "clients/myrient.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/rclone.h"
|
||||
|
||||
#include "server/http_server.h"
|
||||
#include "installer.h"
|
||||
#include "util.h"
|
||||
@@ -22,11 +38,14 @@
|
||||
#include "fs.h"
|
||||
#include "sfo.h"
|
||||
|
||||
#define SERVER_ELF_PATH "/mnt/sandbox/pfsmnt/RMTC00001-app0/daemon/daemon.elf"
|
||||
|
||||
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
|
||||
|
||||
struct BgProgressCheck
|
||||
{
|
||||
ArchivePkgInstallData* pkg_data;
|
||||
ArchivePkgInstallData *archive_pkg_data;
|
||||
SplitPkgInstallData *split_pkg_data;
|
||||
int task_id;
|
||||
std::string hash;
|
||||
};
|
||||
@@ -36,9 +55,15 @@ static OrbisBgftInitParams s_bgft_init_params;
|
||||
static bool s_bgft_initialized = false;
|
||||
|
||||
static std::map<std::string, ArchivePkgInstallData *> archive_pkg_install_data_list;
|
||||
static std::map<std::string, SplitPkgInstallData *> split_pkg_install_data_list;
|
||||
|
||||
namespace INSTALLER
|
||||
{
|
||||
static int FtpCallback(int64_t xfered, void *arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Init(void)
|
||||
{
|
||||
int ret;
|
||||
@@ -107,22 +132,22 @@ namespace INSTALLER
|
||||
s_bgft_initialized = false;
|
||||
}
|
||||
|
||||
std::string GetRemotePkgTitle(RemoteClient *client, const std::string &path, pkg_header *header)
|
||||
{
|
||||
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 "";
|
||||
}
|
||||
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;
|
||||
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)
|
||||
@@ -132,7 +157,7 @@ namespace INSTALLER
|
||||
param_sfo_offset = BE32(entries[i].offset);
|
||||
param_sfo_size = BE32(entries[i].size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(entry_table_data);
|
||||
|
||||
@@ -140,10 +165,10 @@ namespace INSTALLER
|
||||
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)
|
||||
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");
|
||||
const char *tmp_title = SFO::GetString((const char *)param_sfo_data, param_sfo_size, "TITLE");
|
||||
if (tmp_title != nullptr)
|
||||
title = std::string(tmp_title);
|
||||
}
|
||||
@@ -151,7 +176,7 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetLocalPkgTitle(const std::string &path, pkg_header *header)
|
||||
{
|
||||
@@ -165,7 +190,7 @@ namespace INSTALLER
|
||||
FS::Read(fd, entry_table_data, entry_table_size);
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = NULL;
|
||||
void *param_sfo_data = NULL;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
void *icon0_png_data = NULL;
|
||||
@@ -188,7 +213,7 @@ namespace INSTALLER
|
||||
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");
|
||||
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);
|
||||
@@ -197,10 +222,53 @@ namespace INSTALLER
|
||||
return title;
|
||||
}
|
||||
|
||||
std::string StoreBgInstallHostData(RemoteSettings *settings, const std::string &path)
|
||||
{
|
||||
std::string hash = Util::UrlHash(settings->server + path + settings->username + settings->password + std::to_string(settings->type));
|
||||
json_object *history_item_obj = json_object_new_object();
|
||||
json_object_object_add(history_item_obj, "hash", json_object_new_string(hash.c_str()));
|
||||
json_object_object_add(history_item_obj, "url", json_object_new_string(settings->server));
|
||||
json_object_object_add(history_item_obj, "path", json_object_new_string(path.c_str()));
|
||||
json_object_object_add(history_item_obj, "username", json_object_new_string(settings->username));
|
||||
json_object_object_add(history_item_obj, "password", json_object_new_string(settings->password));
|
||||
json_object_object_add(history_item_obj, "type", json_object_new_int(settings->type));
|
||||
|
||||
if (settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
json_object_object_add(history_item_obj, "http_server_type", json_object_new_string(settings->http_server_type));
|
||||
}
|
||||
|
||||
const char *params_str = json_object_to_json_string(history_item_obj);
|
||||
|
||||
httplib::Client client = httplib::Client(std::string("http://127.0.0.1:") + std::to_string(http_int_server_port));
|
||||
client.set_connection_timeout(1);
|
||||
|
||||
if (auto res = client.Post("/store_bg_install_data", params_str, "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
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))
|
||||
if (remote_settings->type == CLIENT_TYPE_HTTP_SERVER && strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
|
||||
{
|
||||
GithubClient *tmp_client = (GithubClient*) remoteclient;
|
||||
return tmp_client->GetDownloadUrl(path);
|
||||
}
|
||||
if ( strlen(remote_settings->username) == 0 &&
|
||||
strlen(remote_settings->password) == 0 &&
|
||||
(remote_settings->type == CLIENT_TYPE_WEBDAV ||
|
||||
(remote_settings->type == CLIENT_TYPE_HTTP_SERVER && strcmp(remote_settings->http_server_type, HTTP_SERVER_ARCHIVEORG) == 0)
|
||||
)
|
||||
)
|
||||
{
|
||||
std::string full_url = WebDAVClient::GetHttpUrl(remote_settings->server + path);
|
||||
size_t scheme_pos = full_url.find("://");
|
||||
@@ -219,9 +287,8 @@ namespace INSTALLER
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string encoded_path = httplib::detail::encode_url(path);
|
||||
std::string encoded_site_name = httplib::detail::encode_url(remote_settings->site_name);
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/" + encoded_site_name + encoded_path;
|
||||
std::string hash = StoreBgInstallHostData(remote_settings, path);
|
||||
std::string full_url = std::string("http://127.0.0.1:") + std::to_string(http_int_server_port) + "/bg_install/" + hash;
|
||||
return full_url;
|
||||
}
|
||||
|
||||
@@ -232,7 +299,7 @@ namespace INSTALLER
|
||||
{
|
||||
bool completed = false;
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck*) argp;
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck *)argp;
|
||||
int ret;
|
||||
|
||||
while (!completed)
|
||||
@@ -253,15 +320,27 @@ namespace INSTALLER
|
||||
sceKernelUsleep(500000);
|
||||
}
|
||||
finish:
|
||||
if (bg_check_data->pkg_data != nullptr)
|
||||
if (bg_check_data->archive_pkg_data != nullptr)
|
||||
{
|
||||
bg_check_data->pkg_data->stop_write_thread = true;
|
||||
pthread_join(bg_check_data->pkg_data->thread, NULL);
|
||||
delete(bg_check_data->pkg_data->split_file);
|
||||
free(bg_check_data->pkg_data);
|
||||
bg_check_data->archive_pkg_data->stop_write_thread = true;
|
||||
pthread_join(bg_check_data->archive_pkg_data->thread, NULL);
|
||||
delete (bg_check_data->archive_pkg_data->split_file);
|
||||
free(bg_check_data->archive_pkg_data);
|
||||
RemoveArchivePkgInstallData(bg_check_data->hash);
|
||||
free(bg_check_data);
|
||||
}
|
||||
else if (bg_check_data->split_pkg_data != nullptr)
|
||||
{
|
||||
bg_check_data->split_pkg_data->stop_write_thread = true;
|
||||
bg_check_data->split_pkg_data->split_file->Close();
|
||||
pthread_join(bg_check_data->split_pkg_data->thread, NULL);
|
||||
delete (bg_check_data->split_pkg_data->split_file);
|
||||
if (bg_check_data->split_pkg_data->delete_client)
|
||||
delete (bg_check_data->split_pkg_data->remote_client);
|
||||
free(bg_check_data->split_pkg_data);
|
||||
RemoveSplitPkgInstallData(bg_check_data->hash);
|
||||
free(bg_check_data);
|
||||
}
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
@@ -385,19 +464,20 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
if (prompt)
|
||||
{
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_to_download = header->pkg_content_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while (!completed)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
ret = sceBgftServiceDownloadGetProgress(task_id, &progress_info);
|
||||
if (ret || (progress_info.transferred > 0 && progress_info.errorResult != 0))
|
||||
return 0;
|
||||
|
||||
|
||||
if (progress_info.length > 0)
|
||||
{
|
||||
completed = progress_info.transferred == progress_info.length;
|
||||
@@ -409,9 +489,10 @@ namespace INSTALLER
|
||||
}
|
||||
else
|
||||
{
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck*) malloc(sizeof(BgProgressCheck));
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck *)malloc(sizeof(BgProgressCheck));
|
||||
memset(bg_check_data, 0, sizeof(BgProgressCheck));
|
||||
bg_check_data->pkg_data = nullptr;
|
||||
bg_check_data->archive_pkg_data = nullptr;
|
||||
bg_check_data->split_pkg_data = nullptr;
|
||||
bg_check_data->task_id = task_id;
|
||||
bg_check_data->hash = "";
|
||||
ret = pthread_create(&bk_install_thid, NULL, CheckBgInstallTaskThread, bg_check_data);
|
||||
@@ -488,8 +569,10 @@ namespace INSTALLER
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_to_download = header.pkg_content_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while (!completed)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
@@ -515,13 +598,13 @@ namespace INSTALLER
|
||||
{
|
||||
int ret;
|
||||
bool completed = false;
|
||||
|
||||
|
||||
if (strncmp(path.c_str(), "/data/", 6) != 0 &&
|
||||
strncmp(path.c_str(), "/user/data/", 11) != 0 &&
|
||||
strncmp(path.c_str(), "/mnt/usb", 8) != 0)
|
||||
return -1;
|
||||
|
||||
std::string filename = path.substr(path.find_last_of("/")+1);
|
||||
std::string filename = path.substr(path.find_last_of("/") + 1);
|
||||
char filepath[1024];
|
||||
snprintf(filepath, 1023, "%s", path.c_str());
|
||||
if (strncmp(path.c_str(), "/data/", 6) == 0)
|
||||
@@ -599,8 +682,10 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
sprintf(activity_message, "%s", lang_strings[STR_WAIT_FOR_INSTALL_MSG]);
|
||||
bytes_to_download = 1;
|
||||
bytes_to_download = header->pkg_content_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while (!completed)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
@@ -639,7 +724,7 @@ namespace INSTALLER
|
||||
FS::Read(fd, entry_table_data, entry_table_size);
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = NULL;
|
||||
void *param_sfo_data = NULL;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
void *icon0_png_data = NULL;
|
||||
@@ -710,7 +795,7 @@ namespace INSTALLER
|
||||
return false;
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = NULL;
|
||||
void *param_sfo_data = NULL;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
void *icon0_png_data = NULL;
|
||||
@@ -778,7 +863,7 @@ namespace INSTALLER
|
||||
|
||||
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data)
|
||||
{
|
||||
std::pair<std::string, ArchivePkgInstallData*> pair = std::make_pair(hash, 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);
|
||||
}
|
||||
@@ -788,10 +873,10 @@ namespace INSTALLER
|
||||
archive_pkg_install_data_list.erase(hash);
|
||||
}
|
||||
|
||||
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg)
|
||||
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData *pkg_data, bool bg)
|
||||
{
|
||||
pkg_header header;
|
||||
pkg_data->split_file->Read((char*)&header, sizeof(pkg_header), 0);
|
||||
pkg_data->split_file->Read((char *)&header, sizeof(pkg_header), 0);
|
||||
|
||||
int ret;
|
||||
std::string cid = std::string((char *)header.pkg_content_id);
|
||||
@@ -834,7 +919,7 @@ namespace INSTALLER
|
||||
}
|
||||
|
||||
std::string hash = Util::UrlHash(path);
|
||||
std::string full_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
|
||||
std::string full_url = std::string("http://127.0.0.1:") + std::to_string(http_server_port) + "/archive_inst/" + hash;
|
||||
AddArchivePkgInstallData(hash, pkg_data);
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
@@ -915,8 +1000,10 @@ namespace INSTALLER
|
||||
if (!bg)
|
||||
{
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_to_download = header.pkg_content_size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
while (!completed)
|
||||
{
|
||||
memset(&progress_info, 0, sizeof(progress_info));
|
||||
@@ -926,7 +1013,6 @@ namespace INSTALLER
|
||||
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;
|
||||
@@ -938,9 +1024,10 @@ namespace INSTALLER
|
||||
}
|
||||
else
|
||||
{
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck*) malloc(sizeof(BgProgressCheck));
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck *)malloc(sizeof(BgProgressCheck));
|
||||
memset(bg_check_data, 0, sizeof(BgProgressCheck));
|
||||
bg_check_data->pkg_data = pkg_data;
|
||||
bg_check_data->archive_pkg_data = pkg_data;
|
||||
bg_check_data->split_pkg_data = nullptr;
|
||||
bg_check_data->task_id = task_id;
|
||||
bg_check_data->hash = hash;
|
||||
ret = pthread_create(&bk_install_thid, NULL, CheckBgInstallTaskThread, bg_check_data);
|
||||
@@ -950,11 +1037,421 @@ namespace INSTALLER
|
||||
finish:
|
||||
pkg_data->stop_write_thread = true;
|
||||
pthread_join(pkg_data->thread, NULL);
|
||||
delete(pkg_data->split_file);
|
||||
delete (pkg_data->split_file);
|
||||
free(pkg_data);
|
||||
RemoveArchivePkgInstallData(hash);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
SplitPkgInstallData *GetSplitPkgInstallData(const std::string &hash)
|
||||
{
|
||||
return split_pkg_install_data_list[hash];
|
||||
}
|
||||
|
||||
void AddSplitPkgInstallData(const std::string &hash, SplitPkgInstallData *pkg_data)
|
||||
{
|
||||
std::pair<std::string, SplitPkgInstallData *> pair = std::make_pair(hash, pkg_data);
|
||||
split_pkg_install_data_list.erase(hash);
|
||||
split_pkg_install_data_list.insert(pair);
|
||||
}
|
||||
|
||||
void RemoveSplitPkgInstallData(const std::string &hash)
|
||||
{
|
||||
split_pkg_install_data_list.erase(hash);
|
||||
}
|
||||
|
||||
bool InstallSplitPkg(const std::string &path, SplitPkgInstallData *pkg_data, bool bg)
|
||||
{
|
||||
pkg_header header;
|
||||
pkg_data->split_file->Read((char *)&header, sizeof(pkg_header), 0);
|
||||
|
||||
int ret;
|
||||
std::string cid = std::string((char *)header.pkg_content_id);
|
||||
cid = cid.substr(cid.find_first_of("-") + 1, 9);
|
||||
std::string display_title = cid;
|
||||
int user_id;
|
||||
ret = sceUserServiceGetForegroundUser(&user_id);
|
||||
const char *package_type;
|
||||
uint32_t content_type = BE32(header.pkg_content_type);
|
||||
uint32_t flags = BE32(header.pkg_content_flags);
|
||||
bool is_patch = false;
|
||||
bool completed = false;
|
||||
|
||||
switch (content_type)
|
||||
{
|
||||
case PKG_CONTENT_TYPE_GD:
|
||||
package_type = "PS4GD";
|
||||
break;
|
||||
case PKG_CONTENT_TYPE_AC:
|
||||
package_type = "PS4AC";
|
||||
break;
|
||||
case PKG_CONTENT_TYPE_AL:
|
||||
package_type = "PS4AL";
|
||||
break;
|
||||
case PKG_CONTENT_TYPE_DP:
|
||||
package_type = "PS4DP";
|
||||
break;
|
||||
default:
|
||||
package_type = NULL;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & PKG_CONTENT_FLAGS_FIRST_PATCH ||
|
||||
flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH ||
|
||||
flags & PKG_CONTENT_FLAGS_DELTA_PATCH ||
|
||||
flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
|
||||
{
|
||||
is_patch = true;
|
||||
}
|
||||
|
||||
std::string hash = Util::UrlHash(path);
|
||||
std::string full_url = std::string("http://127.0.0.1:") + std::to_string(http_server_port) + "/split_inst/" + hash;
|
||||
AddSplitPkgInstallData(hash, pkg_data);
|
||||
|
||||
OrbisBgftTaskProgress progress_info;
|
||||
OrbisBgftDownloadParam params;
|
||||
memset(¶ms, 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(¶ms, &task_id);
|
||||
else
|
||||
ret = sceBgftServiceIntDebugDownloadRegisterPkg(¶ms, &task_id);
|
||||
if (ret == 0x80990088 || ret == 0x80990015)
|
||||
{
|
||||
if (!bg)
|
||||
{
|
||||
sprintf(confirm_message, "%s - %s?", display_title.c_str(), lang_strings[STR_REINSTALL_CONFIRM_MSG]);
|
||||
confirm_state = CONFIRM_WAIT;
|
||||
action_to_take = selected_action;
|
||||
activity_inprogess = false;
|
||||
while (confirm_state == CONFIRM_WAIT)
|
||||
{
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
activity_inprogess = true;
|
||||
selected_action = action_to_take;
|
||||
|
||||
if (confirm_state == CONFIRM_YES)
|
||||
{
|
||||
ret = sceAppInstUtilAppUnInstall(cid.c_str());
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = sceAppInstUtilAppUnInstall(cid.c_str());
|
||||
if (ret != 0)
|
||||
{
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
else if (ret > 0)
|
||||
{
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
ret = sceBgftServiceDownloadStartTask(task_id);
|
||||
if (ret)
|
||||
{
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
Util::Notify("%s queued", display_title.c_str());
|
||||
|
||||
if (!bg)
|
||||
{
|
||||
file_transfering = true;
|
||||
bytes_to_download = pkg_data->size;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
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;
|
||||
}
|
||||
if (progress_info.length > 0)
|
||||
{
|
||||
completed = progress_info.transferred == progress_info.length;
|
||||
bytes_to_download = progress_info.length;
|
||||
bytes_transfered = progress_info.transferred;
|
||||
}
|
||||
sceSystemServicePowerTick();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BgProgressCheck *bg_check_data = (BgProgressCheck *)malloc(sizeof(BgProgressCheck));
|
||||
memset(bg_check_data, 0, sizeof(BgProgressCheck));
|
||||
bg_check_data->split_pkg_data = pkg_data;
|
||||
bg_check_data->archive_pkg_data = nullptr;
|
||||
bg_check_data->task_id = task_id;
|
||||
bg_check_data->hash = hash;
|
||||
ret = pthread_create(&bk_install_thid, NULL, CheckBgInstallTaskThread, bg_check_data);
|
||||
return 1;
|
||||
}
|
||||
ret = 1;
|
||||
finish:
|
||||
pkg_data->stop_write_thread = true;
|
||||
pkg_data->split_file->Close();
|
||||
pthread_join(pkg_data->thread, NULL);
|
||||
delete (pkg_data->split_file);
|
||||
if (pkg_data->delete_client)
|
||||
delete (pkg_data->remote_client);
|
||||
free(pkg_data);
|
||||
RemoveSplitPkgInstallData(hash);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string EzRemoteServerVersion()
|
||||
{
|
||||
if (!IsPortOpen("127.0.0.1", 6701, 1))
|
||||
return "";
|
||||
|
||||
httplib::Client tmp_client = httplib::Client("http://127.0.0.1:6701");
|
||||
|
||||
tmp_client.set_connection_timeout(1);
|
||||
|
||||
if (auto res = tmp_client.Get("/version"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
return res->body;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool IsPortOpen(const char *ip, uint16_t port, int timeout_sec)
|
||||
{
|
||||
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd < 0)
|
||||
return 0;
|
||||
|
||||
// Set socket to non-blocking mode
|
||||
int flags = fcntl(sockfd, F_GETFL, 0);
|
||||
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
inet_pton(AF_INET, ip, &addr.sin_addr);
|
||||
|
||||
// Attempt connection
|
||||
int res = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
if (res < 0)
|
||||
{
|
||||
if (errno == EINPROGRESS)
|
||||
{
|
||||
// Wait for connection completion using select()
|
||||
fd_set write_fds;
|
||||
struct timeval timeout;
|
||||
|
||||
FD_ZERO(&write_fds);
|
||||
FD_SET(sockfd, &write_fds);
|
||||
|
||||
timeout.tv_sec = timeout_sec;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
res = select(sockfd + 1, NULL, &write_fds, NULL, &timeout);
|
||||
|
||||
if (res > 0)
|
||||
{
|
||||
// Check if connection succeeded or failed with an error
|
||||
int so_error;
|
||||
socklen_t len = sizeof(so_error);
|
||||
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
|
||||
if (so_error == 0)
|
||||
{
|
||||
// Port is open! Clean up and return success
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connected instantly (e.g., local loopback)
|
||||
close(sockfd);
|
||||
return 1;
|
||||
}
|
||||
|
||||
close(sockfd);
|
||||
return 0; // Port is closed or timed out
|
||||
}
|
||||
|
||||
int StartEzRemoteServer()
|
||||
{
|
||||
char buffer[8192];
|
||||
in_addr_t in_addr;
|
||||
in_addr_t server_addr;
|
||||
int filefd;
|
||||
int sockfd;
|
||||
ssize_t i;
|
||||
ssize_t read_return;
|
||||
struct hostent *hostent;
|
||||
struct sockaddr_in sockaddr_in;
|
||||
unsigned short server_port = 9090;
|
||||
|
||||
if (IsPortOpen("127.0.0.1", 6701, 1))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
filefd = open(SERVER_ELF_PATH, O_RDONLY);
|
||||
if (filefd == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
hostent = gethostbyname("127.0.0.1");
|
||||
if (hostent == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
in_addr = inet_addr(inet_ntoa(*(struct in_addr *)*(hostent->h_addr_list)));
|
||||
if (in_addr == (in_addr_t)-1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sockaddr_in.sin_addr.s_addr = in_addr;
|
||||
sockaddr_in.sin_family = AF_INET;
|
||||
sockaddr_in.sin_port = htons(server_port);
|
||||
|
||||
if (connect(sockfd, (struct sockaddr *)&sockaddr_in, sizeof(sockaddr_in)) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
read_return = read(filefd, buffer, 8192);
|
||||
if (read_return == 0)
|
||||
break;
|
||||
if (read_return == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (write(sockfd, buffer, read_return) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
close(filefd);
|
||||
close(sockfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void StopEzRemoteServer()
|
||||
{
|
||||
httplib::Client tmp_client = httplib::Client("http://127.0.0.1:6701");
|
||||
tmp_client.Get("/stop");
|
||||
}
|
||||
|
||||
RemoteClient *GetRemoteClient(int site_idx)
|
||||
{
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
RemoteSettings *tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
return GetRemoteClient(tmp_settings);
|
||||
}
|
||||
|
||||
RemoteClient *GetRemoteClient(RemoteSettings *settings)
|
||||
{
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
|
||||
if (settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0)
|
||||
tmp_client = new ApacheClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MS_IIS) == 0)
|
||||
tmp_client = new IISClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NGINX) == 0)
|
||||
tmp_client = new NginxClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
|
||||
tmp_client = new NpxServeClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
|
||||
tmp_client = new RCloneClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_ARCHIVEORG) == 0)
|
||||
tmp_client = new ArchiveOrgClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
|
||||
tmp_client = new GithubClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MYRIENT) == 0)
|
||||
tmp_client = new MyrientClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_WEBDAV)
|
||||
{
|
||||
tmp_client = new WebDAVClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
FtpClient *ftp_client = (FtpClient *)tmp_client;
|
||||
ftp_client->SetCallbackXferFunction(FtpCallback);
|
||||
}
|
||||
else if (settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
}
|
||||
|
||||
tmp_client->Connect(settings->server, settings->username, settings->password, false);
|
||||
|
||||
return tmp_client;
|
||||
}
|
||||
}
|
||||
|
||||
+24
-1
@@ -4,6 +4,7 @@
|
||||
#include "zip_util.h"
|
||||
#include "split_file.h"
|
||||
#include "pthread.h"
|
||||
#include "config.h"
|
||||
|
||||
#define SWAP16(x) \
|
||||
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
|
||||
@@ -129,6 +130,17 @@ struct ArchivePkgInstallData
|
||||
bool stop_write_thread;
|
||||
};
|
||||
|
||||
struct SplitPkgInstallData
|
||||
{
|
||||
SplitFile *split_file;
|
||||
RemoteClient *remote_client;
|
||||
std::string path;
|
||||
int64_t size;
|
||||
pthread_t thread;
|
||||
bool stop_write_thread;
|
||||
bool delete_client;
|
||||
};
|
||||
|
||||
static pthread_t bk_install_thid;
|
||||
|
||||
namespace INSTALLER
|
||||
@@ -149,4 +161,15 @@ namespace INSTALLER
|
||||
void AddArchivePkgInstallData(const std::string &hash, ArchivePkgInstallData *pkg_data);
|
||||
void RemoveArchivePkgInstallData(const std::string &hash);
|
||||
bool InstallArchivePkg(const std::string &path, ArchivePkgInstallData* pkg_data, bool bg = false);
|
||||
}
|
||||
SplitPkgInstallData *GetSplitPkgInstallData(const std::string &hash);
|
||||
void AddSplitPkgInstallData(const std::string &hash, SplitPkgInstallData *pkg_data);
|
||||
void RemoveSplitPkgInstallData(const std::string &hash);
|
||||
bool InstallSplitPkg(const std::string &path, SplitPkgInstallData* pkg_data, bool bg = false);
|
||||
std::string EzRemoteServerVersion();
|
||||
int StartEzRemoteServer();
|
||||
void StopEzRemoteServer();
|
||||
std::string StoreBgInstallHostData(RemoteSettings *remote_settings, const std::string &path);
|
||||
RemoteClient *GetRemoteClient(int site_idx);
|
||||
RemoteClient *GetRemoteClient(RemoteSettings *settings);
|
||||
bool IsPortOpen(const char *ip, uint16_t port, int timeout_sec);
|
||||
}
|
||||
|
||||
+21
-1
@@ -172,6 +172,23 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"Temp Directory", // STR_TEMP_DIRECTORY
|
||||
"Real-Debrid", // STR_REALDEBRID
|
||||
"Package install is running in the background. Don't close the app while install is in progress", // STR_BACKGROUND_INSTALL_INPROGRESS
|
||||
"Enable disk caching. Can improve package install speed in cases where connection to remote is slow, but breaks resuming of install", // STR_ENABLE_DISC_CACHE_MSG
|
||||
"DC", // STR_ENABLE_DISK_CACHE
|
||||
"Install Via AllDebrid", // STR_ENABLE_ALLDEBRID_MSG
|
||||
"Install Via RealDebrid", // STR_ENABLE_REALDEBRID_MSG
|
||||
"Enable Disk Cache", // STR_ENABLE_DISKCACHE_DESC
|
||||
"Cannot perform operation while activity is in progress", // STR_ACTIVITY_IN_PROGRESS_MSG
|
||||
"ezRemote Direct Package Installer payload is not loaded", // STR_ETAHEN_DPI_ERROR_MSG
|
||||
"Start/Restart Server", // STR_RESTART_SERVER
|
||||
"Stop Server", // STR_STOP_SERVER
|
||||
"Warning", // STR_WARNING
|
||||
"The version of ezRemote Server payload running does not match the required version needed by ezRemote Client.", // STR_WARNING_MSG_1
|
||||
"If you are using Goldhen payload loader, then update the elf that comes with ezRemoteClient package.", // STR_WARNING_MSG_2
|
||||
"You may goto the Global Settings and restart ezRemote Server with the version that came packaged.", // STR_WARNING_MSG_3
|
||||
"Enable background download", // STR_ENABLE_BG_DOWNLOAD
|
||||
"Minimum background file size (bytes)", // STR_BG_DOWNLOAD_MIN_SIZE
|
||||
"Background Download Progress", // STR_BG_DOWNLOAD_PROGRESS
|
||||
"Show Background Download Progress", // STR_SHOW_BG_DOWNLOAD_PROGRESS
|
||||
};
|
||||
|
||||
bool needs_extended_font = false;
|
||||
@@ -253,6 +270,9 @@ namespace Lang
|
||||
case ORBIS_SYSTEM_PARAM_LANG_ROMANIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Romanian.ini");
|
||||
break;
|
||||
case ORBIS_SYSTEM_PARAM_LANG_NORWEGIAN:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/Norwegian.ini");
|
||||
break;
|
||||
default:
|
||||
sprintf(langFile, "%s", "/app0/assets/langs/English.ini");
|
||||
break;
|
||||
@@ -289,4 +309,4 @@ namespace Lang
|
||||
sscanf(last_site, "%[^ ] %d", buf, &num);
|
||||
sprintf(display_site, "%s %d", lang_strings[STR_SITE], num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-5
@@ -1,5 +1,5 @@
|
||||
#ifndef __LANG_H__
|
||||
#define __LANG_H__
|
||||
#ifndef __EZ_LANG_H__
|
||||
#define __EZ_LANG_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -165,7 +165,24 @@
|
||||
FUNC(STR_LANGUAGE) \
|
||||
FUNC(STR_TEMP_DIRECTORY) \
|
||||
FUNC(STR_REALDEBRID) \
|
||||
FUNC(STR_BACKGROUND_INSTALL_INPROGRESS)
|
||||
FUNC(STR_BACKGROUND_INSTALL_INPROGRESS) \
|
||||
FUNC(STR_ENABLE_DISC_CACHE_MSG) \
|
||||
FUNC(STR_ENABLE_DISK_CACHE) \
|
||||
FUNC(STR_ENABLE_ALLDEBRID_MSG) \
|
||||
FUNC(STR_ENABLE_REALDEBRID_MSG) \
|
||||
FUNC(STR_ENABLE_DISKCACHE_DESC) \
|
||||
FUNC(STR_ACTIVITY_IN_PROGRESS_MSG) \
|
||||
FUNC(STR_DPI_NOT_STARTED_ERROR_MSG) \
|
||||
FUNC(STR_RESTART_SERVER) \
|
||||
FUNC(STR_STOP_SERVER) \
|
||||
FUNC(STR_WARNING) \
|
||||
FUNC(STR_WARNING_MSG_1) \
|
||||
FUNC(STR_WARNING_MSG_2) \
|
||||
FUNC(STR_WARNING_MSG_3) \
|
||||
FUNC(STR_ENABLE_BG_DOWNLOAD) \
|
||||
FUNC(STR_BG_DOWNLOAD_MIN_SIZE) \
|
||||
FUNC(STR_BG_DOWNLOAD_PROGRESS) \
|
||||
FUNC(STR_SHOW_BG_DOWNLOAD_PROGRESS) \
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
@@ -175,7 +192,7 @@ enum
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 162
|
||||
#define LANG_STRINGS_NUM 179
|
||||
#define LANG_ID_SIZE 64
|
||||
#define LANG_STR_SIZE 384
|
||||
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
|
||||
@@ -187,4 +204,4 @@ namespace Lang
|
||||
void SetTranslation(int32_t lang_idx);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+17
-10
@@ -139,41 +139,43 @@ void InitImgui()
|
||||
sceSystemServiceParamGetInt( ORBIS_SYSTEM_SERVICE_PARAM_ID_LANG, &lang_idx );
|
||||
|
||||
lang = Util::Trim(lang, " ");
|
||||
if (lang.compare("Korean") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_KOREAN))
|
||||
bool use_system_lang = lang.empty() || lang.compare("Default") == 0;
|
||||
|
||||
if (lang.compare("Korean") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_KOREAN))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesKorean());
|
||||
}
|
||||
else if (lang.compare("Simplified Chinese") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_CHINESE_S))
|
||||
else if (lang.compare("Simplified Chinese") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_CHINESE_S))
|
||||
{
|
||||
ImFontConfig config;
|
||||
config.OversampleH = 1;
|
||||
config.OversampleV = 1;
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, &config, io.Fonts->GetGlyphRangesChineseFull());
|
||||
}
|
||||
else if (lang.compare("Traditional Chinese") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_CHINESE_T))
|
||||
else if (lang.compare("Traditional Chinese") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_CHINESE_T))
|
||||
{
|
||||
ImFontConfig config;
|
||||
config.OversampleH = 1;
|
||||
config.OversampleV = 1;
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, &config, io.Fonts->GetGlyphRangesChineseFull());
|
||||
}
|
||||
else if (lang.compare("Japanese") == 0 || lang.compare("Ryukyuan") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_JAPANESE))
|
||||
else if (lang.compare("Japanese") == 0 || lang.compare("Ryukyuan") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_JAPANESE))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesJapanese());
|
||||
}
|
||||
else if (lang.compare("Thai") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_THAI))
|
||||
else if (lang.compare("Thai") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_THAI))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesThai());
|
||||
}
|
||||
else if (lang.compare("Vietnamese") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_VIETNAMESE))
|
||||
else if (lang.compare("Vietnamese") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_VIETNAMESE))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesVietnamese());
|
||||
}
|
||||
else if (lang.compare("Greek") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_GREEK))
|
||||
else if (lang.compare("Greek") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_GREEK))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, io.Fonts->GetGlyphRangesGreek());
|
||||
}
|
||||
else if (lang.compare("Arabic") == 0 || (lang.empty() && lang_idx == ORBIS_SYSTEM_PARAM_LANG_ARABIC))
|
||||
else if (lang.compare("Arabic") == 0 || (use_system_lang && lang_idx == ORBIS_SYSTEM_PARAM_LANG_ARABIC))
|
||||
{
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/Roboto_ext.ttf", 26.0f, NULL, arabic);
|
||||
}
|
||||
@@ -292,13 +294,12 @@ int main()
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_AUDIOOUT) < 0 || sceAudioOutInit() != 0) return 0;
|
||||
if (sceSysmoduleLoadModuleInternal(ORBIS_SYSMODULE_INTERNAL_NET) < 0 || sceNetInit() != 0) return 0;
|
||||
|
||||
sceNetPoolCreate("simple", NET_HEAP_SIZE, 0);
|
||||
sceNetPoolCreate("ezremote_client", NET_HEAP_SIZE, 0);
|
||||
|
||||
if (INSTALLER::Init() < 0)
|
||||
return 0;
|
||||
|
||||
CONFIG::LoadConfig();
|
||||
HttpServer::Start();
|
||||
|
||||
// Create a window context
|
||||
window = SDL_CreateWindow("main", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, FRAME_WIDTH, FRAME_HEIGHT, 0);
|
||||
@@ -327,6 +328,12 @@ int main()
|
||||
|
||||
atexit(terminate);
|
||||
|
||||
HttpServer::Start();
|
||||
if (INSTALLER::StartEzRemoteServer() < 0)
|
||||
{
|
||||
Util::Notify("Cloud not load ezRemote Server. It is needed for background install and download. Please ensure Goldhen payload server is enabled");
|
||||
}
|
||||
|
||||
GUI::RenderLoop(renderer);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "common.h"
|
||||
#include "mem_file.h"
|
||||
|
||||
MemFile::MemFile(const std::string &path, size_t block_size)
|
||||
{
|
||||
this->block_size = block_size;
|
||||
this->complete = false;
|
||||
sem_init(&this->block_ready, 0, 0);
|
||||
}
|
||||
|
||||
MemFile::~MemFile()
|
||||
{
|
||||
for (int i = 0; i < this->mem_blocks.size(); i++)
|
||||
{
|
||||
if (this->mem_blocks[i] != nullptr && this->mem_blocks[i]->status != MEM_BLOCK_STATUS_DELETED)
|
||||
{
|
||||
if (this->mem_blocks[i]->buf != nullptr)
|
||||
{
|
||||
free(this->mem_blocks[i]->buf);
|
||||
this->mem_blocks[i]->buf = nullptr;
|
||||
}
|
||||
free(this->mem_blocks[i]);
|
||||
}
|
||||
}
|
||||
sem_destroy(&this->block_ready);
|
||||
};
|
||||
|
||||
int MemFile::Open()
|
||||
{
|
||||
this->block_in_progress = NewBlock();
|
||||
this->block_in_progress->buf = malloc(block_size);
|
||||
|
||||
return (block_in_progress->buf == nullptr);
|
||||
}
|
||||
|
||||
size_t MemFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
{
|
||||
int first_block_num, block_num;
|
||||
size_t block_offset;
|
||||
size_t remaining;
|
||||
size_t bytes_read;
|
||||
size_t total_bytes_read;
|
||||
MemBlock *block;
|
||||
char *p;
|
||||
|
||||
first_block_num= offset / this->block_size;
|
||||
block_num = first_block_num;
|
||||
block_offset = offset % this->block_size;
|
||||
|
||||
while ((block_num >= this->mem_blocks.size() && !this->complete) ||
|
||||
(block_num < this->mem_blocks.size() && this->mem_blocks[block_num]->status == MEM_BLOCK_STATUS_NOT_EXISTS))
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
}
|
||||
|
||||
block = this->mem_blocks[block_num];
|
||||
if (block->status == MEM_BLOCK_STATUS_DELETED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (block_offset > block->size - 1 && this->complete)
|
||||
{
|
||||
// requested offset is pass the end of split file
|
||||
return 0;
|
||||
}
|
||||
|
||||
remaining = buf_size;
|
||||
bool eof = false;
|
||||
total_bytes_read = 0;
|
||||
p = buf;
|
||||
|
||||
while (remaining > 0 && !eof)
|
||||
{
|
||||
uint8_t *src = (uint8_t*)block->buf;
|
||||
src += block_offset;
|
||||
bytes_read = block_size - block_offset;
|
||||
memcpy(p, src, bytes_read);
|
||||
|
||||
if (bytes_read == remaining)
|
||||
{
|
||||
p += bytes_read;
|
||||
total_bytes_read += bytes_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
p += bytes_read;
|
||||
total_bytes_read += bytes_read;
|
||||
if (block->is_last)
|
||||
{
|
||||
eof = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
remaining -= bytes_read;
|
||||
|
||||
if (remaining == 0)
|
||||
continue;
|
||||
|
||||
block_num++;
|
||||
block_offset = 0;
|
||||
|
||||
while ((block_num > this->mem_blocks.size() - 1 && !this->complete) ||
|
||||
this->mem_blocks[block_num]->status == MEM_BLOCK_STATUS_NOT_EXISTS)
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
}
|
||||
|
||||
block = this->mem_blocks[block_num];
|
||||
}
|
||||
|
||||
// delete blocks before the first read offset block. Assumuption, that reads are always
|
||||
// forward and won't read previously already read blocks. For safety, keeping only current block and 2 previous blocks
|
||||
for (int j=0; j < first_block_num - 2; j++)
|
||||
{
|
||||
if (this->mem_blocks[j]->status == MEM_BLOCK_STATUS_CREATED)
|
||||
{
|
||||
if (this->mem_blocks[j]->buf != nullptr)
|
||||
{
|
||||
free(this->mem_blocks[j]->buf);
|
||||
this->mem_blocks[j]->buf = nullptr;
|
||||
}
|
||||
this->mem_blocks[j]->status = MEM_BLOCK_STATUS_DELETED;
|
||||
}
|
||||
}
|
||||
|
||||
return total_bytes_read;
|
||||
}
|
||||
|
||||
size_t MemFile::Write(char *buf, size_t buf_size)
|
||||
{
|
||||
size_t bytes_written;
|
||||
size_t block_space_remaining;
|
||||
size_t bytes_to_write;
|
||||
|
||||
char *p = buf;
|
||||
size_t total_bytes_written = 0;
|
||||
size_t remaining_to_write = buf_size;
|
||||
|
||||
while (remaining_to_write > 0)
|
||||
{
|
||||
block_space_remaining = this->block_size - block_in_progress->size;
|
||||
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
|
||||
memcpy(block_in_progress->buf, p, bytes_to_write);
|
||||
bytes_written = bytes_to_write;
|
||||
block_in_progress->size += bytes_written;
|
||||
total_bytes_written += bytes_written;
|
||||
remaining_to_write -= bytes_written;
|
||||
block_space_remaining -= bytes_written;
|
||||
p += bytes_written;
|
||||
|
||||
// error if bytes_to_write != bytes_written
|
||||
if (bytes_written != bytes_to_write)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (block_space_remaining == 0)
|
||||
{
|
||||
block_in_progress->status = MEM_BLOCK_STATUS_CREATED;
|
||||
this->mem_blocks.push_back(block_in_progress);
|
||||
sem_post(&this->block_ready);
|
||||
|
||||
block_in_progress = NewBlock();
|
||||
}
|
||||
}
|
||||
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
int MemFile::Close()
|
||||
{
|
||||
block_in_progress->status = MEM_BLOCK_STATUS_CREATED;
|
||||
block_in_progress->is_last = true;
|
||||
this->mem_blocks.push_back(block_in_progress);
|
||||
this->complete = true;
|
||||
sem_post(&this->block_ready);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MemBlock *MemFile::NewBlock()
|
||||
{
|
||||
MemBlock *block = (MemBlock *)malloc(sizeof(MemBlock));
|
||||
memset(block, 0, sizeof(MemBlock));
|
||||
|
||||
block->is_last = false;
|
||||
block->size = 0;
|
||||
block->buf = malloc(block_size);
|
||||
|
||||
return block;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef EZ_MEM_FILE_H
|
||||
#define EZ_MEM_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <pthread.h>
|
||||
|
||||
enum MemBlockStatus
|
||||
{
|
||||
MEM_BLOCK_STATUS_NOT_EXISTS,
|
||||
MEM_BLOCK_STATUS_CREATED,
|
||||
MEM_BLOCK_STATUS_DELETED
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
void* buf;
|
||||
bool is_last;
|
||||
MemBlockStatus status;
|
||||
} MemBlock;
|
||||
|
||||
class MemFile
|
||||
{
|
||||
public:
|
||||
MemFile(const std::string& path, size_t block_size);
|
||||
~MemFile();
|
||||
size_t Read(char* buf, size_t buf_size, size_t offset);
|
||||
size_t Write(char* buf, size_t buf_size);
|
||||
int Open();
|
||||
int Close();
|
||||
|
||||
private:
|
||||
std::vector<MemBlock*> mem_blocks;
|
||||
size_t write_offset;
|
||||
size_t block_size;
|
||||
int write_error;
|
||||
bool complete;
|
||||
MemBlock *block_in_progress;
|
||||
sem_t block_ready;
|
||||
|
||||
MemBlock *NewBlock();
|
||||
};
|
||||
|
||||
#endif
|
||||
+22
-15
@@ -45,25 +45,32 @@ static void build_iovec(struct iovec** iov, int* iovlen, const char* name, const
|
||||
|
||||
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;
|
||||
struct iovec* iov = NULL;
|
||||
int iovlen = 0;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
build_iovec(&iov, &iovlen, "dirmask", mode, -1);
|
||||
build_iovec(&iov, &iovlen, "mask", mode, -1);
|
||||
}
|
||||
ret = nmount(iov, iovlen, flags);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
return nmount(iov, iovlen, flags);
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Variables for (un)jailbreaking
|
||||
|
||||
+484
-137
@@ -8,6 +8,15 @@
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "clients/nfsclient.h"
|
||||
#include "clients/webdav.h"
|
||||
#include "clients/apache.h"
|
||||
#include "clients/archiveorg.h"
|
||||
#include "clients/github.h"
|
||||
#include "clients/iis.h"
|
||||
#include "clients/myrient.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/rclone.h"
|
||||
#include "filehost/filehost.h"
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
@@ -24,11 +33,21 @@
|
||||
#define SUCCESS_MSG "{ \"result\": { \"success\": true, \"error\": null } }"
|
||||
#define FAILURE_MSG "{ \"result\": { \"success\": false, \"error\": \"%s\" } }"
|
||||
#define SUCCESS_MSG_LEN 48
|
||||
#define PKG_INITIAL_REQUEST_SIZE 8388608ul
|
||||
|
||||
using namespace httplib;
|
||||
|
||||
struct RemoteDownloadData
|
||||
{
|
||||
RemoteClient *client = nullptr;
|
||||
std::map<std::string, void *> fp_handles;
|
||||
};
|
||||
|
||||
static RemoteDownloadData remote_data[100];
|
||||
|
||||
Server *svr;
|
||||
int http_server_port = 8080;
|
||||
int http_int_server_port = 6701;
|
||||
char compressed_file_path[1024];
|
||||
bool web_server_enabled = false;
|
||||
|
||||
@@ -91,22 +110,22 @@ namespace HttpServer
|
||||
return s;
|
||||
}
|
||||
|
||||
void failed(Response & res, int status, const std::string &msg)
|
||||
void failed(Response &res, int status, const std::string &msg)
|
||||
{
|
||||
res.status = status;
|
||||
char response_msg[msg.length()+strlen(FAILURE_MSG)+2];
|
||||
char response_msg[msg.length() + strlen(FAILURE_MSG) + 2];
|
||||
snprintf(response_msg, sizeof(response_msg), "{ \"result\": { \"success\": false, \"error\": \"%s\" } }", msg.c_str());
|
||||
res.set_content(response_msg, strlen(response_msg), "application/json");
|
||||
return;
|
||||
}
|
||||
|
||||
void bad_request(Response & res, const std::string &msg)
|
||||
void bad_request(Response &res, const std::string &msg)
|
||||
{
|
||||
failed(res, 200, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
void success(Response & res)
|
||||
void success(Response &res)
|
||||
{
|
||||
res.status = 200;
|
||||
res.set_content(SUCCESS_MSG, SUCCESS_MSG_LEN, "application/json");
|
||||
@@ -182,15 +201,93 @@ namespace HttpServer
|
||||
return 1;
|
||||
}
|
||||
|
||||
static RemoteClient *GetRemoteClient(int site_idx, bool new_client)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
RemoteSettings *tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
if (!new_client)
|
||||
{
|
||||
tmp_client = remote_data[site_idx].client;
|
||||
if (tmp_client != nullptr)
|
||||
return tmp_client;
|
||||
}
|
||||
|
||||
if (tmp_settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_WEBDAV)
|
||||
{
|
||||
tmp_client = new WebDAVClient();
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_GOOGLE)
|
||||
{
|
||||
if (remoteclient != nullptr && remoteclient->clientType() == CLIENT_TYPE_GOOGLE)
|
||||
tmp_client = remoteclient;
|
||||
else
|
||||
tmp_client = new GDriveClient();
|
||||
tmp_client->Connect("", "", "");
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0)
|
||||
tmp_client = new ApacheClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MS_IIS) == 0)
|
||||
tmp_client = new IISClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NGINX) == 0)
|
||||
tmp_client = new NginxClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_NPX_SERVE) == 0)
|
||||
tmp_client = new NpxServeClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_RCLONE) == 0)
|
||||
tmp_client = new RCloneClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_ARCHIVEORG) == 0)
|
||||
tmp_client = new ArchiveOrgClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_MYRIENT) == 0)
|
||||
tmp_client = new MyrientClient();
|
||||
else if (strcmp(remote_settings->http_server_type, HTTP_SERVER_GITHUB) == 0)
|
||||
tmp_client = new GithubClient();
|
||||
}
|
||||
|
||||
if (tmp_client->clientType() != CLIENT_TYPE_GOOGLE)
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
|
||||
if (!new_client && tmp_client->clientType() != CLIENT_TYPE_FTP)
|
||||
{
|
||||
remote_data[site_idx].client = tmp_client;
|
||||
}
|
||||
|
||||
return tmp_client;
|
||||
}
|
||||
|
||||
static void DeleteRemoteClient(RemoteClient *tmp_client, int site_idx)
|
||||
{
|
||||
if (tmp_client != nullptr && tmp_client->clientType() != CLIENT_TYPE_GOOGLE)
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
}
|
||||
}
|
||||
|
||||
void *ServerThread(void *argp)
|
||||
{
|
||||
svr->Get("/", [&](const Request & req, Response & res)
|
||||
{
|
||||
res.set_redirect("/index.html");
|
||||
});
|
||||
svr->Get("/", [&](const Request &req, Response &res)
|
||||
{ res.set_redirect("/index.html"); });
|
||||
|
||||
svr->Get("/index.html", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/index.html", [&](const Request &req, Response &res)
|
||||
{
|
||||
FILE *in = FS::OpenRead("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/index.html");
|
||||
size_t size = FS::GetSize("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/index.html");
|
||||
res.set_content_provider(
|
||||
@@ -206,11 +303,10 @@ namespace HttpServer
|
||||
},
|
||||
[in](bool success) {
|
||||
FS::Close(in);
|
||||
});
|
||||
});
|
||||
}); });
|
||||
|
||||
svr->Get("/favicon.ico", [&](const Request & req, Response & res)
|
||||
{
|
||||
svr->Get("/favicon.ico", [&](const Request &req, Response &res)
|
||||
{
|
||||
FILE *in = FS::OpenRead("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/favicon.ico");
|
||||
size_t size = FS::GetSize("/mnt/sandbox/pfsmnt/RMTC00001-app0/assets/favicon.ico");
|
||||
res.set_content_provider(
|
||||
@@ -226,10 +322,9 @@ namespace HttpServer
|
||||
},
|
||||
[in](bool success) {
|
||||
FS::Close(in);
|
||||
});
|
||||
});
|
||||
}); });
|
||||
|
||||
svr->Post("/__local__/list", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/list", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *path;
|
||||
bool onlyFolders = false;
|
||||
@@ -275,11 +370,11 @@ namespace HttpServer
|
||||
json_object *results = json_object_new_object();
|
||||
json_object_object_add(results, "result", json_files);
|
||||
const char *results_str = json_object_to_json_string(results);
|
||||
res.status = 200;
|
||||
res.set_content(results_str, strlen(results_str), "application/json");
|
||||
});
|
||||
|
||||
svr->Post("/__local__/rename", [&](const Request & req, Response & res)
|
||||
res.status = 200;
|
||||
res.set_content(results_str, strlen(results_str), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/rename", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *item;
|
||||
const char *newItemPath;
|
||||
@@ -302,11 +397,16 @@ namespace HttpServer
|
||||
|
||||
FS::Rename(item, newItemPath);
|
||||
success(res);
|
||||
return;
|
||||
});
|
||||
return; });
|
||||
|
||||
svr->Post("/__local__/move", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/move", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
const json_object *items;
|
||||
const char *newPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -357,11 +457,16 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/copy", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/copy", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
const json_object *items;
|
||||
const char *newPath;
|
||||
const char *singleFilename;
|
||||
@@ -432,11 +537,16 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/remove", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/remove", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *items;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -472,11 +582,16 @@ namespace HttpServer
|
||||
failed(res, 200, error_msg);
|
||||
}
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/install", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/install", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *items;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -512,7 +627,7 @@ namespace HttpServer
|
||||
success(res);
|
||||
});
|
||||
|
||||
svr->Post("/__local__/edit", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/edit", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *item;
|
||||
const char *content;
|
||||
@@ -543,10 +658,9 @@ namespace HttpServer
|
||||
return;
|
||||
}
|
||||
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Post("/__local__/getContent", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/getContent", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *item;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -569,11 +683,12 @@ namespace HttpServer
|
||||
json_object *result = json_object_new_object();
|
||||
json_object_object_add(result, "result", json_object_new_string(content.data()));
|
||||
const char *result_str = json_object_to_json_string(result);
|
||||
|
||||
res.status = 200;
|
||||
res.set_content(result_str, strlen(result_str), "application/json");
|
||||
});
|
||||
|
||||
svr->Post("/__local__/createFolder", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/createFolder", [&](const Request &req, Response &res)
|
||||
{
|
||||
const char *newPath;
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
@@ -596,13 +711,19 @@ namespace HttpServer
|
||||
success(res);
|
||||
});
|
||||
|
||||
svr->Post("/__local__/permission", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/permission", [&](const Request &req, Response &res)
|
||||
{
|
||||
failed(res, 200, "Operation not supported");
|
||||
});
|
||||
|
||||
svr->Post("/__local__/compress", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/compress", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
json_object *items;
|
||||
const char* destination;
|
||||
const char* compressedFilename;
|
||||
@@ -652,11 +773,16 @@ namespace HttpServer
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Failed to create zip");
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
svr->Post("/__local__/extract", [&](const Request & req, Response & res)
|
||||
svr->Post("/__local__/extract", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (activity_inprogess)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ACTIVITY_IN_PROGRESS_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* item;
|
||||
const char* destination;
|
||||
const char* folderName;
|
||||
@@ -692,8 +818,7 @@ namespace HttpServer
|
||||
else if (ret == -1)
|
||||
failed(res, 200, "Unsupported compressed file format");
|
||||
else
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
svr->Get("/__local__/uploadResumeSize", [&](const Request &req, Response &res)
|
||||
{
|
||||
@@ -705,8 +830,7 @@ namespace HttpServer
|
||||
size = FS::GetSize(file_path);
|
||||
std::string result_str = "{\"size\":" + std::to_string(size) + "}";
|
||||
res.status = 200;
|
||||
res.set_content(result_str.c_str(), result_str.length(), "application/json");
|
||||
});
|
||||
res.set_content(result_str.c_str(), result_str.length(), "application/json"); });
|
||||
|
||||
svr->Post("/__local__/upload", [&](const Request &req, Response &res, const ContentReader &content_reader)
|
||||
{
|
||||
@@ -775,11 +899,10 @@ namespace HttpServer
|
||||
{
|
||||
FS::Close(out);
|
||||
}
|
||||
success(res);
|
||||
});
|
||||
success(res); });
|
||||
|
||||
// Download multiple files as ZIP
|
||||
svr->Get("/__local__/downloadMultiple", [&](const Request & req, Response & res)
|
||||
svr->Get("/__local__/downloadMultiple", [&](const Request &req, Response &res)
|
||||
{
|
||||
if (req.get_param_value_count("items") == 0 || req.get_param_value_count("toFilename") == 0)
|
||||
{
|
||||
@@ -834,11 +957,10 @@ namespace HttpServer
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Failed to create zip");
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
// Download single file
|
||||
svr->Get("/__local__/downloadFile", [&](const Request & req, Response & res)
|
||||
svr->Get("/__local__/downloadFile", [&](const Request &req, Response &res)
|
||||
{
|
||||
std::string path = req.get_param_value("path", 0);
|
||||
if (path.empty())
|
||||
@@ -869,8 +991,7 @@ namespace HttpServer
|
||||
},
|
||||
[in](bool success) {
|
||||
FS::Close(in);
|
||||
});
|
||||
});
|
||||
}); });
|
||||
|
||||
svr->Get("/google_auth", [](const Request &req, Response &res)
|
||||
{
|
||||
@@ -883,7 +1004,7 @@ namespace HttpServer
|
||||
std::string post_data = std::string("code=") + auth_code +
|
||||
"&client_id=" + gg_app.client_id +
|
||||
"&client_secret=" + gg_app.client_secret +
|
||||
"&redirect_uri=http%3A//localhost%3A" + std::to_string(http_server_port) + "/google_auth"
|
||||
"&redirect_uri=http%3A//127.0.0.1%3A" + std::to_string(http_server_port) + "/google_auth"
|
||||
"&grant_type=authorization_code";
|
||||
|
||||
if (auto result = client.Post(url, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded"))
|
||||
@@ -922,9 +1043,9 @@ namespace HttpServer
|
||||
res.set_content(str.c_str(), "text/plain");
|
||||
});
|
||||
|
||||
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request & req, Response & res)
|
||||
svr->Get("/rmt_inst/Site (\\d+)(/)(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
RemoteClient *tmp_client = nullptr;
|
||||
RemoteSettings *tmp_settings;
|
||||
auto site_idx = std::stoi(req.matches[1])-1;
|
||||
std::string path;
|
||||
@@ -932,33 +1053,6 @@ namespace HttpServer
|
||||
if (site_idx != 98)
|
||||
{
|
||||
path = std::string("/") + std::string(req.matches[3]);
|
||||
|
||||
tmp_settings = &site_settings[sites[site_idx]];
|
||||
|
||||
if (tmp_settings->type == CLIENT_TYPE_SFTP)
|
||||
{
|
||||
tmp_client = new SFTPClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_SMB)
|
||||
{
|
||||
tmp_client = new SmbClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_FTP)
|
||||
{
|
||||
tmp_client = new FtpClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else if (tmp_settings->type == CLIENT_TYPE_NFS)
|
||||
{
|
||||
tmp_client = new NfsClient();
|
||||
tmp_client->Connect(tmp_settings->server, tmp_settings->username, tmp_settings->password);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp_client = remoteclient;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -973,33 +1067,34 @@ namespace HttpServer
|
||||
tmp_client->Connect(host, "", "");
|
||||
}
|
||||
|
||||
if (tmp_client == nullptr || !tmp_client->IsConnected())
|
||||
{
|
||||
res.status = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (req.method == "HEAD")
|
||||
{
|
||||
int64_t file_size;
|
||||
int ret;
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, true);
|
||||
|
||||
ret = tmp_client->Size(path, &file_size);
|
||||
if (!ret)
|
||||
{
|
||||
res.status = 500;
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
res.status = 204;
|
||||
res.set_header("Content-Length", std::to_string(file_size));
|
||||
res.set_header("Accept-Ranges", "bytes");
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.ranges.empty())
|
||||
{
|
||||
res.status = 200;
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, true);
|
||||
|
||||
res.set_content_provider(
|
||||
(1024*128), "application/octet-stream",
|
||||
[tmp_client, path](size_t offset, size_t length, DataSink &sink) {
|
||||
@@ -1007,15 +1102,7 @@ namespace HttpServer
|
||||
return (ret == 1);
|
||||
},
|
||||
[tmp_client, path, site_idx](bool success) {
|
||||
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|
||||
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
}
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
});
|
||||
}
|
||||
else
|
||||
@@ -1024,32 +1111,60 @@ namespace HttpServer
|
||||
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
|
||||
if (req.ranges[0].second >= 18000000000000000000ul)
|
||||
{
|
||||
range_len = 524288ul;
|
||||
range_len = PKG_INITIAL_REQUEST_SIZE;
|
||||
res.set_header("Content-Length", std::to_string(range_len));
|
||||
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len));
|
||||
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+PKG_INITIAL_REQUEST_SIZE-1) + "/"+std::to_string(range_len));
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (site_idx != 98)
|
||||
tmp_client = GetRemoteClient(site_idx, false);
|
||||
}
|
||||
|
||||
std::pair<ssize_t, ssize_t> range = req.ranges[0];
|
||||
res.set_content_provider(
|
||||
range_len, "application/octet-stream",
|
||||
[tmp_client, path, range, range_len](size_t offset, size_t length, DataSink &sink) {
|
||||
int ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
return (ret == 1);
|
||||
},
|
||||
[tmp_client, site_idx, path, range, range_len](bool success) {
|
||||
if (tmp_client != nullptr && (tmp_client->clientType() == CLIENT_TYPE_SFTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_SMB
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_FTP
|
||||
|| tmp_client->clientType() == CLIENT_TYPE_NFS
|
||||
|| (tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98)))
|
||||
[tmp_client, path, range, range_len, site_idx](size_t offset, size_t length, DataSink &sink) {
|
||||
int ret;
|
||||
if (range_len == PKG_INITIAL_REQUEST_SIZE)
|
||||
{
|
||||
tmp_client->Quit();
|
||||
delete tmp_client;
|
||||
ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
}
|
||||
else if ((tmp_client->SupportedActions() & REMOTE_ACTION_RAW_READ) == 0)
|
||||
{
|
||||
ret = tmp_client->GetRange(path, sink, range_len, range.first);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::map<std::string, void *>::iterator it = remote_data[site_idx].fp_handles.find(path);
|
||||
void *fp;
|
||||
if (it == remote_data[site_idx].fp_handles.end())
|
||||
{
|
||||
fp = tmp_client->Open(path, O_RDONLY);
|
||||
remote_data[site_idx].fp_handles[path] = fp;
|
||||
}
|
||||
else
|
||||
{
|
||||
fp = it->second;
|
||||
}
|
||||
ret = tmp_client->GetRange(fp, sink, range_len, range.first);
|
||||
}
|
||||
return (ret==1);
|
||||
},
|
||||
[tmp_client, path, range, site_idx](bool success) {
|
||||
if (range.second >= 18000000000000000000ul ||
|
||||
(tmp_client->clientType() == CLIENT_TYPE_HTTP_SERVER && site_idx == 98) ||
|
||||
tmp_client->clientType() == CLIENT_TYPE_FTP)
|
||||
{
|
||||
DeleteRemoteClient(tmp_client, site_idx);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} });
|
||||
|
||||
svr->Get("/archive_inst/(.*)", [&](const Request & req, Response & res)
|
||||
svr->Get("/archive_inst/(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
RemoteClient *tmp_client;
|
||||
RemoteSettings *tmp_settings;
|
||||
@@ -1087,9 +1202,10 @@ namespace HttpServer
|
||||
size_t range_len = (req.ranges[0].second - req.ranges[0].first) + 1;
|
||||
if (req.ranges[0].second >= 18000000000000000000ul)
|
||||
{
|
||||
range_len = 524288ul;
|
||||
range_len = PKG_INITIAL_REQUEST_SIZE;
|
||||
res.set_header("Content-Length", std::to_string(range_len));
|
||||
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+524288ul-1) + "/"+std::to_string(range_len));
|
||||
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+PKG_INITIAL_REQUEST_SIZE-1) + "/"+std::to_string(range_len));
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
}
|
||||
std::pair<ssize_t, ssize_t> range = req.ranges[0];
|
||||
res.set_content_provider(
|
||||
@@ -1107,12 +1223,76 @@ namespace HttpServer
|
||||
}
|
||||
});
|
||||
|
||||
svr->Post("/__local__/install_url", [&](const Request & req, Response & res)
|
||||
svr->Get("/split_inst/(.*)", [&](const Request &req, Response &res)
|
||||
{
|
||||
std::string hash = req.matches[1];
|
||||
|
||||
SplitPkgInstallData *pkg_data = INSTALLER::GetSplitPkgInstallData(hash);
|
||||
|
||||
if (pkg_data == nullptr)
|
||||
{
|
||||
failed(res, 500, "Cannot resume split_inst");
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.method == "HEAD")
|
||||
{
|
||||
res.status = 204;
|
||||
res.set_header("Content-Length", std::to_string(pkg_data->size));
|
||||
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 = PKG_INITIAL_REQUEST_SIZE;
|
||||
res.set_header("Content-Length", std::to_string(range_len));
|
||||
res.set_header("Content-Range", std::string("bytes ") + std::to_string(req.ranges[0].first)+"-" + std::to_string(req.ranges[0].first+PKG_INITIAL_REQUEST_SIZE-1) + "/"+std::to_string(range_len));
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
}
|
||||
std::pair<ssize_t, ssize_t> range = req.ranges[0];
|
||||
res.set_content_provider(
|
||||
range_len, "application/octet-stream",
|
||||
[pkg_data, range, range_len](size_t offset, size_t length, DataSink &sink) {
|
||||
char *buf = (char*) malloc(range_len);
|
||||
size_t bytes_read = pkg_data->split_file->Read(buf, range_len, range.first);
|
||||
sink.write(buf, bytes_read);
|
||||
free(buf);
|
||||
return true;
|
||||
},
|
||||
[](bool success) {
|
||||
return true;
|
||||
});
|
||||
} });
|
||||
|
||||
svr->Post("/__local__/install_url", [&](const Request &req, Response &res)
|
||||
{
|
||||
std::string url;
|
||||
const char *url_param;
|
||||
bool use_alldebrid = false;
|
||||
bool use_realdebrid = false;
|
||||
bool use_disk_cache = false;
|
||||
bool enable_rpi = false;
|
||||
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
@@ -1120,6 +1300,9 @@ namespace HttpServer
|
||||
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
|
||||
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
|
||||
use_realdebrid = json_object_get_boolean(json_object_object_get(jobj, "use_realdebrid"));
|
||||
use_disk_cache = json_object_get_boolean(json_object_object_get(jobj, "use_disk_cache"));
|
||||
enable_rpi = json_object_get_boolean(json_object_object_get(jobj, "enable_rpi"));
|
||||
|
||||
if (url_param == nullptr)
|
||||
{
|
||||
bad_request(res, "Required url_param parameter missing");
|
||||
@@ -1153,6 +1336,8 @@ namespace HttpServer
|
||||
file_transfering = true;
|
||||
bytes_to_download = 100;
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
Windows::SetModalMode(true);
|
||||
|
||||
std::string download_url = filehost->GetDownloadUrl();
|
||||
@@ -1161,10 +1346,9 @@ namespace HttpServer
|
||||
failed(res, 200, lang_strings[STR_CANT_EXTRACT_URL_MSG]);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(true);
|
||||
Windows::SetModalMode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
delete(filehost);
|
||||
|
||||
size_t scheme_pos = download_url.find("://");
|
||||
@@ -1175,23 +1359,86 @@ namespace HttpServer
|
||||
|
||||
BaseClient *baseclient = new BaseClient();
|
||||
baseclient->Connect(host, "", "");
|
||||
|
||||
if (!baseclient->FileExists(path))
|
||||
{
|
||||
failed(res, 200, baseclient->LastResponse());
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
FileHost::AddCacheDownloadUrl(hash, download_url);
|
||||
std::string title = INSTALLER::GetRemotePkgTitle(baseclient, path, &header);
|
||||
|
||||
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_server_port) + "/rmt_inst/Site%2099/" + hash;
|
||||
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title, false);
|
||||
if (rc == 0)
|
||||
if (BE32(header.pkg_magic) == 0x7F434E54)
|
||||
{
|
||||
if (enable_rpi && !use_disk_cache)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(true);
|
||||
return;
|
||||
json_object *history_item_obj = json_object_new_object();
|
||||
json_object_object_add(history_item_obj, "hash", json_object_new_string(hash.c_str()));
|
||||
json_object_object_add(history_item_obj, "url", json_object_new_string(host.c_str()));
|
||||
json_object_object_add(history_item_obj, "path", json_object_new_string(path.c_str()));
|
||||
json_object_object_add(history_item_obj, "username", json_object_new_string(""));
|
||||
json_object_object_add(history_item_obj, "password", json_object_new_string(""));
|
||||
json_object_object_add(history_item_obj, "type", json_object_new_int(CLIENT_TYPE_FILEHOST));
|
||||
|
||||
const char *params_str = json_object_to_json_string(history_item_obj);
|
||||
|
||||
Client tmp_client = Client(std::string("http://127.0.0.1:") + std::to_string(http_int_server_port));
|
||||
|
||||
if (auto resp = tmp_client.Post("/store_bg_install_data", params_str, strlen(params_str), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(resp->status))
|
||||
{
|
||||
std::string remote_install_url = std::string("http://localhost:") + std::to_string(http_int_server_port) + "/bg_install/" + hash;
|
||||
int rc = INSTALLER::InstallRemotePkg(remote_install_url, &header, title);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
sleep(2);
|
||||
}
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Could not save host data for background install");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
failed(res, 200, "Could not save host data for background install");
|
||||
}
|
||||
}
|
||||
else if (enable_rpi && use_disk_cache)
|
||||
{
|
||||
SplitPkgInstallData *install_data = (SplitPkgInstallData*) malloc(sizeof(SplitPkgInstallData));
|
||||
memset(install_data, 0, sizeof(SplitPkgInstallData));
|
||||
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
std::string install_pkg_path = std::string(temp_folder) + "/" + std::to_string(tick.mytick) + ".pkg";
|
||||
SplitFile *sp = new SplitFile(install_pkg_path, INSTALL_ARCHIVE_PKG_SPLIT_SIZE/2);
|
||||
|
||||
install_data->split_file = sp;
|
||||
install_data->remote_client = baseclient;
|
||||
install_data->path = path;
|
||||
baseclient->Size(path, &install_data->size);
|
||||
install_data->stop_write_thread = false;
|
||||
install_data->delete_client = true;
|
||||
|
||||
int ret = pthread_create(&install_data->thread, NULL, Actions::DownloadSplitPkg, install_data);
|
||||
|
||||
ret = INSTALLER::InstallSplitPkg(download_url, install_data, true);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
Windows::SetModalMode(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1218,6 +1465,7 @@ namespace HttpServer
|
||||
failed(res, 200, lang_strings[STR_FAIL_INSTALL_FROM_URL_MSG]);
|
||||
activity_inprogess = false;
|
||||
file_transfering = false;
|
||||
free(install_data);
|
||||
Windows::SetModalMode(false);
|
||||
return;
|
||||
}
|
||||
@@ -1232,6 +1480,105 @@ namespace HttpServer
|
||||
}
|
||||
}
|
||||
success(res);
|
||||
|
||||
});
|
||||
|
||||
svr->Post("/__local__/download_url", [&](const Request &req, Response &res)
|
||||
{
|
||||
std::string url;
|
||||
std::string dest;
|
||||
const char *url_param;
|
||||
const char *dest_param;
|
||||
bool use_alldebrid = false;
|
||||
bool use_realdebrid = false;
|
||||
|
||||
json_object *jobj = json_tokener_parse(req.body.c_str());
|
||||
if (jobj != nullptr)
|
||||
{
|
||||
url_param = json_object_get_string(json_object_object_get(jobj, "url"));
|
||||
dest_param = json_object_get_string(json_object_object_get(jobj, "dest"));
|
||||
use_alldebrid = json_object_get_boolean(json_object_object_get(jobj, "use_alldebrid"));
|
||||
use_realdebrid = json_object_get_boolean(json_object_object_get(jobj, "use_realdebrid"));
|
||||
|
||||
if (url_param == nullptr || dest_param == nullptr)
|
||||
{
|
||||
bad_request(res, "Required url, dest parameter missing");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_request(res, "Invalid payload");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((use_alldebrid && strlen(alldebrid_api_key) == 0) || (use_realdebrid && strlen(realdebrid_api_key) == 0))
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_ALLDEBRID_API_KEY_MISSING_MSG]);
|
||||
return;
|
||||
}
|
||||
|
||||
url = std::string(url_param);
|
||||
FileHost *filehost = FileHost::getFileHost(url, use_alldebrid, use_realdebrid);
|
||||
|
||||
if (!filehost->IsValidUrl())
|
||||
{
|
||||
failed(res, 200, lang_strings[STR_INVALID_URL]);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string 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);
|
||||
int64_t file_size;
|
||||
|
||||
RemoteClient *baseclient = new BaseClient();
|
||||
baseclient->Connect(host, "", "");
|
||||
baseclient->Size(path, &file_size);
|
||||
delete baseclient;
|
||||
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
json_object *params = json_object_new_object();
|
||||
json_object_object_add(params, "type", json_object_new_int(CLIENT_TYPE_FILEHOST));
|
||||
json_object_object_add(params, "url", json_object_new_string(host.c_str()));
|
||||
json_object_object_add(params, "username", json_object_new_string(""));
|
||||
json_object_object_add(params, "password", json_object_new_string(""));
|
||||
json_object_object_add(params, "src_path", json_object_new_string(path.c_str()));
|
||||
json_object_object_add(params, "dest_path", json_object_new_string(dest_param));
|
||||
json_object_object_add(params, "size", json_object_new_uint64(file_size));
|
||||
json_object_object_add(params, "id", json_object_new_uint64(tick.mytick));
|
||||
|
||||
const char *params_str = json_object_to_json_string(params);
|
||||
httplib::Client tmp_client = httplib::Client(std::string("http://127.0.0.1:") + std::to_string(http_int_server_port));
|
||||
|
||||
std::string download_req_url = + "/download_url";
|
||||
if (auto resp = tmp_client.Post(download_req_url, params_str, strlen(params_str), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(resp->status))
|
||||
{
|
||||
Util::Notify("%s queued for download", path.c_str());
|
||||
success(res);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Util::Notify("Failed to queue %s for download in background", path.c_str());
|
||||
failed(res, 200, "Failed to download");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
failed(res, 200, "Failed to download");
|
||||
});
|
||||
|
||||
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
|
||||
@@ -1257,7 +1604,7 @@ namespace HttpServer
|
||||
svr->set_payload_max_length(1024 * 1024 * 12);
|
||||
svr->set_tcp_nodelay(true);
|
||||
svr->set_mount_point("/", "/");
|
||||
|
||||
|
||||
if (web_server_enabled)
|
||||
svr->listen("0.0.0.0", http_server_port);
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef HTTP_SERVER_H
|
||||
#define HTTP_SERVER_H
|
||||
#ifndef EZ_HTTP_SERVER_H
|
||||
#define EZ_HTTP_SERVER_H
|
||||
|
||||
#include "http/httplib.h"
|
||||
|
||||
@@ -8,6 +8,7 @@ extern Server *svr;
|
||||
|
||||
static pthread_t http_server_thid;
|
||||
extern int http_server_port;
|
||||
extern int http_int_server_port;
|
||||
extern char compressed_file_path[];
|
||||
extern bool web_server_enabled;
|
||||
|
||||
@@ -18,4 +19,4 @@ namespace HttpServer
|
||||
void Stop();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef LAUNCHER_SFO_H
|
||||
#define LAUNCHER_SFO_H
|
||||
#ifndef EZ_SFO_H
|
||||
#define EZ_SFO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
+63
-16
@@ -24,7 +24,7 @@ SplitFile::~SplitFile()
|
||||
fclose(this->file_blocks[i]->fd);
|
||||
}
|
||||
remove(this->file_blocks[i]->block_file.c_str());
|
||||
free(this->file_blocks[i]);
|
||||
delete this->file_blocks[i];
|
||||
}
|
||||
}
|
||||
sem_destroy(&this->block_ready);
|
||||
@@ -33,8 +33,6 @@ SplitFile::~SplitFile()
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -56,9 +54,16 @@ size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
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);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += 2;
|
||||
sem_timedwait(&this->block_ready, &ts);
|
||||
}
|
||||
|
||||
// If complete and block_num is past the end, the requested offset is beyond EOF
|
||||
if (block_num >= this->file_blocks.size())
|
||||
return 0;
|
||||
|
||||
block = this->file_blocks[block_num];
|
||||
if (block->status == BLOCK_STATUS_DELETED)
|
||||
{
|
||||
@@ -118,19 +123,26 @@ size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
block_offset = 0;
|
||||
|
||||
while ((block_num > this->file_blocks.size() - 1 && !this->complete) ||
|
||||
this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS)
|
||||
(block_num < this->file_blocks.size() && this->file_blocks[block_num]->status == BLOCK_STATUS_NOT_EXISTS))
|
||||
{
|
||||
sem_wait(&this->block_ready);
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_sec += 2;
|
||||
sem_timedwait(&this->block_ready, &ts);
|
||||
}
|
||||
|
||||
// If complete and block_num is past the end, no more data
|
||||
if (block_num >= this->file_blocks.size())
|
||||
break;
|
||||
|
||||
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++)
|
||||
for (int j=0; j < first_block_num - 13; j++)
|
||||
{
|
||||
if (this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
|
||||
if (this->file_blocks[j] != nullptr && this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
|
||||
{
|
||||
if (this->file_blocks[j]->fd != nullptr)
|
||||
{
|
||||
@@ -139,23 +151,29 @@ size_t SplitFile::Read(char *buf, size_t buf_size, size_t offset)
|
||||
}
|
||||
this->file_blocks[j]->status = BLOCK_STATUS_DELETED;
|
||||
remove(this->file_blocks[j]->block_file.c_str());
|
||||
delete (this->file_blocks[j]);
|
||||
this->file_blocks[j] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
this->read_offset = offset + total_bytes_read;
|
||||
return total_bytes_read;
|
||||
}
|
||||
|
||||
size_t SplitFile::Write(char *buf, size_t buf_size)
|
||||
ssize_t SplitFile::Write(char *buf, size_t buf_size)
|
||||
{
|
||||
size_t bytes_written;
|
||||
size_t bytes_written = 0;
|
||||
size_t block_space_remaining;
|
||||
size_t bytes_to_write;
|
||||
|
||||
char *p = buf;
|
||||
size_t total_bytes_written = 0;
|
||||
ssize_t total_bytes_written = 0;
|
||||
size_t remaining_to_write = buf_size;
|
||||
|
||||
while (remaining_to_write > 0)
|
||||
if (this->IsClosed())
|
||||
return -1;
|
||||
|
||||
while (remaining_to_write > 0 && !this->complete)
|
||||
{
|
||||
block_space_remaining = this->block_size - block_in_progress->size;
|
||||
bytes_to_write = MIN(remaining_to_write, block_space_remaining);
|
||||
@@ -186,12 +204,18 @@ size_t SplitFile::Write(char *buf, size_t buf_size)
|
||||
block_in_progress = NewBlock();
|
||||
}
|
||||
}
|
||||
this->write_offset += total_bytes_written;
|
||||
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
int SplitFile::Close()
|
||||
{
|
||||
if (this->complete)
|
||||
return 0;
|
||||
|
||||
this->complete = true;
|
||||
|
||||
if (block_in_progress->fd != nullptr)
|
||||
{
|
||||
fflush(block_in_progress->fd);
|
||||
@@ -201,16 +225,39 @@ int SplitFile::Close()
|
||||
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);
|
||||
|
||||
// Wait until file is fully read, if file isn't full read
|
||||
// in 5 mins then go ahead and delete all file chunks
|
||||
int retries = 10;
|
||||
size_t prev_read_offset = 0;
|
||||
while (this->read_offset != this->write_offset && retries > 0)
|
||||
{
|
||||
if (prev_read_offset == this->read_offset)
|
||||
retries--;
|
||||
prev_read_offset = this->read_offset;
|
||||
sceKernelUsleep(1000000);
|
||||
}
|
||||
sceKernelUsleep(5000000);
|
||||
|
||||
for (size_t j = 0; j < this->file_blocks.size(); j++)
|
||||
{
|
||||
if (this->file_blocks[j] != nullptr && this->file_blocks[j]->status == BLOCK_STATUS_CREATED)
|
||||
{
|
||||
remove(this->file_blocks[j]->block_file.c_str());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SplitFile::IsClosed()
|
||||
{
|
||||
return this->complete;
|
||||
}
|
||||
|
||||
FileBlock *SplitFile::NewBlock()
|
||||
{
|
||||
FileBlock *block = (FileBlock *)malloc(sizeof(FileBlock));
|
||||
memset(block, 0, sizeof(FileBlock));
|
||||
FileBlock *block = new FileBlock{};
|
||||
|
||||
block->is_last = false;
|
||||
block->size = 0;
|
||||
@@ -218,4 +265,4 @@ FileBlock *SplitFile::NewBlock()
|
||||
block->fd = fopen(block->block_file.c_str(), "w");
|
||||
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-5
@@ -1,9 +1,10 @@
|
||||
#ifndef SPLIT_FILE_H
|
||||
#define SPLIT_FILE_H
|
||||
#ifndef EZ_SPLIT_FILE_H
|
||||
#define EZ_SPLIT_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <semaphore.h>
|
||||
#include <pthread.h>
|
||||
|
||||
enum FileBlockStatus
|
||||
@@ -28,14 +29,16 @@ 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);
|
||||
ssize_t Write(char* buf, size_t buf_size);
|
||||
int Open();
|
||||
int Close();
|
||||
bool IsClosed();
|
||||
|
||||
private:
|
||||
std::vector<FileBlock*> file_blocks;
|
||||
size_t write_offset;
|
||||
size_t write_offset = 0;
|
||||
size_t block_size;
|
||||
size_t read_offset;
|
||||
std::string path;
|
||||
int write_error;
|
||||
bool complete;
|
||||
@@ -45,4 +48,4 @@ private:
|
||||
FileBlock *NewBlock();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#ifndef EZ_SYSTEM_H
|
||||
#define EZ_SYSTEM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -42,3 +45,5 @@ void convertLocalTimeToUtc(const OrbisDateTime *local_time, OrbisDateTime *utc);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef LAUNCHER_TEXTURES_H
|
||||
#define LAUNCHER_TEXTURES_H
|
||||
#ifndef EZ_TEXTURES_H
|
||||
#define EZ_TEXTURES_H
|
||||
|
||||
#include <string>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
@@ -88,6 +88,13 @@ namespace Util
|
||||
return out;
|
||||
}
|
||||
|
||||
static uint64_t GetTick()
|
||||
{
|
||||
static struct timeval tick;
|
||||
gettimeofday(&tick, NULL);
|
||||
return tick.tv_sec * 1000000 + tick.tv_usec;
|
||||
}
|
||||
|
||||
static inline void Notify(const char *fmt, ...)
|
||||
{
|
||||
OrbisNotificationRequest request;
|
||||
|
||||
+422
-16
@@ -14,10 +14,11 @@
|
||||
#include "util.h"
|
||||
#include "lang.h"
|
||||
#include "ime_dialog.h"
|
||||
#include "IconsFontAwesome6.h"
|
||||
#include "IconsFontAwesome6.h"
|
||||
#include "OpenFontIcons.h"
|
||||
#include "textures.h"
|
||||
#include "sfo.h"
|
||||
#include "system.h"
|
||||
|
||||
#define MAX_IMAGE_HEIGHT 980
|
||||
#define MAX_IMAGE_WIDTH 1820
|
||||
@@ -30,6 +31,9 @@ extern "C"
|
||||
bool paused = false;
|
||||
int view_mode;
|
||||
static float scroll_direction = 0.0f;
|
||||
static int selected_local_position = -1;
|
||||
static int selected_remote_position = -1;
|
||||
|
||||
static ime_callback_t ime_callback = nullptr;
|
||||
static ime_callback_t ime_after_update = nullptr;
|
||||
static ime_callback_t ime_before_update = nullptr;
|
||||
@@ -37,18 +41,25 @@ static ime_callback_t ime_cancelled = nullptr;
|
||||
static std::vector<std::string> *ime_multi_field;
|
||||
static char *ime_single_field;
|
||||
static int ime_field_size;
|
||||
static bool show_ezremote_server_warning;
|
||||
|
||||
static char txt_http_server_port[6];
|
||||
static char txt_bg_download_size[32];
|
||||
|
||||
bool is_server_started = false;
|
||||
bool ezremote_server_version_match = true;
|
||||
bool handle_updates = false;
|
||||
int64_t bytes_transfered;
|
||||
int64_t bytes_to_download;
|
||||
OrbisTick prev_tick;
|
||||
|
||||
std::vector<DirEntry> local_files;
|
||||
std::vector<DirEntry> remote_files;
|
||||
std::set<DirEntry> multi_selected_local_files;
|
||||
std::set<DirEntry> multi_selected_remote_files;
|
||||
std::vector<DirEntry> local_paste_files;
|
||||
std::vector<DirEntry> remote_paste_files;
|
||||
std::vector<DownloadProgress> bg_download_progress;
|
||||
DirEntry selected_local_file;
|
||||
DirEntry selected_remote_file;
|
||||
ACTIONS selected_action;
|
||||
@@ -72,6 +83,8 @@ int favorite_url_idx = 0;
|
||||
char extract_zip_folder[256];
|
||||
char zip_file_path[384];
|
||||
bool show_settings = false;
|
||||
bool show_bg_download_progress = false;
|
||||
uint64_t refresh_bg_download_time;
|
||||
|
||||
// Editor variables
|
||||
std::vector<std::string> edit_buffer;
|
||||
@@ -118,12 +131,16 @@ namespace Windows
|
||||
sprintf(local_filter, "");
|
||||
sprintf(remote_filter, "");
|
||||
sprintf(txt_http_server_port, "%d", http_server_port);
|
||||
sprintf(txt_bg_download_size, "%lu", minimum_backgrond_file_size);
|
||||
dont_prompt_overwrite = false;
|
||||
confirm_transfer_state = -1;
|
||||
dont_prompt_overwrite_cb = false;
|
||||
overwrite_type = OVERWRITE_PROMPT;
|
||||
local_paste_files.clear();
|
||||
remote_paste_files.clear();
|
||||
std::string cur_version = INSTALLER::EzRemoteServerVersion();
|
||||
ezremote_server_version_match = cur_version.empty() || (cur_version.compare(EZREMOTE_SERVER_REQUIRED_VERSION) == 0);
|
||||
show_ezremote_server_warning = !ezremote_server_version_match;
|
||||
|
||||
Actions::RefreshLocalFiles(false);
|
||||
}
|
||||
@@ -321,11 +338,13 @@ namespace Windows
|
||||
if (ImGui::BeginCombo("##Site", display_site, ImGuiComboFlags_PopupAlignLeft | ImGuiComboFlags_HeightLargest | ImGuiComboFlags_NoArrowButton))
|
||||
{
|
||||
static char site_id[64];
|
||||
static char site_display[512];
|
||||
for (int n = 0; n < sites.size(); n++)
|
||||
{
|
||||
const bool is_selected = strcmp(sites[n].c_str(), last_site) == 0;
|
||||
sprintf(site_id, "%s %d", lang_strings[STR_SITE], n + 1);
|
||||
if (ImGui::Selectable(site_id, is_selected))
|
||||
sprintf(site_display, "%s %d %s", lang_strings[STR_SITE], n + 1, site_settings[sites[n]].server);
|
||||
if (ImGui::Selectable(site_display, is_selected))
|
||||
{
|
||||
sprintf(last_site, "%s", sites[n].c_str());
|
||||
sprintf(display_site, "%s", site_id);
|
||||
@@ -442,13 +461,33 @@ namespace Windows
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(450, 70));
|
||||
ImGui::SetNextWindowSize(ImVec2(450, 110));
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 440);
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_RPI_FTP_SMB_MSG]);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_ENABLE_DISK_CACHE]);
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Checkbox("###enable_disk_cache", &remote_settings->enable_disk_cache))
|
||||
{
|
||||
CONFIG::SaveConfig();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(550, 110));
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 540);
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_DISC_CACHE_MSG]);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
ImGui::SameLine();
|
||||
@@ -456,6 +495,7 @@ namespace Windows
|
||||
if (ImGui::Button(ICON_FA_GEAR, ImVec2(35, 0)))
|
||||
{
|
||||
show_settings = true;
|
||||
is_server_started = !INSTALLER::EzRemoteServerVersion().empty();
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
@@ -614,6 +654,22 @@ namespace Windows
|
||||
ImGui::Text("%s", item.name);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadUp) && !paused)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
selected_local_position = local_files.size()-1;
|
||||
scroll_direction = 0.0f;
|
||||
}
|
||||
}
|
||||
else if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadDown) && !paused)
|
||||
{
|
||||
if (j == local_files.size()-1)
|
||||
{
|
||||
selected_local_position = 0;
|
||||
scroll_direction = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
|
||||
{
|
||||
@@ -623,6 +679,12 @@ namespace Windows
|
||||
ImGui::SetScrollHereY(0.5f);
|
||||
sprintf(local_file_to_select, "");
|
||||
}
|
||||
if (selected_local_position == j && !paused)
|
||||
{
|
||||
SetNavFocusHere();
|
||||
ImGui::SetScrollHereY(scroll_direction);
|
||||
selected_local_position = -1;
|
||||
}
|
||||
selected_browser |= LOCAL_BROWSER;
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
@@ -779,6 +841,22 @@ namespace Windows
|
||||
ImGui::Text("%s", item.name);
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadUp) && !paused)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
selected_remote_position = remote_files.size()-1;
|
||||
scroll_direction = 0.0f;
|
||||
}
|
||||
}
|
||||
else if (ImGui::IsKeyPressed(ImGuiKey_GamepadDpadDown) && !paused)
|
||||
{
|
||||
if (j == remote_files.size()-1)
|
||||
{
|
||||
selected_remote_position = 0;
|
||||
scroll_direction = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::PopID();
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows))
|
||||
@@ -789,6 +867,12 @@ namespace Windows
|
||||
ImGui::SetScrollHereY(0.5f);
|
||||
sprintf(remote_file_to_select, "");
|
||||
}
|
||||
if (selected_remote_position == j && !paused)
|
||||
{
|
||||
SetNavFocusHere();
|
||||
ImGui::SetScrollHereY(scroll_direction);
|
||||
selected_remote_position = -1;
|
||||
}
|
||||
selected_browser |= REMOTE_BROWSER;
|
||||
}
|
||||
ImGui::NextColumn();
|
||||
@@ -806,6 +890,38 @@ namespace Windows
|
||||
ImGui::Columns(1);
|
||||
ImGui::EndChild();
|
||||
EndGroupPanel();
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_C) && !paused)
|
||||
{
|
||||
if (selected_browser & LOCAL_BROWSER)
|
||||
{
|
||||
selected_local_file = local_files[0];
|
||||
selected_action = ACTION_CHANGE_LOCAL_DIRECTORY;
|
||||
}
|
||||
else if (selected_browser & REMOTE_BROWSER)
|
||||
{
|
||||
if (remoteclient != nullptr && remote_files.size() > 0)
|
||||
{
|
||||
selected_remote_file = remote_files[0];
|
||||
selected_action = ACTION_CHANGE_REMOTE_DIRECTORY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_D) && !paused)
|
||||
{
|
||||
if (selected_browser & LOCAL_BROWSER)
|
||||
{
|
||||
selected_action = ACTION_REFRESH_LOCAL_FILES;
|
||||
}
|
||||
else if (selected_browser & REMOTE_BROWSER)
|
||||
{
|
||||
if (remoteclient != nullptr && remote_files.size() > 0)
|
||||
{
|
||||
selected_action = ACTION_REFRESH_REMOTE_FILES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StatusPanel()
|
||||
@@ -1319,7 +1435,10 @@ namespace Windows
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 300);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||
if (ImGui::Button(lang_strings[STR_CLOSE], ImVec2(100, 0)))
|
||||
|
||||
char id[128];
|
||||
sprintf(id, "%s##prodialog", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(100, 0)))
|
||||
{
|
||||
SetModalMode(false);
|
||||
selected_action = ACTION_NONE;
|
||||
@@ -1356,8 +1475,19 @@ namespace Windows
|
||||
if (file_transfering)
|
||||
{
|
||||
static float progress = 0.0f;
|
||||
static double transfer_speed = 0.0f;
|
||||
static char progress_text[32];
|
||||
static OrbisTick cur_tick;
|
||||
static double tick_delta;
|
||||
|
||||
sceRtcGetCurrentTick(&cur_tick);
|
||||
tick_delta = (cur_tick.mytick - prev_tick.mytick) * 1.0f / 1000000.0f;
|
||||
|
||||
progress = bytes_transfered * 1.0f / (float)bytes_to_download;
|
||||
ImGui::ProgressBar(progress, ImVec2(625, 0));
|
||||
transfer_speed = (bytes_transfered * 1.0f / tick_delta) / 1048576.0f;
|
||||
|
||||
sprintf(progress_text, "%.2f MB/s", transfer_speed);
|
||||
ImGui::ProgressBar(progress, ImVec2(625, 0), progress_text);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
@@ -1398,7 +1528,52 @@ namespace Windows
|
||||
{
|
||||
ImVec2 cur_pos = ImGui::GetCursorPos();
|
||||
char id[128];
|
||||
if (ImGui::Button(lang_strings[STR_ONETIME_URL], ImVec2(535, 0)))
|
||||
|
||||
ImGui::Checkbox("##enable_alldebrid_install_uril", &install_pkg_url.enable_alldebrid);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_ALLDEBRID_MSG]);
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+40);
|
||||
ImGui::Checkbox("##enable_realdebrid_install_uril", &install_pkg_url.enable_realdebrid);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_REALDEBRID_MSG]);
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+40);
|
||||
ImGui::Checkbox("##enable_rpi_install_url", &install_pkg_url.enable_rpi);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(550, 110));
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 540);
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_RPI_WEBDAV_MSG]);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_RPI]);
|
||||
|
||||
if (install_pkg_url.enable_rpi)
|
||||
{
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+40);
|
||||
ImGui::Checkbox("##enable_diskcache_install_uril", &install_pkg_url.enable_disk_cache);
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(550, 110));
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 540);
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_DISC_CACHE_MSG]);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_DISKCACHE_DESC]);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::Button(lang_strings[STR_ONETIME_URL], ImVec2(1070, 0)))
|
||||
{
|
||||
ResetImeCallbacks();
|
||||
sprintf(install_pkg_url.url, "%s", "");
|
||||
@@ -1412,14 +1587,6 @@ namespace Windows
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
sprintf(id, "%s##favoriteurl", lang_strings[STR_CANCEL]);
|
||||
if (ImGui::Button(id, ImVec2(535, 0)))
|
||||
{
|
||||
select_url_inprogress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
for (int j = 0; j < MAX_FAVORITE_URLS; j++)
|
||||
@@ -1467,6 +1634,13 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
|
||||
{
|
||||
select_url_inprogress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
@@ -1474,6 +1648,9 @@ namespace Windows
|
||||
|
||||
void ShowEditorDialog()
|
||||
{
|
||||
if (!paused)
|
||||
saved_selected_browser = selected_browser;
|
||||
|
||||
if (editor_inprogress)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
@@ -1608,6 +1785,140 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
|
||||
void ShowWarningDialog()
|
||||
{
|
||||
if (show_ezremote_server_warning)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
ImGuiStyle *style = &ImGui::GetStyle();
|
||||
ImVec4 *colors = style->Colors;
|
||||
|
||||
SetModalMode(true);
|
||||
ImGui::OpenPopup(lang_strings[STR_WARNING]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(600, 350));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(720, 80), ImVec2(720, 500), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_WARNING], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImVec2 cur_pos = ImGui::GetCursorPos();
|
||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 700);
|
||||
ImGui::Text("%s %s %s", lang_strings[STR_WARNING_MSG_1], lang_strings[STR_WARNING_MSG_2], lang_strings[STR_WARNING_MSG_3]);
|
||||
ImGui::PopTextWrapPos();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 285);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||
|
||||
char id[128];
|
||||
sprintf(id, "%s##warning", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(150, 0)))
|
||||
{
|
||||
show_ezremote_server_warning = false;
|
||||
SetModalMode(false);
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowAppearing())
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
|
||||
{
|
||||
show_ezremote_server_warning = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowDownloadProgressDialog()
|
||||
{
|
||||
if (show_bg_download_progress)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
ImGuiStyle *style = &ImGui::GetStyle();
|
||||
ImVec4 *colors = style->Colors;
|
||||
char datetime_str[32];
|
||||
|
||||
SetModalMode(true);
|
||||
ImGui::OpenPopup(lang_strings[STR_BG_DOWNLOAD_PROGRESS]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(345, 320));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(1260, 80), ImVec2(1260, 500), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_BG_DOWNLOAD_PROGRESS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::Columns(4, "bg_download_progress##Columns", true);
|
||||
|
||||
for (int j = 0; j < bg_download_progress.size(); j++)
|
||||
{
|
||||
DownloadProgress item = bg_download_progress[j];
|
||||
|
||||
std::tm* ptm = std::localtime(&item.timestamp);
|
||||
// Format: YYYY-MM-DD HH:MM:SS
|
||||
std::strftime(datetime_str, sizeof(datetime_str), "%Y-%m-%d %H:%M", ptm);
|
||||
|
||||
ImGui::SetColumnWidth(-1, 220);
|
||||
ImGui::Text("%s", datetime_str);
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::SetColumnWidth(-1, 740);
|
||||
ImGui::Text("%s", item.path.c_str());
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::SetColumnWidth(-1, 150);
|
||||
ImGui::Text("%s", item.state.c_str());
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::SetColumnWidth(-1, 100);
|
||||
ImGui::Text("%.2f%%", (item.bytes_transfered * 1.0f/item.file_size * 1.0f)*100);
|
||||
|
||||
ImGui::NextColumn();
|
||||
ImGui::Separator();
|
||||
}
|
||||
ImGui::Columns(1);
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 485);
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||
|
||||
char id[128];
|
||||
sprintf(id, "%s##bg_dl_progress", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(150, 0)))
|
||||
{
|
||||
show_bg_download_progress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowAppearing())
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
|
||||
{
|
||||
show_bg_download_progress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
uint64_t cur_time = tick.mytick;
|
||||
if (cur_time - refresh_bg_download_time > 2000000)
|
||||
{
|
||||
refresh_bg_download_time = cur_time;
|
||||
Actions::GetBackgroundDownloadProgress();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShowSettingsDialog()
|
||||
{
|
||||
if (show_settings)
|
||||
@@ -1621,7 +1932,7 @@ namespace Windows
|
||||
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(1050, 80));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 750), NULL, NULL);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 850), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
char id[192];
|
||||
@@ -1659,6 +1970,7 @@ namespace Windows
|
||||
ImGui::SetCursorPosX(805);
|
||||
ImGui::Checkbox("##auto_delete_tmp_pkg", &auto_delete_tmp_pkg);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_SHOW_HIDDEN_FILES]);
|
||||
ImGui::SameLine();
|
||||
@@ -1680,7 +1992,36 @@ namespace Windows
|
||||
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);
|
||||
Dialog::initImeDialog(lang_strings[STR_COMPRESSED_FILE_PATH], temp_folder, 255, ORBIS_TYPE_DEFAULT, 1050, 80);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_ENABLE_BG_DOWNLOAD]);
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(805);
|
||||
ImGui::Checkbox("##enable_bg_download", &enable_background_download);
|
||||
ImGui::Separator();
|
||||
|
||||
field_size = ImGui::CalcTextSize(lang_strings[STR_BG_DOWNLOAD_MIN_SIZE]);
|
||||
width = field_size.x + 45;
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_BG_DOWNLOAD_MIN_SIZE]);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
|
||||
sprintf(id, "%s##bg_download_min_size", txt_bg_download_size);
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
if (ImGui::Button(id, ImVec2(835-width, 0)))
|
||||
{
|
||||
ResetImeCallbacks();
|
||||
ime_single_field = txt_bg_download_size;
|
||||
ime_field_size = 16;
|
||||
ime_callback = SingleValueImeCallback;
|
||||
ime_after_update = AfterMinBgDlSizeChangeCallback;
|
||||
Dialog::initImeDialog(lang_strings[STR_BG_DOWNLOAD_MIN_SIZE], txt_bg_download_size, 16, ORBIS_TYPE_NUMBER, 1050, 80);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
@@ -1716,6 +2057,7 @@ namespace Windows
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
|
||||
ImGui::Text("%s", lang_strings[STR_COMPRESSED_FILE_PATH]);
|
||||
ImGui::SameLine();
|
||||
@@ -1735,6 +2077,33 @@ namespace Windows
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_RESTART_SERVER]);
|
||||
if (is_server_started)
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 1.0f, 0.0f, 1.0f)); // Green background
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); // Black Text
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); // Red background
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); // White Text
|
||||
}
|
||||
if (ImGui::Button(id, ImVec2(410, 0)))
|
||||
{
|
||||
Actions::RestartServer();
|
||||
is_server_started = !INSTALLER::EzRemoteServerVersion().empty();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_STOP_SERVER]);
|
||||
if (ImGui::Button(id, ImVec2(410, 0)))
|
||||
{
|
||||
INSTALLER::StopEzRemoteServer();
|
||||
is_server_started = !INSTALLER::EzRemoteServerVersion().empty();
|
||||
}
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_ALLDEBRID]);
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -1834,6 +2203,21 @@ namespace Windows
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::Separator();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_SHOW_BG_DOWNLOAD_PROGRESS]);
|
||||
if (ImGui::Button(id, ImVec2(835, 0)))
|
||||
{
|
||||
Actions::GetBackgroundDownloadProgress();
|
||||
show_bg_download_progress = true;
|
||||
show_settings = false;
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
refresh_bg_download_time = tick.mytick;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
sprintf(id, "%s##settings", lang_strings[STR_CLOSE]);
|
||||
if (ImGui::Button(id, ImVec2(835, 0)))
|
||||
{
|
||||
@@ -1997,6 +2381,8 @@ namespace Windows
|
||||
ShowSettingsDialog();
|
||||
ShowImageDialog();
|
||||
ShowPackageInfoDialog();
|
||||
ShowWarningDialog();
|
||||
ShowDownloadProgressDialog();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -2495,6 +2881,18 @@ namespace Windows
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
{
|
||||
CONFIG::SetClientType(remote_settings);
|
||||
if (strncasecmp(remote_settings->server, "https://archive.org/", 20) == 0)
|
||||
{
|
||||
sprintf(remote_settings->http_server_type, "%s", HTTP_SERVER_ARCHIVEORG);
|
||||
}
|
||||
else if (strncasecmp(remote_settings->server, "https://myrient.erista.me/", 26) == 0)
|
||||
{
|
||||
sprintf(remote_settings->http_server_type, "%s", HTTP_SERVER_MYRIENT);
|
||||
}
|
||||
else if (strncasecmp(remote_settings->server, "https://github.com/", 19) == 0)
|
||||
{
|
||||
snprintf(remote_settings->http_server_type, 24, "%s", HTTP_SERVER_GITHUB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2506,6 +2904,14 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
|
||||
void AfterMinBgDlSizeChangeCallback(int ime_result)
|
||||
{
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
{
|
||||
minimum_backgrond_file_size = atol(txt_bg_download_size);
|
||||
}
|
||||
}
|
||||
|
||||
void AfterEditorCallback(int ime_result)
|
||||
{
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
|
||||
+8
-2
@@ -1,5 +1,5 @@
|
||||
#ifndef LAUNCHER_WINDOWS_H
|
||||
#define LAUNCHER_WINDOWS_H
|
||||
#ifndef EZ_WINDOWS_H
|
||||
#define EZ_WINDOWS_H
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <set>
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "imgui_internal.h"
|
||||
#include "common.h"
|
||||
#include "actions.h"
|
||||
#include "system.h"
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
#define LOCAL_BROWSER 1
|
||||
@@ -16,12 +17,14 @@ extern int view_mode;
|
||||
extern bool handle_updates;
|
||||
extern int64_t bytes_transfered;
|
||||
extern int64_t bytes_to_download;
|
||||
extern OrbisTick prev_tick;
|
||||
extern std::vector<DirEntry> local_files;
|
||||
extern std::vector<DirEntry> remote_files;
|
||||
extern std::set<DirEntry> multi_selected_local_files;
|
||||
extern std::set<DirEntry> multi_selected_remote_files;
|
||||
extern std::vector<DirEntry> local_paste_files;
|
||||
extern std::vector<DirEntry> remote_paste_files;
|
||||
extern std::vector<DownloadProgress> bg_download_progress;
|
||||
extern ACTIONS paste_action;
|
||||
extern DirEntry selected_local_file;
|
||||
extern DirEntry selected_remote_file;
|
||||
@@ -42,6 +45,8 @@ extern bool file_transfering;
|
||||
extern char extract_zip_folder[];
|
||||
extern char zip_file_path[];
|
||||
extern std::vector<std::string> edit_buffer;
|
||||
extern bool is_server_started;
|
||||
extern bool ezremote_server_version_match;
|
||||
|
||||
static ImVector<ImRect> s_GroupPanelLabelStack;
|
||||
|
||||
@@ -210,6 +215,7 @@ namespace Windows
|
||||
void AfterZipFileCallback(int ime_result);
|
||||
void AferServerChangeCallback(int ime_result);
|
||||
void AfterHttpPortChangeCallback(int ime_result);
|
||||
void AfterMinBgDlSizeChangeCallback(int ime_result);
|
||||
void AfterEditorCallback(int ime_result);
|
||||
}
|
||||
|
||||
|
||||
+71
-21
@@ -72,6 +72,8 @@ namespace ZipUtil
|
||||
convertToZipTime(file_stat.st_mtim.tv_sec, &zi.tmz_date);
|
||||
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
bytes_to_download = file_stat.st_size;
|
||||
|
||||
// Large file?
|
||||
@@ -288,8 +290,9 @@ namespace ZipUtil
|
||||
static int extract2fd(struct archive *a, const std::string &pathname, int fd)
|
||||
{
|
||||
ssize_t len;
|
||||
unsigned char *buffer = (unsigned char *) malloc(ARCHIVE_TRANSFER_SIZE);
|
||||
unsigned char *buffer = (unsigned char *)malloc(ARCHIVE_TRANSFER_SIZE);
|
||||
bytes_transfered = 0;
|
||||
sceRtcGetCurrentTick(&prev_tick);
|
||||
|
||||
/* loop over file contents and write to fd */
|
||||
for (int n = 0;; n++)
|
||||
@@ -309,7 +312,7 @@ namespace ZipUtil
|
||||
return 0;
|
||||
}
|
||||
bytes_transfered += len;
|
||||
|
||||
|
||||
if (write(fd, buffer, len) != len)
|
||||
{
|
||||
sprintf(status_message, "error write('%s')", pathname.c_str());
|
||||
@@ -451,6 +454,10 @@ namespace ZipUtil
|
||||
client->Size(file, &data->size);
|
||||
data->client = client;
|
||||
data->path = file;
|
||||
if (client->SupportedActions() & REMOTE_ACTION_RAW_READ)
|
||||
{
|
||||
data->fp = client->Open(file, O_RDONLY);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -468,7 +475,11 @@ namespace ZipUtil
|
||||
return 0;
|
||||
|
||||
to_read = MIN(to_read, ARCHIVE_TRANSFER_SIZE);
|
||||
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
|
||||
if (data->client->SupportedActions() & REMOTE_ACTION_RAW_READ)
|
||||
ret = data->client->GetRange((data->fp), data->buf, to_read, data->offset);
|
||||
else
|
||||
ret = data->client->GetRange(data->path, data->buf, to_read, data->offset);
|
||||
|
||||
if (ret == 0)
|
||||
return -1;
|
||||
data->offset = data->offset + to_read;
|
||||
@@ -479,10 +490,46 @@ namespace ZipUtil
|
||||
static int CloseRemoteArchive(struct archive *a, void *client_data)
|
||||
{
|
||||
if (client_data != nullptr)
|
||||
{
|
||||
RemoteArchiveData *data = (RemoteArchiveData *)client_data;
|
||||
if (data->client->SupportedActions() & REMOTE_ACTION_RAW_READ)
|
||||
data->client->Close(data->fp);
|
||||
free(client_data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t SeekRemoteArchive(struct archive *, void *client_data, int64_t offset, int whence)
|
||||
{
|
||||
RemoteArchiveData *data = (RemoteArchiveData *)client_data;
|
||||
|
||||
if (whence == SEEK_SET)
|
||||
{
|
||||
data->offset = offset;
|
||||
}
|
||||
else if (whence == SEEK_CUR)
|
||||
{
|
||||
data->offset = data->offset + offset - 1;
|
||||
}
|
||||
else if (whence == SEEK_END)
|
||||
{
|
||||
data->offset = data->size - 1;
|
||||
}
|
||||
else
|
||||
return ARCHIVE_FATAL;
|
||||
|
||||
return data->offset;
|
||||
}
|
||||
|
||||
int64_t SkipRemoteArchive(struct archive *, void *client_data, int64_t request)
|
||||
{
|
||||
RemoteArchiveData *data = (RemoteArchiveData *)client_data;
|
||||
|
||||
data->offset = data->offset + request - 1;
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main loop: open the zipfile, iterate over its contents and decide what
|
||||
* to do with each entry.
|
||||
@@ -520,13 +567,16 @@ namespace ZipUtil
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
|
||||
ret = archive_read_set_seek_callback(a, SeekRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
sprintf(status_message, "archive_read_set_seek_callback failed - %s", archive_error_string(a));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = archive_read_open2(a, client_data, NULL, ReadRemoteArchive, SkipRemoteArchive, CloseRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
if (client_data != nullptr)
|
||||
{
|
||||
free(client_data);
|
||||
}
|
||||
sprintf(status_message, "%s", "archive_read_open failed");
|
||||
return 0;
|
||||
}
|
||||
@@ -568,7 +618,10 @@ namespace ZipUtil
|
||||
int ret;
|
||||
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
{
|
||||
sprintf(status_message, "%s", "archive_read_new failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
@@ -592,13 +645,16 @@ namespace ZipUtil
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ret = archive_read_open(a, client_data, NULL, ReadRemoteArchive, CloseRemoteArchive);
|
||||
ret = archive_read_set_seek_callback(a, SeekRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
sprintf(status_message, "archive_read_set_seek_callback failed - %s", archive_error_string(a));
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = archive_read_open2(a, client_data, NULL, ReadRemoteArchive, SkipRemoteArchive, CloseRemoteArchive);
|
||||
if (ret < ARCHIVE_OK)
|
||||
{
|
||||
if (client_data != nullptr)
|
||||
{
|
||||
free(client_data);
|
||||
}
|
||||
sprintf(status_message, "%s", "archive_read_open_filename failed");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -611,16 +667,14 @@ namespace ZipUtil
|
||||
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)
|
||||
{
|
||||
@@ -689,10 +743,6 @@ namespace ZipUtil
|
||||
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;
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
#ifndef ZIP_UTIL_H
|
||||
#define ZIP_UTIL_H
|
||||
#ifndef EZ_ZIP_UTIL_H
|
||||
#define EZ_ZIP_UTIL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
|
||||
#define ARCHIVE_TRANSFER_SIZE 5242880
|
||||
#define ARCHIVE_TRANSFER_SIZE 20971520
|
||||
|
||||
static uint8_t MAGIC_ZIP_1[4] = {0x50, 0x4B, 0x03, 0x04};
|
||||
static uint8_t MAGIC_ZIP_2[4] = {0x50, 0x4B, 0x05, 0x06};
|
||||
@@ -30,6 +30,7 @@ enum CompressFileType {
|
||||
|
||||
struct RemoteArchiveData
|
||||
{
|
||||
void *fp;
|
||||
std::string path;
|
||||
ssize_t size;
|
||||
ssize_t offset;
|
||||
|
||||
Reference in New Issue
Block a user