Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c022615e1e | |||
| 87ad8bf9b3 | |||
| 57248f797e | |||
| 4a7ab7e131 | |||
| e563f422c0 | |||
| ff802d0a62 | |||
| 4aabf850b8 | |||
| 4ea584e092 | |||
| 15597ccfc1 | |||
| e600715164 | |||
| a46f3f4cca | |||
| 751011d08b | |||
| d34df2cf94 | |||
| f6cf00974b | |||
| 9788b7e963 | |||
| aa9ef34991 | |||
| fc96b76260 | |||
| c54fc8fcbc | |||
| 5ca56b47df | |||
| 05d253edd8 | |||
| d752dd8fed | |||
| 45320ed2ca | |||
| 8aef5d0233 | |||
| 2c9d31fbcc | |||
| a4510e0b47 | |||
| d6ec9ac1a5 | |||
| 2975f736de | |||
| 9a9308244c | |||
| 649f6daac2 | |||
| cc541c6da5 | |||
| ec7b845bdc | |||
| eed0e5193b | |||
| 9d7e46dcc6 | |||
| 2164443969 | |||
| d3f8cdc774 | |||
| f58e9fdecd | |||
| ea768a3528 | |||
| 6371c6fd29 | |||
| 456b1aa075 | |||
| e654667621 | |||
| a4ac55ca88 | |||
| f0c291eb0c | |||
| d96734aeeb | |||
| 4aa6b7c02a | |||
| c632f0d7cb | |||
| 686caec0f7 | |||
| 4c5429902a | |||
| 7378736b3f | |||
| 05c7207b7c | |||
| cd26aeaa77 | |||
| 5aef0f648d | |||
| 2ee0e9ae74 | |||
| c6143be6f0 | |||
| 23c8c678f1 | |||
| f314c94ddc | |||
| e3c908bfbf | |||
| d772b3d3f5 | |||
| 837258afda | |||
| 98c71d3411 | |||
| b156fea640 | |||
| 7508ec12da | |||
| ad43c48454 | |||
| 32ba34fefb | |||
| ba3c2d5600 | |||
| a18971a62f | |||
| 5e6710c815 | |||
| 89c8fd652a | |||
| 951f1f8f45 | |||
| b0ca95338f | |||
| e519343164 | |||
| 1cfeece53f | |||
| fc60358a1e |
+28
-17
@@ -10,9 +10,16 @@ add_definitions(-DCPPHTTPLIB_OPENSSL_SUPPORT)
|
||||
include_directories(
|
||||
source
|
||||
source/pugixml
|
||||
source/imgui
|
||||
)
|
||||
|
||||
add_executable(ezremote_client
|
||||
source/imgui/imgui_draw.cpp
|
||||
source/imgui/imgui_impl_sdl.cpp
|
||||
source/imgui/imgui_impl_sdlrenderer.cpp
|
||||
source/imgui/imgui_tables.cpp
|
||||
source/imgui/imgui_widgets.cpp
|
||||
source/imgui/imgui.cpp
|
||||
source/pugixml/pugixml.cpp
|
||||
source/web/callback.cpp
|
||||
source/web/fsinfo.cpp
|
||||
@@ -21,15 +28,21 @@ add_executable(ezremote_client
|
||||
source/web/urn.cpp
|
||||
source/webdav/client.cpp
|
||||
source/http/httplib.cpp
|
||||
source/http/baseclient.cpp
|
||||
source/http/apache.cpp
|
||||
source/http/iis.cpp
|
||||
source/http/nginx.cpp
|
||||
source/http/npxserve.cpp
|
||||
source/clients/baseclient.cpp
|
||||
source/clients/apache.cpp
|
||||
source/clients/ftpclient.cpp
|
||||
source/clients/gdrive.cpp
|
||||
source/clients/iis.cpp
|
||||
source/clients/nginx.cpp
|
||||
source/clients/npxserve.cpp
|
||||
source/clients/smbclient.cpp
|
||||
source/clients/webdavclient.cpp
|
||||
source/clients/sftpclient.cpp
|
||||
source/server/http_server.cpp
|
||||
source/actions.cpp
|
||||
source/config.cpp
|
||||
source/crypt.c
|
||||
source/fs.cpp
|
||||
source/ftpclient.cpp
|
||||
source/gui.cpp
|
||||
source/getentropy.c
|
||||
source/ime_dialog.cpp
|
||||
@@ -38,30 +51,27 @@ add_executable(ezremote_client
|
||||
source/lang.cpp
|
||||
source/main.cpp
|
||||
source/orbis_jbc.c
|
||||
source/rtc.cpp
|
||||
source/smbclient.cpp
|
||||
source/system.cpp
|
||||
source/sfo.cpp
|
||||
source/textures.cpp
|
||||
source/windows.cpp
|
||||
source/webdavclient.cpp
|
||||
source/zip_util.cpp
|
||||
source/imgui_draw.cpp
|
||||
source/imgui_impl_sdl.cpp
|
||||
source/imgui_impl_sdlrenderer.cpp
|
||||
source/imgui_tables.cpp
|
||||
source/imgui_widgets.cpp
|
||||
source/imgui.cpp
|
||||
)
|
||||
|
||||
add_self(ezremote_client)
|
||||
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.01" 32 0)
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.06" 32 0)
|
||||
|
||||
target_link_libraries(ezremote_client
|
||||
c
|
||||
c++
|
||||
png
|
||||
webp
|
||||
jpeg
|
||||
z
|
||||
pthread
|
||||
SDL2
|
||||
SDL2_image
|
||||
samplerate
|
||||
jbc
|
||||
crypto
|
||||
@@ -72,6 +82,8 @@ target_link_libraries(ezremote_client
|
||||
minizip
|
||||
un7zip
|
||||
unrar
|
||||
json-c
|
||||
ssh2
|
||||
kernel
|
||||
SceShellCoreUtil
|
||||
SceSysmodule
|
||||
@@ -87,5 +99,4 @@ target_link_libraries(ezremote_client
|
||||
SceNet
|
||||
SceBgft
|
||||
SceAppInstUtil
|
||||
SceLncUtil
|
||||
)
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
# ezRemote Client
|
||||
|
||||
ezRemote Client is an application that allows you to connect the PS4 to remote FTP, SMB, WebDAV and HTTP servers to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
|
||||
ezRemote Client is an application that allows you to connect the PS4 to remote FTP/SFTP, SMB, WebDAV, HTTP servers and Google Drive to transfer files. The interface is inspired by Filezilla client which provides a commander like GUI.
|
||||

|
||||
## Usage
|
||||
To distinguish between FTP, SMB, WebDAV or HTTP, the URL must be prefix with **ftp://**, **smb://**, **webdav://**, **webdavs://**, **http://** and **https://**
|
||||
To distinguish between FTP, SMB, WebDAV or HTTP, the URL must be prefix with **ftp://**, **sftp://**, **smb://**, **webdav://**, **webdavs://**, **http://** and **https://**
|
||||
|
||||
- The url format for FTP is
|
||||
```
|
||||
ftp://hostname[:port]
|
||||
sftp://hostname[:port]
|
||||
|
||||
- hostname can be the textual hostname or an IP address. hostname is required
|
||||
- port is optional and defaults to 21 if not provided
|
||||
- port is optional and defaults to 21(ftp) and 22(sftp) if not provided
|
||||
```
|
||||
For Secure FTP (sftp), use of identity files is possible. Put both the **id_rsa** and **id_rsa.pub** into a folder in the PS4 hard drive. Then in the password field in the UI, instead of putting a password reference the folder where id_rsa and id_rsa.pub is place. Prefix the folder with **"file://"** and **do not** password protect the identity file.
|
||||
```
|
||||
Example: If you had placed the id_rsa and id_rsa.pub files into the folder /data/ezremote-client,
|
||||
then in the password field enter file:///data/ezremote-client
|
||||
```
|
||||
|
||||
- The url format for SMB is
|
||||
@@ -40,7 +46,9 @@ To distinguish between FTP, SMB, WebDAV or HTTP, the URL must be prefix with **f
|
||||
- port is optional and defaults to 80(http) and 443(https) if not provided
|
||||
- url_path is optional based on your HTTP Server hosting requiremets
|
||||
```
|
||||
|
||||
- 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)
|
||||
|
||||
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.
|
||||
@@ -54,15 +62,20 @@ Remote Package Installation only works if the WebDAV server allow anonymous acce
|
||||
|
||||
## Features ##
|
||||
- Transfer files back and forth between PS4 and FTP/SMB/WebDAV server
|
||||
- Support for connecting to Http Servers like (Apache/Nginx,Microsoft IIS, Serve) with directory listings to download or install pkg.
|
||||
- Support for connecting to Http Servers like (Apache/Nginx,Microsoft IIS, Serve) with html directory listings to download or install pkg.
|
||||
- Install Remote Packages from connected WebDAV server
|
||||
- Ability to connect to your "Google Drive" to transfer files back and fort. Can also install packages from it. The app will download the file to the PS4's harddrive and then install it. You need to keep the app opened. Here is a link to the wiki for what you need to do to make it work. Also able to access files that are shared to you. As of v1.06, Google Shared Drives from Google workspace is supported.
|
||||
- Install Remote Packages for FTP/SMB if HTTP server setup on same host sharing same folder as FTP/SMB
|
||||
- If Remote Package Install is not possible, optionally the user can choose to download package to PS4 local drive and install
|
||||
- Install packages from PS4 local drive **/data** folder or usb drive **/mnt/usbX**
|
||||
- Install package from Direct Links. Direct links are links that can be reached without being redirected to a webpage where it requires capthas or timers. Example of direct links are github release artifacts. Google shared links is the only exception since I could indirectly parse the webpage to obtain the direct links
|
||||
- Create Zip files on PS4 local drive or usb drive
|
||||
- Extract from zip, 7zip and rar files
|
||||
- File management function include cut/copy/paste/rename/delete/new folder for files on PS4 local drive or usb or WebDAV Server.
|
||||
- File management function include cut/copy/paste/rename/delete/new folder/file for files on PS4 local drive or usb or WebDAV Server.
|
||||
- Simple Text Editor to make simply changes to config text files. Limited to edit files over 32kb and limited to edit lines up to 1023 characters. If you try edit lines longer then 1023 characters, it will be truncated. For common text files with the following extensions (txt, log, ini, json, xml, html, conf, config) selecting them in the file browser with the X button will automatically open the Text Editor.
|
||||
- Ability to view jpg, png, bmp and webp image files. (Selecting files with X button will automatically view the file)
|
||||
- Ability to preview pkg files. In the file browser, select a pkg file with the X button, a preview of the package will now display the icon and SFO attributes. If pkg is in the /data or /mnt/usbX folder, user has the option to install the package from the preview dialog.
|
||||
|
||||
|
||||
## Installation
|
||||
Copy the **ezremote_client.pkg** in to a FAT32 format usb drive then install from package installer
|
||||
@@ -71,11 +84,12 @@ Copy the **ezremote_client.pkg** in to a FAT32 format usb drive then install fro
|
||||
```
|
||||
Triangle - Menu (after a file(s)/folder(s) is selected)
|
||||
Cross - Select Button/TextBox
|
||||
Circle - Un-Select the file list to navigate to other widgets
|
||||
Circle - Un-Select the file list to navigate to other widgets or Close Dialog window in most cases
|
||||
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
|
||||
TouchPad Button - Exit Application
|
||||
TouchPad Button - Exit Application (versions prior to 1.06)
|
||||
Options Button - Exit Application (versions 1.06 and above)
|
||||
```
|
||||
|
||||
## Multi Language Support
|
||||
@@ -161,12 +175,20 @@ Build and install libsmb2 - https://github.com/cy33hc/libsmb2/blob/ps4/README_PS
|
||||
|
||||
Build and install lexbor - https://github.com/lexbor/lexbor.git
|
||||
|
||||
Build and install libssh2 - https://www.libssh2.org/
|
||||
|
||||
Build libjbc - https://github.com/cy33hc/ps4-libjbc/blob/master/README_PS4.md
|
||||
|
||||
Build libunrar - https://github.com/cy33hc/libunrar-ps3
|
||||
|
||||
Build libun7zip - https://github.com/cy33hc/libun7zip
|
||||
|
||||
Build libjson-c - https://github.com/json-c/json-c
|
||||
|
||||
I have included the source code from the following 2 projects embedded into this repo.
|
||||
<br/>https://github.com/yhirose/cpp-httplib
|
||||
<br/>https://github.com/CloudPolis/webdav-client-cpp
|
||||
|
||||
Finally build the app
|
||||
```
|
||||
source /opt/pacbrew/ps4/openorbis/ps4vars.sh
|
||||
@@ -175,5 +197,3 @@ Finally build the app
|
||||
make
|
||||
```
|
||||
|
||||
## Credits
|
||||
The color theme was borrowed from NX-Shell on the switch.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDqDCCApCgAwIBAgIUSlUxeW2iMsLD8Lk3+ffGUfxej6QwDQYJKoZIhvcNAQEL
|
||||
BQAwYzELMAkGA1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQ
|
||||
MA4GA1UECgwHTWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxv
|
||||
Y2FsaG9zdDAgFw0yMzAyMjUwNzAyMTNaGA8yMDUzMDIxNzA3MDIxM1owYzELMAkG
|
||||
A1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQMA4GA1UECgwH
|
||||
TWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOWQx+pfhpDqd2wPkV5BL6Yf
|
||||
8UVTCsP13+1YlxZiD93VHhcK23T/YYqSxx6tDHAR4sA/oKELT+dFuhMhC/QE5Sw6
|
||||
HD/FwCwdNJ7Ke3z+iUActtInDU5URC0XwdW7wTAt1MLx4T9j7CkoVHsaiDlf6LTG
|
||||
165bIXD8JKzud26WXHmTCCBCgIU3zcq13jpFeb4Po4rJtuDLwb3gloZzEzdS9S6O
|
||||
mjVNUSlZeb+ksep3TbJHIACy6WrPJZ+u2aScDOBOt9Gv/UeOYHcvGIFHXddG+kHl
|
||||
/ay6b7JxNbBNWL57/PswmXcpB16gkBNWCfL1PDmDFEkvd6uJTnPUnMge7CBNzX8C
|
||||
AwEAAaNSMFAwHwYDVR0jBBgwFoAUeCZ0CXLAs8C5xVsPGIhzu4haXpEwCQYDVR0T
|
||||
BAIwADAiBgNVHREEGzAZgglsb2NhbGhvc3SCCTEyNy4wLjAuMYIBKjANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEAsgC/89C7+OAspaOgU5Tr9WFcZ1Nph21WTltBM0z9f4NyeR1Y
|
||||
b/YoJrvocRWw9gpgCcj7AArSHNsha2+QMBEko3PIpkdMoSHylf2WqYNTCIb8cvJA
|
||||
pHDYJJR99Cajo0meP5h1mtQdjOVv70Q3jtS6iSdD/KI5VwIRcfDutjHys78Bb2NQ
|
||||
1KEZuHKwmhE3209OQ5ZbjDQ0gViJFPnfPfnbWuOllpIN27ZwGvlhhM9x7xRvwsWt
|
||||
puh5wV2TBAYagOT+canBOxugv7L1eOpnNVE49YS0vr5y8JhLuKFoZ0hTi7PeqO4c
|
||||
mE4zIVwKjIQ6w+N2Vj/ghNjkyJm0azpmnbPtFg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,17 @@
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICqDCCAZACAQAwYzELMAkGA1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UE
|
||||
BwwETW9vbjEQMA4GA1UECgwHTWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQ
|
||||
BgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||
AOWQx+pfhpDqd2wPkV5BL6Yf8UVTCsP13+1YlxZiD93VHhcK23T/YYqSxx6tDHAR
|
||||
4sA/oKELT+dFuhMhC/QE5Sw6HD/FwCwdNJ7Ke3z+iUActtInDU5URC0XwdW7wTAt
|
||||
1MLx4T9j7CkoVHsaiDlf6LTG165bIXD8JKzud26WXHmTCCBCgIU3zcq13jpFeb4P
|
||||
o4rJtuDLwb3gloZzEzdS9S6OmjVNUSlZeb+ksep3TbJHIACy6WrPJZ+u2aScDOBO
|
||||
t9Gv/UeOYHcvGIFHXddG+kHl/ay6b7JxNbBNWL57/PswmXcpB16gkBNWCfL1PDmD
|
||||
FEkvd6uJTnPUnMge7CBNzX8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQB2gc2Z
|
||||
7bzytAja4uDQQjQOxZMzwwgfODyQTWhvyEVJxq7iK8Saogn/dpjgeVhNaIgMAGRs
|
||||
RNQ26cBQxvs9ZfNmNcNvc1eFw9NJicRpHOUjNf0mMHtqiFIpGc9Fnu34p1DLGKJ4
|
||||
qp5Kd9cl4Vx96xaPWqCyH+sXFxnIt8lK6K0yKHaDXLKzFmuJvEEc2Z/g0/RRfgq7
|
||||
cO9+otlsD3sF6TziNL/KFFYPqgn4Wkx8K8z9ovpMnyvYH1KnQsuhCNr9nUhmA8Wu
|
||||
o9DMKQbqDYq9NLUmTJMgX75Vi71idbkgOZN7kvmUnEW+Ltf1FLl9AnF5kpkvMTvR
|
||||
KIcPUOLLdpzwZ8jc
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
@@ -0,0 +1,7 @@
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
subjectAltName = @alt_names
|
||||
[alt_names]
|
||||
DNS.1 = localhost
|
||||
DNS.2 = 127.0.0.1
|
||||
DNS.3 = *
|
||||
@@ -0,0 +1,30 @@
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIDkuJpr20dpYCAggA
|
||||
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECAKW47FhDo5vBIIEyNJd7CLIboON
|
||||
iXmQ5Vzj7nHna+HXfPdrNGUnAtRKQ7oZmAvPJQMqrEO88am5zl/puOThwdJ/b+tp
|
||||
Ftt76zi8JffShf0fwNeL3zOfiVEUSmGeOfRzx4MV1flivbk70UjHx4ga9Nqdab6t
|
||||
0dvV8copWkmj+B/sP2zk3+S9Urv6VPz97hq6PTqrmjWm+VwssDJyv9s7KGM/+9bC
|
||||
/9DQR5AAQbd4e7sxW45cL9desyRfs0XNcYj6Go9sVHzFhKaSx75u6Shd5Rb2N5sX
|
||||
2Dmm349cy3XimqNBCsrPIp76uLfCIhSp/pgC6phMeIu52SrFwM2OOwCuPkGZyVQv
|
||||
I6n0vagltBHXYj5a371P9imV8LWTCy326yb6Ro1Mjy6XEMWVIBk/XI/U12APHytf
|
||||
c1VvCk1pGemD3ArVYpuECdjtwZxxCOneOxeIYgSV/h3GHMHKmQiK36zQOslNNdfy
|
||||
l7AO6kokITWoW/VPk2FG0tclWJe1aA8WOiqI3ZYRwBlovk9jUrjNqEA3BG/rzAWU
|
||||
VbApXd4FvbsgLETHRZl1KWvwZFhO9vZ02+CznrnzzMWCb13UipCA7RuePuhdbViT
|
||||
jOy1JJG408NcwRu0PNwr77oIZu7OrdEPu0u7YJ+SR/q3pxS6u86l6O3lvbUhtOyC
|
||||
1grybOa+lJXrAL07yrbriCoy8igNIMKiA8blwpwCC/22CtGrY5UJqzpLIZuTLcnB
|
||||
8pVoFioSGetvsjpzRsv6jCsacdAZwhuYEUCi82wFW1yd3UNCVMh6U8ypspQp3wz3
|
||||
tbdoGbzlwbwbgd2o9+MpxzW66s2emEsCBjG+SrNElZBkfAG8ZgSbF3yGlSe778BJ
|
||||
7O71TEjxmYfUglvn90ZWpV7IH1TNbaKeIOJXkmuqQDaiG6U61kHcq//QvuZfU/tv
|
||||
TEUlQGqbdYS1E7+byCxubUnD3rclSP1cMTGyUtacHGUzFhiCZfuuDc+1P1Q8wKTe
|
||||
NkGfMpmXWLSncVUDEPgpsuz+hCtt65BAb0BfCWLZPyBXQ4Qbovk6Z/O5Ta5tyWEl
|
||||
g2wRqFXUL8ZYk+TKbmSclU+1h3QfFwvyEmEGFi+igKRZR1ERB4cAEEDjOJP+uI7B
|
||||
3K7lomdeh4kuPG6move8PCm9Dw1GhWPVFCKoan0MW2sNfnhmoOqXkoMT6P+M4U7+
|
||||
DjHY+G5Op2jkP+BrHQ99VRApXz40MtLaOdfu6S+IWURnqqwPuL99We8XFMgX3xX4
|
||||
++v7lSkcp54uSoN5e/fY/2fYG/RPxaI6+W6oxP4YmxUZjdvGdZvJiJJGqIBzCj1p
|
||||
26WynwFu25wnsyXBzWo4wzH4Ga6ZtUvb59KFRTSJqQKieLVmX2zNjSps2B2/twax
|
||||
EQt03AGIbtr677NeYKM3BUws+iw9TyBUjEMsqnpp6EuWhDcPga8WJn1ivw04BenP
|
||||
uaOw2w1nLe8InaJxahmBKmRiSjX7XX4+PPgB/FwGN89nMBpy8+ujitteOYvlY6Hf
|
||||
050aTysBmYWu4oCsx/kz8OHpwt7zPO8zkVdtHCGa8+5bm//pLUGHyoDVY2Xj68MD
|
||||
OMfwbJl0Q4W+bOkCEK4fYhkB7HWPZqxZKujcR/goXBsUCvIk/WuDx8pNnjIas1Qm
|
||||
MUDSs9XQFGWE8ydRYN4RRw==
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
@@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDqTCCApGgAwIBAgIUbNUnFW+Ibevm3bOTzzznsNO4laIwDQYJKoZIhvcNAQEL
|
||||
BQAwYzELMAkGA1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQ
|
||||
MA4GA1UECgwHTWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxv
|
||||
Y2FsaG9zdDAgFw0yMzAyMjUwNjU4MTJaGA8yMDUzMDIxNzA2NTgxMlowYzELMAkG
|
||||
A1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQMA4GA1UECgwH
|
||||
TWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBF0q8GELLjXu6zTTNtCovU
|
||||
QVsgg8kSN56p8Xxv5gZHEuhUXjan+UyiklW2aoxJZpyRbE8dpAR78ca6kLUG1LMf
|
||||
2RX8FDjA6W5xXR2C2FmSYGnPyLigRFPbZv3sb7PyOYhqgPuu1xKMEmq5n1lE9pCV
|
||||
nO7hAsfwqS3mZrPFL3MZIqrT6HqeSO1tVe8gUUWTm3dm9Yb0E/sVExdG6u0RfbVu
|
||||
eqHykO4iCUonm3lOigskDbZ7WFKQyVRM3vZbALEpE7YlltcgT14GmG+L8aeFY6iT
|
||||
FoPDV7bFAGtgg30os4kV135HUNJ80koIoUocwxThuyBpADltIZ5R2FSHBl1XzK8C
|
||||
AwEAAaNTMFEwHQYDVR0OBBYEFHgmdAlywLPAucVbDxiIc7uIWl6RMB8GA1UdIwQY
|
||||
MBaAFHgmdAlywLPAucVbDxiIc7uIWl6RMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
||||
hvcNAQELBQADggEBAGW6HVweWcsIxp2vVzspBaKSp2ECYRpx4xunge/eDWlokAj3
|
||||
OCW7kxgPfEbtClLOeQj3p9WolHzABgG+qqIB6kPbGtNXYaXrQbsD6j9f56GFklNK
|
||||
tuYH3WtDpp5TLsYyj2cLeK2x02Z8k3+r11SqB1DeMPTBAkhXiTwrkUt3axnZuiZC
|
||||
2Miwzi0b5muMbdecYukB+50xlV8TkiVmWUtQ5cVVE/U640sC6O1GMZG0zO9Ys0+U
|
||||
xTeB/3Xq5Wg6OQx86GpbD7+8xRhSkdJxoVbuFgh0KNUlBREC/pYobehnwji7WWFH
|
||||
F7nBdVyedi6qZTa7dVEk4eaXgalemTp9k4rzbZ8=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,30 @@
|
||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIoyT8iwjhZBECAggA
|
||||
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECKy1pYbVGbtDBIIEyIIY1X/XVv5q
|
||||
ihMCTQbnesuyEstQCw/9BFQ/ka4Ee2D6yJp59gSiEODwce+EgIn1jrgJImOZbnsz
|
||||
xKtRJXNd+ENBwsZgh8am15o+bJ2WeOztuKcrhOvrRmj8wrDPAon4+sdcfphqRUbG
|
||||
hilLbV7T8jpE1ScTD/zYU/KKWEIytYTxT+vfHvXYv8oQY9IscwNqx6cnXxNtoO7C
|
||||
SO87/Apkul3irVHnad29gV/jyj4imlm6gVCmqByaD/JaV/d9Y0hWhZVeSzceP64Q
|
||||
95kfhUM8AsTJi5A25vWAQAxa2Gi8ywiv+/NRVC4qhzMID4wbqI/2Oy8iEMJJfkaK
|
||||
Ah/S5lY8sVRpenUmX4kSZs+oKbITc5LNccx5OUESvVZCj/mW9t91uZfTWTt23iac
|
||||
snYzhH4PvYxCGU7LXzrgS5suv/N3R33E5kcND0dJbKkW4VVVxmv7HUDfs8YqduJn
|
||||
teQFQNsoNuQO5Te9WsMpamickF/65nrg+OOhsbVkLsuCRPzyXIRgAPBBGFqlr3IG
|
||||
XK41kQR5I4HTAeFXCClz00LfLrCl+T7IO3NbH+AD1EVGUHYPuwgJBRic/cMbXZwT
|
||||
Kcxo98Apwsm+OHKRAq4c5wEmUb9ipVSwq6CRUojklrGMclJfXnd9r57FFl/9eYdY
|
||||
ZEp+jnAqq3M8v2m29dPjja07CTIuimIRgIPaIjWZuZX8oW1GVpapV3JfIun5KXE4
|
||||
Sc+ScLA015Gzm/3hgKNke5HGYH49x9V/lYhr9j5AxgdWnoj4H3qbJSu2jJKooYmS
|
||||
tsimgs3pqz/dygyx9Zmy2L5eb597MYEQwg4kZdFPyixAttmFXRdXVvRmQCB9H8VX
|
||||
kx6z4Rus/Zh6NM6z0aHvWoaih9jJ444CdnOPLYSngLL5yzI3xunwT67Di9rrkNeL
|
||||
nVBJP9Ljc9cE4LgK63xAy+25+bZWv/mZ07CBXatc91CCSa/O3KM4eLmOMNaZNU+T
|
||||
P8EYHR3r24V6TCzud7dLp3k+Glkxj1feiXEktmFxnfUbGoS5Ihw4cVGqrst7hSSE
|
||||
IaQFIx0X70sKyl/ixxVHWIMdV4Zqdxhf2boNZk7aHx8+yOhCnOEY4/8KUJM98W+W
|
||||
a6VRhxYucKsz+B3i0BKEZg4sB1bT/6G17JAentfGmKp42IFJR3JeRydEF6ppCaWT
|
||||
gdLnRlsYDHEpAMcTPsbDiQK3Crid3E0i/2QU5V5VEhR2ncq+oKZ0oy7nwoOV232W
|
||||
TuodV43urEshbh8RDr321+2UxCgT6AGMAt6BPgx9D/mIZHMVgZalvHqtzPDyN5Av
|
||||
5LiXct8nl4fO+c0iMdfAw2TfCvl6sIkaAW5ClqbHXxiSg9OUXSrfgBVMkcCmcnB0
|
||||
cNbx6Xc6jdLZEtnch+IcYZzj4wmLFx01zVAs9daPxbGw6mg1TloDQ0fYhgixkRSi
|
||||
NDkztXZzLFx9MB4rYy/v8h08OWwNi/R6IOZDI4DNf7qXEtgqouqa85srsT9Pspc4
|
||||
SAN5YzHlo6AKujmUNRo+uYbJGqsssMXQPWNvozxnXIgQsiZ5/Y/x3KsUJu49RveL
|
||||
baNm/ScI3ghTbt92bPE16ebtodULkxuPFAqXdjWXLjblSVihiKxvQ9wTULB97zHI
|
||||
1oX6YdWladLddzK/De6JMA==
|
||||
-----END ENCRYPTED PRIVATE KEY-----
|
||||
@@ -0,0 +1 @@
|
||||
4A5531796DA232C2C3F0B937F9F7C651FC5E8FA5
|
||||
Binary file not shown.
@@ -107,11 +107,39 @@ STR_CANT_COPY_TO_SUBDIR_MSG=Cannot copy parent directory to sub subdirectory
|
||||
STR_UNSUPPORTED_OPERATION_MSG=Operation not supported
|
||||
STR_HTTP_PORT=Http Port
|
||||
STR_REINSTALL_CONFIRM_MSG=The content has already been installed. Do you want to continue installing
|
||||
STR_REMOTE_NOT_SUPPORT_MSG=Remote server requires at least a username.
|
||||
STR_REMOTE_NOT_SUPPORT_MSG=Remote package installation is not supported for protected servers.
|
||||
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?
|
||||
STR_DOWNLOAD_INSTALL_MSG=Remote Package Install not possible. Would you like to download package and install instead?
|
||||
STR_CHECKING_REMOTE_SERVER_MSG=Checking remote server for Remote Package Install.
|
||||
STR_ENABLE_RPI=RPI
|
||||
STR_ENABLE_RPI_FTP_SMB_MSG=This option enables Remote Package Installation. This requires a HTTP Server setup on the same host sharing the same folder with anonymous access.
|
||||
STR_ENABLE_RPI_WEBDAV_MSG=This option enables Remote Package Installation. This requires the Server with anonymous access that does not need username/password.
|
||||
STR_FILES=Files
|
||||
STR_EDITOR=Editor
|
||||
STR_SAVE=Save
|
||||
STR_MAX_EDIT_FILE_SIZE_MSG=Cannot edit files bigger than
|
||||
STR_DELETE_LINE=Delete Selected Line
|
||||
STR_INSERT_LINE=Insert Below Selected Line
|
||||
STR_MODIFIED=Modified
|
||||
STR_FAIL_GET_TOKEN_MSG=Failed to obtain an access token from
|
||||
STR_GET_TOKEN_SUCCESS_MSG=Login Success. You may close the browser and return to the application
|
||||
STR_PERM_DRIVE=See, edit, create, and delete all of your Google Drive files
|
||||
STR_PERM_DRIVE_APPDATA=See, create, and delete its own configuration data in your Google Drive
|
||||
STR_PERM_DRIVE_FILE=See, edit, create, and delete only the specific Google Drive files you use with this app
|
||||
STR_PERM_DRIVE_METADATA=View and manage metadata of files in your Google Drive
|
||||
STR_PERM_DRIVE_METADATA_RO=See information about your Google Drive files
|
||||
STR_GOOGLE_LOGIN_FAIL_MSG=Google login failed
|
||||
STR_GOOGLE_LOGIN_TIMEOUT_MSG=Google login timed out
|
||||
STR_NEW_FILE=New File
|
||||
STR_SETTINGS=Settings
|
||||
STR_CLIENT_ID=Client ID
|
||||
STR_CLIENT_SECRET=Client Secret
|
||||
STR_GLOBAL=Global
|
||||
STR_GOOGLE=Google
|
||||
STR_COPY_LINE=Copy selected line
|
||||
STR_PASTE_LINE=Paste into selected line
|
||||
STR_SHOW_HIDDEN_FILES=Show hidden files
|
||||
STR_SET_DEFAULT_DIRECTORY=Set Default Folder
|
||||
STR_SET_DEFAULT_DIRECTORY_MSG=has being set as default direcotry
|
||||
STR_VIEW_IMAGE=View Image
|
||||
STR_VIEW_PKG_INFO=Package Information
|
||||
|
||||
@@ -1,61 +1,141 @@
|
||||
STR_CONNECTION_SETTINGS=Configurações de Conexão
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remoto
|
||||
STR_MESSAGES=Mensagens
|
||||
STR_UPDATE_SOFTWARE=Atualizar Software
|
||||
STR_CONNECT=Conectar
|
||||
STR_DISCONNECT=Desconectar
|
||||
STR_SEARCH=Pesquisar
|
||||
STR_REFRESH=Recarregar
|
||||
STR_SERVER=Servidor
|
||||
STR_USERNAME=Usuário
|
||||
STR_PASSWORD=Senha
|
||||
STR_PORT=Porta
|
||||
STR_PASV=Salvar
|
||||
STR_DIRECTORY=Diretório
|
||||
STR_FILTER=Filtro
|
||||
STR_YES=Sim
|
||||
STR_NO=Não
|
||||
STR_CANCEL=Cancelar
|
||||
STR_CONTINUE=Continuar
|
||||
STR_CLOSE=Fechar
|
||||
STR_FOLDER=Pasta
|
||||
STR_FILE=Arquivo
|
||||
STR_TYPE=Tipo
|
||||
STR_NAME=Nome
|
||||
STR_SIZE=Tamanho
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nova pasta
|
||||
STR_RENAME=Renomear
|
||||
STR_DELETE=Deletar
|
||||
STR_UPLOAD=Carregar
|
||||
STR_DOWNLOAD=Baixar
|
||||
STR_SELECT_ALL=Selecionar tudo
|
||||
STR_CLEAR_ALL=Apagar tudo
|
||||
STR_UPLOADING=Carregando
|
||||
STR_DOWNLOADING=Baixando
|
||||
STR_OVERWRITE=Sobrescrever
|
||||
STR_DONT_OVERWRITE=Não sobrescrever
|
||||
STR_ASK_FOR_CONFIRM=Perguntar novamente
|
||||
STR_DONT_ASK_CONFIRM=Não perguntar novamente
|
||||
STR_ALLWAYS_USE_OPTION=Usar sempre esta opção e não perguntar novamente
|
||||
STR_ACTIONS=Ações
|
||||
STR_CONFIRM=Confirmar
|
||||
STR_OVERWRITE_OPTIONS=Sobrescrever opções
|
||||
STR_PROPERTIES=Propriedades
|
||||
STR_PROGRESS=Progresso
|
||||
STR_UPDATES=Atualizações
|
||||
STR_DEL_CONFIRM_MSG=Tem certeza que deseja deletar este(a) arquivo(s)/pasta(s)?
|
||||
STR_CANCEL_ACTION_MSG=Cancelando. Aguardando a conclusão da última ação
|
||||
STR_FAIL_UPLOAD_MSG=Falha em carregar o arquivo
|
||||
STR_FAIL_DOWNLOAD_MSG=Falha em baixar o arquivo
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Falha ao ler o conteúdo do diretório ou pasta não existe.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Conexão encerrada.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 O servidor remoto encerrou a conexão.
|
||||
STR_FAIL_LOGIN_MSG=300 Falha no login. Favor checar o usuário e senha.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Falha. Tempo limite de conexão atingido.
|
||||
STR_FAIL_DEL_DIR_MSG=Falha ao excluir o diretório
|
||||
STR_DELETING=Excluindo
|
||||
STR_FAIL_DEL_FILE_MSG=Falha ao excluir o arquivo
|
||||
STR_DELETED=Excluido
|
||||
STR_CONNECTION_SETTINGS=Configurações de Conexão
|
||||
STR_SITE=Site
|
||||
STR_LOCAL=Local
|
||||
STR_REMOTE=Remoto
|
||||
STR_MESSAGES=Mensagens
|
||||
STR_UPDATE_SOFTWARE=Atualizar Software
|
||||
STR_CONNECT=Conectar
|
||||
STR_DISCONNECT=Desconectar
|
||||
STR_SEARCH=Pesquisar
|
||||
STR_REFRESH=Recarregar
|
||||
STR_SERVER=Servidor
|
||||
STR_USERNAME=Usuário
|
||||
STR_PASSWORD=Senha
|
||||
STR_PORT=Porta
|
||||
STR_PASV=Salvar
|
||||
STR_DIRECTORY=Diretório
|
||||
STR_FILTER=Filtro
|
||||
STR_YES=Sim
|
||||
STR_NO=Não
|
||||
STR_CANCEL=Cancelar
|
||||
STR_CONTINUE=Continuar
|
||||
STR_CLOSE=Fechar
|
||||
STR_FOLDER=Pasta
|
||||
STR_FILE=Arquivo
|
||||
STR_TYPE=Tipo
|
||||
STR_NAME=Nome
|
||||
STR_SIZE=Tamanho
|
||||
STR_DATE=Data
|
||||
STR_NEW_FOLDER=Nova pasta
|
||||
STR_RENAME=Renomear
|
||||
STR_DELETE=Deletar
|
||||
STR_UPLOAD=Carregar
|
||||
STR_DOWNLOAD=Baixar
|
||||
STR_SELECT_ALL=Selecionar tudo
|
||||
STR_CLEAR_ALL=Apagar tudo
|
||||
STR_UPLOADING=Carregando
|
||||
STR_DOWNLOADING=Baixando
|
||||
STR_OVERWRITE=Sobrescrever
|
||||
STR_DONT_OVERWRITE=Não sobrescrever
|
||||
STR_ASK_FOR_CONFIRM=Perguntar novamente
|
||||
STR_DONT_ASK_CONFIRM=Não perguntar novamente
|
||||
STR_ALLWAYS_USE_OPTION=Usar sempre esta opção e não perguntar novamente
|
||||
STR_ACTIONS=Ações
|
||||
STR_CONFIRM=Confirmar
|
||||
STR_OVERWRITE_OPTIONS=Sobrescrever opções
|
||||
STR_PROPERTIES=Propriedades
|
||||
STR_PROGRESS=Progresso
|
||||
STR_UPDATES=Atualizações
|
||||
STR_DEL_CONFIRM_MSG=Tem certeza que deseja deletar este(a) arquivo(s)/pasta(s)?
|
||||
STR_CANCEL_ACTION_MSG=Cancelando. Aguardando a conclusão da última ação
|
||||
STR_FAIL_UPLOAD_MSG=Falha em carregar o arquivo
|
||||
STR_FAIL_DOWNLOAD_MSG=Falha em baixar o arquivo
|
||||
STR_FAIL_READ_LOCAL_DIR_MSG=Falha ao ler o conteúdo do diretório ou pasta não existe.
|
||||
STR_CONNECTION_CLOSE_ERR_MSG=426 Conexão encerrada.
|
||||
STR_REMOTE_TERM_CONN_MSG=426 O servidor remoto encerrou a conexão.
|
||||
STR_FAIL_LOGIN_MSG=300 Falha no login. Favor checar o usuário e senha.
|
||||
STR_FAIL_TIMEOUT_MSG=426 Falha. Tempo limite de conexão atingido.
|
||||
STR_FAIL_DEL_DIR_MSG=Falha ao excluir o diretório
|
||||
STR_DELETING=Excluindo
|
||||
STR_FAIL_DEL_FILE_MSG=Falha ao excluir o arquivo
|
||||
STR_DELETED=Excluido
|
||||
STR_LINK=Link
|
||||
STR_SHARE=Compartilhar
|
||||
STR_FAILED=Falha 310
|
||||
STR_FAIL_CREATE_LOCAL_FILE_MSG=310 Falha ao criar arquivo no local
|
||||
STR_INSTALL=Instalar
|
||||
STR_INSTALLING=Instalando
|
||||
STR_INSTALL_SUCCESS=Sucesso
|
||||
STR_INSTALL_FAILED=Falha
|
||||
STR_INSTALL_SKIPPED=Pular
|
||||
STR_CHECK_HTTP_MSG=Verificando a conexão com o servidor HTTP remoto
|
||||
STR_FAILED_HTTP_CHECK=Falha ao conectar-se ao servidor HTTP
|
||||
STR_REMOTE_NOT_HTTP=Remoto não é um servidor HTTP
|
||||
STR_INSTALL_FROM_DATA_MSG=O pacote não está na pasta /data ou /mnt/usbX
|
||||
STR_ALREADY_INSTALLED_MSG=O pacote já está instalado!
|
||||
STR_INSTALL_FROM_URL=Instalar a partir do URL?
|
||||
STR_CANNOT_READ_PKG_HDR_MSG=Não foi possível ler as informações do cabeçalho do pacote
|
||||
STR_FAVORITE_URLS=URLs favoritas
|
||||
STR_SLOT=Slot
|
||||
STR_EDIT=Editar
|
||||
STR_ONETIME_URL=Url único
|
||||
STR_NOT_A_VALID_PACKAGE=Não é um pacote válido
|
||||
STR_WAIT_FOR_INSTALL_MSG=Aguardando o pacote terminar de instalar
|
||||
STR_FAIL_INSTALL_TMP_PKG_MSG=Falha ao instalar o arquivo PKG. Exclua o pacote tmp manualmente
|
||||
STR_FAIL_TO_OBTAIN_GG_DL_MSG=Falha ao obter o URL de download do Google
|
||||
STR_AUTO_DELETE_TMP_PKG=Excluir automaticamente o arquivo PKG temporário baixado após a instalação?
|
||||
STR_PROTOCOL_NOT_SUPPORTED=Protocolo não suportado
|
||||
STR_COULD_NOT_RESOLVE_HOST=Não foi possível resolver o nome do Host
|
||||
STR_EXTRACT=Extrair
|
||||
STR_EXTRACTING=Extraindo
|
||||
STR_FAILED_TO_EXTRACT=Falha ao extrair
|
||||
STR_EXTRACT_LOCATION=Local de Extração
|
||||
STR_COMPRESS=Comprimir
|
||||
STR_ZIP_FILE_PATH=Nome do arquivo zip
|
||||
STR_COMPRESSING=Comprimindo
|
||||
STR_ERROR_CREATE_ZIP=Ocorreu um erro ao criar o zip
|
||||
STR_UNSUPPORTED_FILE_FORMAT=Formato de arquivo compactado não suportado
|
||||
STR_CUT=Recortar
|
||||
STR_COPY=Copiar
|
||||
STR_PASTE=Colar
|
||||
STR_MOVING=Movendo
|
||||
STR_COPYING=Copiando
|
||||
STR_FAIL_MOVE_MSG=Falha ao mover o arquivo
|
||||
STR_FAIL_COPY_MSG=Falha ao copiar o arquivo
|
||||
STR_CANT_MOVE_TO_SUBDIR_MSG=Não é possível mover o diretório pai para o subdiretório
|
||||
STR_CANT_COPY_TO_SUBDIR_MSG=Não é possível copiar o diretório pai para o subdiretório
|
||||
STR_UNSUPPORTED_OPERATION_MSG=Operação não suportada
|
||||
STR_HTTP_PORT=Porta HTTP
|
||||
STR_REINSTALL_CONFIRM_MSG=O conteúdo já foi instalado. Deseja continuar instalando?
|
||||
STR_REMOTE_NOT_SUPPORT_MSG=A instalação remota de pacotes não é compatível com servidores protegidos.
|
||||
STR_CANNOT_CONNECT_REMOTE_MSG=Servidor HTTP remoto não esta acessível.
|
||||
STR_DOWNLOAD_INSTALL_MSG=A instalação remota do pacote não é possível. Você gostaria de baixar o pacote e instalar?
|
||||
STR_CHECKING_REMOTE_SERVER_MSG=Verificando servidor remoto para instalação de pacote remoto.
|
||||
STR_ENABLE_RPI=RPI
|
||||
STR_ENABLE_RPI_FTP_SMB_MSG=Esta opção permite a instalação remota de pacotes. Isso requer uma configuração de servidor HTTP no mesmo Host compartilhando a mesma pasta com acesso anônimo.
|
||||
STR_ENABLE_RPI_WEBDAV_MSG=Esta opção permite a instalação remota de pacotes. Isso requer o servidor com acesso anônimo que não precisa de nome de usuário/senha.
|
||||
STR_FILES=Arquivos
|
||||
STR_EDITOR=Editar
|
||||
STR_SAVE=Salvar
|
||||
STR_MAX_EDIT_FILE_SIZE_MSG=Não é possível editar arquivos maiores que
|
||||
STR_DELETE_LINE=Excluir linha selecionada
|
||||
STR_INSERT_LINE=Inserir Abaixo da Linha Selecionada
|
||||
STR_MODIFIED=Modificar
|
||||
STR_FAIL_GET_TOKEN_MSG=Falha ao obter o token de acesso de
|
||||
STR_GET_TOKEN_SUCCESS_MSG=Login realizado com sucesso. Você pode fechar o navegador e retornar ao aplicativo
|
||||
STR_PERM_DRIVE=Veja, Edite, Crie e Exclua todos os seus arquivos do Google Drive
|
||||
STR_PERM_DRIVE_APPDATA=Veja, Edite, Crie e Exclua seus próprios dados de configuração em seu Google Drive
|
||||
STR_PERM_DRIVE_FILE=Veja, Edite, Crie e Exclua apenas os arquivos específicos do Google Drive que você usa com este aplicativo
|
||||
STR_PERM_DRIVE_METADATA=Visualize e Gerencie metadados de arquivos em seu Google Drive
|
||||
STR_PERM_DRIVE_METADATA_RO=Ver informações sobre seus arquivos do Google Drive
|
||||
STR_GOOGLE_LOGIN_FAIL_MSG=Falha no login do Google
|
||||
STR_GOOGLE_LOGIN_TIMEOUT_MSG=O login do Google expirou
|
||||
STR_NEW_FILE=Novo arquivo
|
||||
STR_SETTINGS=Configurações
|
||||
STR_CLIENT_ID=ID do Cliente Google
|
||||
STR_CLIENT_SECRET=Segredo do cliente Google
|
||||
STR_GLOBAL=Global
|
||||
STR_GOOGLE=Google
|
||||
STR_COPY_LINE=Copiar linha selecionada
|
||||
STR_PASTE_LINE=Colar na linha selecionada
|
||||
STR_SHOW_HIDDEN_FILES=Mostrar arquivos ocultos
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#define ICON_OF_SQUARE "\xee\x83\x8b" // U+E0CB
|
||||
#define ICON_OF_TRIANGLE "\xee\x83\x9e" // U+E0CB
|
||||
+70
-15
@@ -4,6 +4,15 @@
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <minizip/unzip.h>
|
||||
#include "clients/gdrive.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "clients/smbclient.h"
|
||||
#include "clients/webdavclient.h"
|
||||
#include "clients/apache.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "clients/iis.h"
|
||||
#include "clients/sftpclient.h"
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "config.h"
|
||||
@@ -14,14 +23,7 @@
|
||||
#include "installer.h"
|
||||
#include "web/request.hpp"
|
||||
#include "web/urn.hpp"
|
||||
#include "rtc.h"
|
||||
#include "ftpclient.h"
|
||||
#include "smbclient.h"
|
||||
#include "webdavclient.h"
|
||||
#include "http/apache.h"
|
||||
#include "http/nginx.h"
|
||||
#include "http/npxserve.h"
|
||||
#include "http/iis.h"
|
||||
#include "system.h"
|
||||
#include "zip_util.h"
|
||||
|
||||
namespace Actions
|
||||
@@ -819,7 +821,7 @@ namespace Actions
|
||||
|
||||
void *ExtractZipThread(void *argp)
|
||||
{
|
||||
FS::MkDirs(extract_zip_folder, true);
|
||||
FS::MkDirs(extract_zip_folder);
|
||||
std::vector<DirEntry> files;
|
||||
if (multi_selected_local_files.size() > 0)
|
||||
std::copy(multi_selected_local_files.begin(), multi_selected_local_files.end(), std::back_inserter(files));
|
||||
@@ -1107,7 +1109,13 @@ namespace Actions
|
||||
void Connect()
|
||||
{
|
||||
CONFIG::SaveConfig();
|
||||
if (strncmp(remote_settings->server, "https://", 8) == 0 || strncmp(remote_settings->server, "http://", 7) == 0)
|
||||
|
||||
if (strncmp(remote_settings->server, GOOGLE_DRIVE_BASE_URL, strlen(GOOGLE_DRIVE_BASE_URL)) == 0)
|
||||
{
|
||||
remoteclient = new GDriveClient();
|
||||
remoteclient->Connect("", "", "");
|
||||
}
|
||||
else if (strncmp(remote_settings->server, "https://", 8) == 0 || strncmp(remote_settings->server, "http://", 7) == 0)
|
||||
{
|
||||
if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0)
|
||||
remoteclient = new ApacheClient();
|
||||
@@ -1134,6 +1142,10 @@ namespace Actions
|
||||
client->SetCallbackXferFunction(FtpCallback);
|
||||
remoteclient = client;
|
||||
}
|
||||
else if (strncmp(remote_settings->server, "sftp://", 7) == 0)
|
||||
{
|
||||
remoteclient = new SFTPClient();
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(status_message, "%s", lang_strings[STR_PROTOCOL_NOT_SUPPORTED]);
|
||||
@@ -1171,8 +1183,8 @@ namespace Actions
|
||||
remoteclient->Quit();
|
||||
multi_selected_remote_files.clear();
|
||||
remote_files.clear();
|
||||
sprintf(remote_directory, "%s", "/");
|
||||
sprintf(status_message, "%s", "");
|
||||
delete remoteclient;
|
||||
remoteclient = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -1262,7 +1274,7 @@ namespace Actions
|
||||
{
|
||||
int err;
|
||||
std::vector<DirEntry> entries = FS::ListDir(src.path, &err);
|
||||
FS::MkDirs(dest, true);
|
||||
FS::MkDirs(dest);
|
||||
for (int i = 0; i < entries.size(); i++)
|
||||
{
|
||||
if (stop_activity)
|
||||
@@ -1277,7 +1289,7 @@ namespace Actions
|
||||
if (strcmp(entries[i].name, "..") == 0)
|
||||
continue;
|
||||
|
||||
FS::MkDirs(new_path, true);
|
||||
FS::MkDirs(new_path);
|
||||
ret = CopyOrMove(entries[i], new_path, isCopy);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -1526,7 +1538,7 @@ namespace Actions
|
||||
if (strcmp(entries[i].name, "..") == 0)
|
||||
continue;
|
||||
|
||||
FS::MkDirs(new_path, true);
|
||||
remoteclient->Mkdir(new_path);
|
||||
ret = CopyRemotePath(entries[i], new_path);
|
||||
if (ret <= 0)
|
||||
{
|
||||
@@ -1594,7 +1606,7 @@ namespace Actions
|
||||
}
|
||||
else
|
||||
{
|
||||
int res = CopyRemotePath(*it, remote_directory);
|
||||
int res = CopyRemotePath(*it, remote_directory);
|
||||
if (res == 0)
|
||||
sprintf(status_message, "%s - %s", it->name, lang_strings[STR_FAIL_COPY_MSG]);
|
||||
}
|
||||
@@ -1639,4 +1651,47 @@ namespace Actions
|
||||
|
||||
return INSTALLER::InstallLocalPkg(local_file, header, true);
|
||||
}
|
||||
|
||||
void CreateLocalFile(char *filename)
|
||||
{
|
||||
std::string new_file = FS::GetPath(local_directory, filename);
|
||||
std::string temp_file = new_file;
|
||||
int i = 1;
|
||||
while (true)
|
||||
{
|
||||
if (!FS::FileExists(temp_file))
|
||||
break;
|
||||
temp_file = new_file + "." + std::to_string(i);
|
||||
i++;
|
||||
}
|
||||
FILE* f = FS::Create(temp_file);
|
||||
FS::Close(f);
|
||||
RefreshLocalFiles(false);
|
||||
sprintf(local_file_to_select, "%s", temp_file.c_str());
|
||||
}
|
||||
|
||||
void CreateRemoteFile(char *filename)
|
||||
{
|
||||
std::string new_file = FS::GetPath(remote_directory, filename);
|
||||
std::string temp_file = new_file;
|
||||
int i = 1;
|
||||
while (true)
|
||||
{
|
||||
if (!remoteclient->FileExists(temp_file))
|
||||
break;
|
||||
temp_file = new_file + "." + std::to_string(i);
|
||||
i++;
|
||||
}
|
||||
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
std::string local_tmp = std::string(DATA_PATH) + "/" + std::to_string(tick.mytick);
|
||||
FILE *f = FS::Create(local_tmp);
|
||||
FS::Close(f);
|
||||
remoteclient->Put(local_tmp, temp_file);
|
||||
FS::Rm(local_tmp);
|
||||
RefreshRemoteFiles(false);
|
||||
sprintf(remote_file_to_select, "%s", temp_file.c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+13
-1
@@ -44,9 +44,19 @@ enum ACTIONS
|
||||
ACTION_LOCAL_CUT,
|
||||
ACTION_LOCAL_COPY,
|
||||
ACTION_LOCAL_PASTE,
|
||||
ACTION_LOCAL_EDIT,
|
||||
ACTION_REMOTE_CUT,
|
||||
ACTION_REMOTE_COPY,
|
||||
ACTION_REMOTE_PASTE
|
||||
ACTION_REMOTE_PASTE,
|
||||
ACTION_REMOTE_EDIT,
|
||||
ACTION_NEW_LOCAL_FILE,
|
||||
ACTION_NEW_REMOTE_FILE,
|
||||
ACTION_SET_DEFAULT_LOCAL_FOLDER,
|
||||
ACTION_SET_DEFAULT_REMOTE_FOLDER,
|
||||
ACTION_VIEW_LOCAL_IMAGE,
|
||||
ACTION_VIEW_REMOTE_IMAGE,
|
||||
ACTION_VIEW_LOCAL_PKG,
|
||||
ACTION_VIEW_REMOTE_PKG
|
||||
};
|
||||
|
||||
enum OverWriteType
|
||||
@@ -104,6 +114,8 @@ namespace Actions
|
||||
void *CopyRemoteFilesThread(void *argp);
|
||||
void CopyRemoteFiles();
|
||||
int DownloadAndInstallPkg(const std::string &filename, pkg_header *header);
|
||||
void CreateLocalFile(char *filename);
|
||||
void CreateRemoteFile(char *filename);
|
||||
}
|
||||
|
||||
#endif
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
#ifndef BASE64_H_
|
||||
#define BASE64_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
class Base64
|
||||
{
|
||||
public:
|
||||
static int Encode(const std::string &input, std::string &out)
|
||||
{
|
||||
static constexpr char sEncodingTable[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/'};
|
||||
|
||||
size_t in_len = input.size();
|
||||
size_t out_len = 4 * ((in_len + 2) / 3);
|
||||
out.resize(out_len);
|
||||
size_t i;
|
||||
char *p = const_cast<char *>(out.c_str());
|
||||
|
||||
for (i = 0; i < in_len - 2; i += 3)
|
||||
{
|
||||
*p++ = sEncodingTable[(input[i] >> 2) & 0x3F];
|
||||
*p++ = sEncodingTable[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)];
|
||||
*p++ = sEncodingTable[((input[i + 1] & 0xF) << 2) | ((int)(input[i + 2] & 0xC0) >> 6)];
|
||||
*p++ = sEncodingTable[input[i + 2] & 0x3F];
|
||||
}
|
||||
if (i < in_len)
|
||||
{
|
||||
*p++ = sEncodingTable[(input[i] >> 2) & 0x3F];
|
||||
if (i == (in_len - 1))
|
||||
{
|
||||
*p++ = sEncodingTable[((input[i] & 0x3) << 4)];
|
||||
*p++ = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
*p++ = sEncodingTable[((input[i] & 0x3) << 4) | ((int)(input[i + 1] & 0xF0) >> 4)];
|
||||
*p++ = sEncodingTable[((input[i + 1] & 0xF) << 2)];
|
||||
}
|
||||
*p++ = '=';
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Decode(const std::string &input, std::string &out)
|
||||
{
|
||||
static constexpr unsigned char kDecodingTable[] = {
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
|
||||
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
|
||||
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64};
|
||||
|
||||
size_t in_len = input.size();
|
||||
if (in_len % 4 != 0)
|
||||
return 0;
|
||||
|
||||
size_t out_len = in_len / 4 * 3;
|
||||
if (input[in_len - 1] == '=')
|
||||
out_len--;
|
||||
if (input[in_len - 2] == '=')
|
||||
out_len--;
|
||||
|
||||
out.resize(out_len);
|
||||
|
||||
for (size_t i = 0, j = 0; i < in_len;)
|
||||
{
|
||||
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||
|
||||
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
|
||||
|
||||
if (j < out_len)
|
||||
out[j++] = (triple >> 2 * 8) & 0xFF;
|
||||
if (j < out_len)
|
||||
out[j++] = (triple >> 1 * 8) & 0xFF;
|
||||
if (j < out_len)
|
||||
out[j++] = (triple >> 0 * 8) & 0xFF;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <fstream>
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
#include "http/apache.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/apache.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "http/baseclient.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class ApacheClient : public BaseClient
|
||||
{
|
||||
@@ -1,9 +1,10 @@
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <fstream>
|
||||
#include <curl/curl.h>
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
#include "http/npxserve.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
@@ -76,12 +77,12 @@ 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),
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
file_stream.write(data, data_length);
|
||||
bytes_transfered += data_length;
|
||||
return true;
|
||||
}))
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
file_stream.write(data, data_length);
|
||||
bytes_transfered += data_length;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
file_stream.close();
|
||||
return 1;
|
||||
@@ -93,6 +94,35 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BaseClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
char range_header[64];
|
||||
sprintf(range_header, "bytes=%lu-%lu", offset, offset+size-1);
|
||||
Headers headers = {{"Range", range_header}};
|
||||
size_t bytes_read = 0;
|
||||
std::vector<char> body;
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
body.insert(body.end(), data, data + data_length);
|
||||
bytes_read += data_length;
|
||||
if (bytes_read > size)
|
||||
return false;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
if (body.size() != size)
|
||||
return 0;
|
||||
memcpy(buffer, body.data(), size);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BaseClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
@@ -126,21 +156,22 @@ int BaseClient::Move(const std::string &from, const std::string &to)
|
||||
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);
|
||||
sprintf(range_header, "bytes=%lu-%lu", 0L, len - 1);
|
||||
Headers headers = {{"Range", range_header}};
|
||||
size_t bytes_read = 0;
|
||||
std::vector<char> body;
|
||||
if (auto res = client->Get(GetFullPath(path), headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
body.insert(body.end(), data, data+data_length);
|
||||
bytes_read += data_length;
|
||||
if (bytes_read > len)
|
||||
return false;
|
||||
return true;
|
||||
}))
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
body.insert(body.end(), data, data + data_length);
|
||||
bytes_read += data_length;
|
||||
if (bytes_read > len)
|
||||
return false;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
if (body.size() < len) return 0;
|
||||
if (body.size() < len)
|
||||
return 0;
|
||||
memcpy(buffer, body.data(), len);
|
||||
return 1;
|
||||
}
|
||||
@@ -161,21 +192,7 @@ std::vector<DirEntry> BaseClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path[path.length() - 1] == '/' && path.length() > 1)
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
return out;
|
||||
@@ -187,7 +204,9 @@ std::string BaseClient::GetPath(std::string ppath1, std::string ppath2)
|
||||
std::string path2 = ppath2;
|
||||
path1 = Util::Trim(Util::Trim(path1, " "), "/");
|
||||
path2 = Util::Trim(Util::Trim(path2, " "), "/");
|
||||
path1 = this->base_path + "/" + path1 + "/" + path2;
|
||||
path1 = this->base_path + ((this->base_path.length() > 0) ? "/" : "") + path1 + "/" + path2;
|
||||
if (path1[0] != '/')
|
||||
path1 = "/" + path1;
|
||||
return path1;
|
||||
}
|
||||
|
||||
@@ -242,3 +261,38 @@ uint32_t BaseClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_DOWNLOAD | REMOTE_ACTION_INSTALL;
|
||||
}
|
||||
|
||||
std::string BaseClient::EncodeUrl(const std::string &url)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
if (curl)
|
||||
{
|
||||
char *output = curl_easy_escape(curl, url.c_str(), url.length());
|
||||
if (output)
|
||||
{
|
||||
std::string encoded_url = std::string(output);
|
||||
curl_free(output);
|
||||
return encoded_url;
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string BaseClient::DecodeUrl(const std::string &url)
|
||||
{
|
||||
CURL *curl = curl_easy_init();
|
||||
if (curl)
|
||||
{
|
||||
int decode_len;
|
||||
char *output = curl_easy_unescape(curl, url.c_str(), url.length(), &decode_len);
|
||||
if (output)
|
||||
{
|
||||
std::string decoded_url = std::string(output, decode_len);
|
||||
curl_free(output);
|
||||
return decoded_url;
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class BaseClient : public RemoteClient
|
||||
{
|
||||
@@ -17,6 +17,7 @@ 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 GetRange(const std::string &path, void *buffer, 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 +34,8 @@ public:
|
||||
int Quit();
|
||||
ClientType clientType();
|
||||
uint32_t SupportedActions();
|
||||
static std::string EncodeUrl(const std::string &url);
|
||||
static std::string DecodeUrl(const std::string &url);
|
||||
|
||||
protected:
|
||||
httplib::Client *client;
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <sys/errno.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
@@ -12,11 +12,10 @@
|
||||
#include <errno.h>
|
||||
|
||||
#include "lang.h"
|
||||
#include "ftpclient.h"
|
||||
#include "clients/ftpclient.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
|
||||
|
||||
#define FTP_CLIENT_BUFSIZ 1048576
|
||||
#define ACCEPT_TIMEOUT 30
|
||||
|
||||
@@ -1267,6 +1266,40 @@ int FtpClient::Get(const std::string &outputfile, const std::string &path, uint6
|
||||
return FtpXfer(outputfile, path, mp_ftphandle, FtpClient::filereadappend, FtpClient::transfermode::image);
|
||||
}
|
||||
|
||||
int FtpClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
ftphandle *nData;
|
||||
mp_ftphandle->offset = offset;
|
||||
if (!FtpAccess(path, FtpClient::fileread, FtpClient::transfermode::image, mp_ftphandle, &nData))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char buf[8192];
|
||||
int l = 0;
|
||||
uint64_t remaining = size;
|
||||
char *p = (char*) buffer;
|
||||
while ((l = FtpRead(buf, 8192, nData)) > 0)
|
||||
{
|
||||
if (l <= remaining)
|
||||
{
|
||||
memcpy(p, buf, l);
|
||||
p += l;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(p, buf, remaining);
|
||||
break;
|
||||
}
|
||||
remaining -= l;
|
||||
}
|
||||
FtpClose(nData);
|
||||
mp_ftphandle->offset = 0;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* FtpPut - issue a PUT command and send data from input
|
||||
*
|
||||
@@ -1578,21 +1611,7 @@ std::vector<DirEntry> FtpClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path[path.length() - 1] == '/' && path.length() > 1)
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
ftphandle *nData;
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <time.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "remote_client.h"
|
||||
#include "clients/remote_client.h"
|
||||
|
||||
#define FTP_CLIENT_MAX_FILENAME_LEN 128
|
||||
|
||||
@@ -78,6 +78,7 @@ 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 GetRange(const std::string &path, void *buffer, 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);
|
||||
@@ -0,0 +1,915 @@
|
||||
#include <orbis/UserService.h>
|
||||
#include <lexbor/html/parser.h>
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <json-c/json.h>
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "server/http_server.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/gdrive.h"
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
#include "system.h"
|
||||
|
||||
#define GOOGLE_BUF_SIZE 262144
|
||||
|
||||
static std::string shared_with_me("Shared with me");
|
||||
static std::string my_drive("My Drive");
|
||||
|
||||
using namespace httplib;
|
||||
|
||||
std::string GetRedirectUrl()
|
||||
{
|
||||
return std::string("https://localhost:" + std::to_string(http_server_port) + "/google_auth");
|
||||
}
|
||||
|
||||
std::string GetScopes()
|
||||
{
|
||||
std::vector<std::string> permissions = Util::Split(gg_app.permissions, ",");
|
||||
std::string scopes;
|
||||
for (int i = 0; i < permissions.size(); i++)
|
||||
{
|
||||
scopes.append("https://www.googleapis.com/auth/");
|
||||
scopes.append(permissions[i]);
|
||||
if (i < permissions.size() - 1)
|
||||
{
|
||||
scopes.append(" ");
|
||||
}
|
||||
}
|
||||
return scopes;
|
||||
}
|
||||
|
||||
int RefreshAccessToken()
|
||||
{
|
||||
Client client(GOOGLE_OAUTH_HOST);
|
||||
client.enable_server_certificate_verification(false);
|
||||
client.set_follow_location(true);
|
||||
std::string url = std::string("/token");
|
||||
std::string post_data = std::string("grant_type=refresh_token") +
|
||||
"&client_id=" + gg_app.client_id +
|
||||
"&client_secret=" + gg_app.client_secret +
|
||||
"&refresh_token=" + remote_settings->gg_account.refresh_token;
|
||||
|
||||
if (auto res = client.Post(url, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
enum json_type type;
|
||||
json_object_object_foreach(jobj, key, val)
|
||||
{
|
||||
if (strcmp(key, "access_token") == 0)
|
||||
snprintf(remote_settings->gg_account.access_token, 255, "%s", json_object_get_string(val));
|
||||
else if (strcmp(key, "expires_in") == 0)
|
||||
{
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
remote_settings->gg_account.token_expiry = tick.mytick + (json_object_get_uint64(val) * 1000000);
|
||||
}
|
||||
}
|
||||
if (remoteclient != nullptr && remoteclient->clientType() == CLIENT_TYPE_GOOGLE)
|
||||
{
|
||||
GDriveClient *client = (GDriveClient *)remoteclient;
|
||||
client->SetAccessToken(remote_settings->gg_account.access_token);
|
||||
}
|
||||
CONFIG::SaveConfig();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int login_state;
|
||||
|
||||
std::string GetValue(const std::map<std::string, std::string> &options, const std::string &name)
|
||||
{
|
||||
auto it = options.find(name);
|
||||
if (it == options.end())
|
||||
{
|
||||
return std::string{""};
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
int GDriveClient::RequestAuthorization()
|
||||
{
|
||||
SceShellUIUtilLaunchByUriParam param;
|
||||
param.size = sizeof(SceShellUIUtilLaunchByUriParam);
|
||||
sceUserServiceGetForegroundUser((int *)¶m.userId);
|
||||
|
||||
std::string auth_url = std::string(GOOGLE_AUTH_URL "?client_id=") + gg_app.client_id + "&redirect_uri=" + GetRedirectUrl() +
|
||||
"&response_type=code&access_type=offline&scope=" + GetScopes() + "&include_granted_scopes=true";
|
||||
auth_url = EncodeUrl(auth_url);
|
||||
std::string launch_uri = std::string("pswebbrowser:search?url=") + auth_url;
|
||||
int ret = sceShellUIUtilLaunchByUri(launch_uri.c_str(), ¶m);
|
||||
|
||||
login_state = 0;
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
while (login_state == 0)
|
||||
{
|
||||
OrbisTick cur_tick;
|
||||
sceRtcGetCurrentTick(&cur_tick);
|
||||
if (cur_tick.mytick - tick.mytick > 120000000)
|
||||
{
|
||||
login_state = -2;
|
||||
break;
|
||||
}
|
||||
sceKernelUsleep(100000);
|
||||
}
|
||||
|
||||
if (login_state == -1)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_GOOGLE_LOGIN_FAIL_MSG]);
|
||||
return 0;
|
||||
}
|
||||
else if (login_state == -2)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_GOOGLE_LOGIN_TIMEOUT_MSG]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string GDriveClient::GetDriveId(const std::string path)
|
||||
{
|
||||
size_t slash_pos = path.find("/", 1);
|
||||
std::string root_path = path.substr(0, slash_pos);
|
||||
std::string id = GetValue(shared_drive_map, root_path);
|
||||
return id;
|
||||
}
|
||||
|
||||
GDriveClient::GDriveClient()
|
||||
{
|
||||
client = nullptr;
|
||||
path_id_map.insert(std::make_pair("/" + my_drive, "root"));
|
||||
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)
|
||||
{
|
||||
if (strlen(remote_settings->gg_account.refresh_token) > 0)
|
||||
{
|
||||
int ret = RefreshAccessToken();
|
||||
if (ret == 0)
|
||||
{
|
||||
RequestAuthorization();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RequestAuthorization();
|
||||
}
|
||||
StartRefreshToken();
|
||||
|
||||
client = new Client(GOOGLE_API_URL);
|
||||
client->set_bearer_token_auth(remote_settings->gg_account.access_token);
|
||||
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->connected = true;
|
||||
|
||||
std::string drives_url = std::string("/drive/v3/drives?pageSize=100");
|
||||
if (auto res = client->Get(drives_url))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
json_object *drives = json_object_object_get(jobj, "drives");
|
||||
if (json_object_get_type(drives) == json_type_array)
|
||||
{
|
||||
struct array_list *adrives = json_object_get_array(drives);
|
||||
for (size_t idx = 0; idx < adrives->length; ++idx)
|
||||
{
|
||||
json_object *drive = (json_object *)array_list_get_idx(adrives, idx);
|
||||
const char *id = json_object_get_string(json_object_object_get(drive, "id"));
|
||||
const char *name = json_object_get_string(json_object_object_get(drive, "name"));
|
||||
shared_drive_map.insert(std::make_pair("/" + std::string(name), id));
|
||||
path_id_map.insert(std::make_pair("/" + std::string(name), id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GDriveClient::Rename(const std::string &src, const std::string &dst)
|
||||
{
|
||||
if (src.find("/" + shared_with_me) != std::string::npos || dst.find("/" + shared_with_me) != std::string::npos)
|
||||
return 0;
|
||||
|
||||
std::string src_id = GetValue(path_id_map, src);
|
||||
std::string dst_id = GetValue(path_id_map, dst);
|
||||
std::string src_drive_id = GetDriveId(src);
|
||||
std::string dst_drive_id = GetDriveId(dst);
|
||||
|
||||
if (src_id.compare("root") == 0 || dst_id.compare("root") == 0 || src_id.compare(src_drive_id) == 0 || dst_id.compare(dst_drive_id) == 0)
|
||||
return 0;
|
||||
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(src_id);
|
||||
if (!src_drive_id.empty())
|
||||
url += "?supportsAllDrives=true";
|
||||
std::string filename = dst.substr(dst.find_last_of("/") + 1);
|
||||
std::string body = "{'name' : '" + filename + "'}";
|
||||
if (auto res = client->Patch(url, body.c_str(), body.length(), "application/json; charset=UTF-8"))
|
||||
{
|
||||
sprintf(response, "%d", res->status);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
path_id_map.erase(src);
|
||||
path_id_map.insert(std::make_pair(dst, src_id));
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(response, "%s", to_string(res.error()).c_str());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool GDriveClient::FileExists(const std::string &path)
|
||||
{
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
if (id.empty()) // then find it parent folder to see if it exists
|
||||
{
|
||||
size_t name_separator = path.find_last_of("/");
|
||||
std::string parent = path.substr(0, name_separator);
|
||||
if (parent.empty())
|
||||
parent = "/";
|
||||
|
||||
if (FileExists(parent))
|
||||
{
|
||||
ListDir(parent);
|
||||
id = GetValue(path_id_map, path);
|
||||
if (!id.empty())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
int GDriveClient::Head(const std::string &path, void *buffer, uint64_t len)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
std::vector<char> body;
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Range", "bytes=" + std::to_string(0) + "-" + std::to_string(len - 1)));
|
||||
if (auto res = client->Get(url, headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
body.insert(body.end(), data, data + data_length);
|
||||
bytes_read += data_length;
|
||||
if (bytes_read > len)
|
||||
return false;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
if (body.size() < len)
|
||||
return 0;
|
||||
memcpy(buffer, body.data(), len);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GDriveClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
|
||||
{
|
||||
std::ofstream file_stream(outputfile, std::ios::binary);
|
||||
bytes_transfered = 0;
|
||||
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
if (auto res = client->Get(url,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
file_stream.write(data, data_length);
|
||||
bytes_transfered += data_length;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GDriveClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
size_t bytes_read = 0;
|
||||
std::vector<char> body;
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Range", "bytes=" + std::to_string(offset) + "-" + std::to_string(offset + size - 1)));
|
||||
if (auto res = client->Get(url, headers,
|
||||
[&](const char *data, size_t data_length)
|
||||
{
|
||||
body.insert(body.end(), data, data + data_length);
|
||||
bytes_read += data_length;
|
||||
if (bytes_read > size)
|
||||
return false;
|
||||
return true;
|
||||
}))
|
||||
{
|
||||
if (body.size() != size)
|
||||
return 0;
|
||||
memcpy(buffer, body.data(), size);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", httplib::to_string(res.error()).c_str());
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int GDriveClient::Update(const std::string &inputfile, const std::string &path)
|
||||
{
|
||||
bytes_to_download = FS::GetSize(inputfile);
|
||||
bytes_transfered = 0;
|
||||
|
||||
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);
|
||||
|
||||
std::string url = "/upload/drive/v3/files/" + BaseClient::EncodeUrl(id) + "?uploadType=resumable";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
|
||||
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
|
||||
char *buf = new char[GOOGLE_BUF_SIZE];
|
||||
if (auto res = client->Patch(url))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
std::string upload_uri = res->get_header_value("location");
|
||||
upload_uri = std::regex_replace(upload_uri, std::regex(GOOGLE_API_URL), "");
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download)));
|
||||
std::string range_value = "bytes 0-" + std::to_string(bytes_to_download - 1) + "/" + std::to_string(bytes_to_download);
|
||||
headers.insert(std::make_pair("Content-Range", range_value));
|
||||
|
||||
if (auto res = client->Put(
|
||||
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);
|
||||
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);
|
||||
} while (count < length);
|
||||
return true;
|
||||
},
|
||||
"application/octet-stream"))
|
||||
{
|
||||
// success
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GDriveClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset)
|
||||
{
|
||||
if (path.find("/" + shared_with_me) != std::string::npos || path.compare("/") == 0)
|
||||
return 0;
|
||||
|
||||
if (FileExists(path))
|
||||
return Update(inputfile, path);
|
||||
|
||||
bytes_to_download = FS::GetSize(inputfile);
|
||||
bytes_transfered = 0;
|
||||
|
||||
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)
|
||||
parent_dir = "/";
|
||||
else
|
||||
parent_dir = path.substr(0, path_pos);
|
||||
|
||||
std::string filename = path.substr(path_pos + 1);
|
||||
std::string parent_id = GetValue(path_id_map, parent_dir);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
|
||||
std::string url = "/upload/drive/v3/files?uploadType=resumable";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
|
||||
std::string post_data = std::string("{'name': '") + filename + "'," +
|
||||
(drive_id.empty() ? "" : "'driveId' : '" + drive_id + "',") +
|
||||
"'parents': ['" + parent_id + "']}";
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream"));
|
||||
headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download)));
|
||||
char *buf = new char[GOOGLE_BUF_SIZE];
|
||||
if (auto res = client->Post(url, headers, post_data.c_str(), post_data.length(), "application/json"))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
std::string upload_uri = res->get_header_value("location");
|
||||
upload_uri = std::regex_replace(upload_uri, std::regex(GOOGLE_API_URL), "");
|
||||
Headers headers;
|
||||
headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download)));
|
||||
std::string range_value = "bytes 0-" + std::to_string(bytes_to_download - 1) + "/" + std::to_string(bytes_to_download);
|
||||
headers.insert(std::make_pair("Content-Range", range_value));
|
||||
|
||||
if (auto res = client->Put(
|
||||
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);
|
||||
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);
|
||||
} while (count < length);
|
||||
return true;
|
||||
},
|
||||
"application/octet-stream"))
|
||||
{
|
||||
// success
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
delete[] buf;
|
||||
file_stream.close();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GDriveClient::Size(const std::string &path, int64_t *size)
|
||||
{
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?fields=size";
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
if (auto res = client->Get(url))
|
||||
{
|
||||
sprintf(response, "%d", res->status);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
*size = json_object_get_uint64(json_object_object_get(jobj, "size"));
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(response, "%s", to_string(res.error()).c_str());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GDriveClient::Mkdir(const std::string &path)
|
||||
{
|
||||
if (path.find("/" + shared_with_me) != std::string::npos || path.find_last_of("/") == 0)
|
||||
return 0;
|
||||
|
||||
// if path already exists return;
|
||||
if (FileExists(path))
|
||||
return 1;
|
||||
|
||||
size_t path_pos = path.find_last_of("/");
|
||||
std::string parent_dir;
|
||||
if (path_pos == 0)
|
||||
parent_dir = "/";
|
||||
else
|
||||
parent_dir = path.substr(0, path_pos);
|
||||
|
||||
std::string folder_name = path.substr(path_pos + 1);
|
||||
std::string parent_id = GetValue(path_id_map, parent_dir);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
|
||||
// if parent dir does not exists, create it first
|
||||
if (parent_id.length() == 0 || parent_id.empty())
|
||||
{
|
||||
Mkdir(parent_dir);
|
||||
parent_id = GetValue(path_id_map, parent_dir);
|
||||
}
|
||||
|
||||
std::string url = std::string("/drive/v3/files?fields=id");
|
||||
if (!drive_id.empty())
|
||||
url += "&supportsAllDrives=true";
|
||||
std::string folder_metadata = "{'name' : '" + folder_name + "'," +
|
||||
"'parents' : ['" + parent_id + "']," +
|
||||
(drive_id.empty() ? "" : "'driveId' : '" + drive_id + "',") +
|
||||
"'mimeType' : 'application/vnd.google-apps.folder'}";
|
||||
|
||||
if (auto res = client->Post(url, folder_metadata.c_str(), folder_metadata.length(), "application/json; charset=UTF-8"))
|
||||
{
|
||||
sprintf(response, "%d", res->status);
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
const char *id = json_object_get_string(json_object_object_get(jobj, "id"));
|
||||
path_id_map.insert(std::make_pair(path, id));
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(response, "%s", to_string(res.error()).c_str());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rmdir in google drive deletes all files/folders in subdirectories also.
|
||||
* Delete file/folder is the same api
|
||||
*/
|
||||
int GDriveClient::Rmdir(const std::string &path, bool recursive)
|
||||
{
|
||||
if (path.find("/" + shared_with_me) != std::string::npos)
|
||||
return 0;
|
||||
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
|
||||
if (id.compare("root") == 0 || id.compare(drive_id) == 0)
|
||||
return 0;
|
||||
|
||||
int ret = Delete(path);
|
||||
if (ret != 0)
|
||||
{
|
||||
std::string subfolders = path + "/";
|
||||
for (std::map<std::string, std::string>::iterator it = path_id_map.begin(); it != path_id_map.end();)
|
||||
{
|
||||
if (strncmp(it->first.c_str(), subfolders.c_str(), path.length()) == 0)
|
||||
{
|
||||
it = path_id_map.erase(it);
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int GDriveClient::Delete(const std::string &path)
|
||||
{
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
std::string drive_id = GetDriveId(path);
|
||||
if (strcmp(id.c_str(), "root") == 0)
|
||||
return 0;
|
||||
|
||||
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id);
|
||||
if (!drive_id.empty())
|
||||
url += "?supportsAllDrives=true";
|
||||
if (auto res = client->Delete(url))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
path_id_map.erase(path);
|
||||
sprintf(response, "%d", res->status);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(response, "%s", to_string(res.error()).c_str());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SetupSharedWithMeFolder(DirEntry *entry)
|
||||
{
|
||||
memset(entry, 0, sizeof(DirEntry));
|
||||
sprintf(entry->directory, "%s", "/");
|
||||
sprintf(entry->name, "%s", shared_with_me.c_str());
|
||||
sprintf(entry->path, "/%s", shared_with_me.c_str());
|
||||
sprintf(entry->display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry->file_size = 0;
|
||||
entry->isDir = true;
|
||||
entry->selectable = false;
|
||||
}
|
||||
|
||||
void SetupMyDriveFolder(DirEntry *entry)
|
||||
{
|
||||
memset(entry, 0, sizeof(DirEntry));
|
||||
sprintf(entry->directory, "%s", "/");
|
||||
sprintf(entry->name, "%s", my_drive.c_str());
|
||||
sprintf(entry->path, "/%s", my_drive.c_str());
|
||||
sprintf(entry->display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry->file_size = 0;
|
||||
entry->isDir = true;
|
||||
entry->selectable = false;
|
||||
}
|
||||
|
||||
std::vector<DirEntry> GDriveClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
if (strcmp(path.c_str(), "/") == 0)
|
||||
{
|
||||
SetupSharedWithMeFolder(&entry);
|
||||
out.push_back(entry);
|
||||
SetupMyDriveFolder(&entry);
|
||||
out.push_back(entry);
|
||||
|
||||
std::string drives_url = std::string("/drive/v3/drives?pageSize=100");
|
||||
if (auto res = client->Get(drives_url))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
json_object *drives = json_object_object_get(jobj, "drives");
|
||||
if (json_object_get_type(drives) == json_type_array)
|
||||
{
|
||||
struct array_list *adrives = json_object_get_array(drives);
|
||||
for (size_t idx = 0; idx < adrives->length; ++idx)
|
||||
{
|
||||
json_object *drive = (json_object *)array_list_get_idx(adrives, idx);
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
entry.selectable = false;
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
|
||||
const char *id = json_object_get_string(json_object_object_get(drive, "id"));
|
||||
const char *name = json_object_get_string(json_object_object_get(drive, "name"));
|
||||
sprintf(entry.name, "%s", name);
|
||||
sprintf(entry.path, "/%s", name);
|
||||
shared_drive_map.insert(std::make_pair(entry.path, id));
|
||||
path_id_map.insert(std::make_pair(entry.path, id));
|
||||
out.push_back(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string id = GetValue(path_id_map, path);
|
||||
if (id.empty())
|
||||
{
|
||||
if (FileExists(path))
|
||||
{
|
||||
id = GetValue(path_id_map, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
std::string drive_id = GetDriveId(path);
|
||||
std::string base_url = std::string("/drive/v3/files?q=") + BaseClient::EncodeUrl("\"" + id + "\" in parents") +
|
||||
"&pageSize=1000&fields=" + BaseClient::EncodeUrl("files(id,mimeType,name,modifiedTime,size),nextPageToken");
|
||||
if (!drive_id.empty())
|
||||
{
|
||||
base_url += "&driveId=" + drive_id + "&corpora=drive&includeItemsFromAllDrives=true&supportsAllDrives=true";
|
||||
}
|
||||
|
||||
bool find_no_parent = false;
|
||||
if (id.compare(shared_with_me) == 0)
|
||||
{
|
||||
base_url = std::string("/drive/v3/files?q=sharedWithMe&pageSize=1000&fields=") + BaseClient::EncodeUrl("files(id,mimeType,name,modifiedTime,size),nextPageToken");
|
||||
}
|
||||
|
||||
std::string next_page_url = base_url;
|
||||
while (true)
|
||||
{
|
||||
if (auto res = client->Get(next_page_url))
|
||||
{
|
||||
if (HTTP_SUCCESS(res->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(res->body.c_str());
|
||||
json_object *next_page_token = json_object_object_get(jobj, "nextPageToken");
|
||||
json_object *files = json_object_object_get(jobj, "files");
|
||||
if (json_object_get_type(files) == json_type_array)
|
||||
{
|
||||
struct array_list *afiles = json_object_get_array(files);
|
||||
for (size_t idx = 0; idx < afiles->length; ++idx)
|
||||
{
|
||||
json_object *file = (json_object *)array_list_get_idx(afiles, idx);
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
entry.selectable = true;
|
||||
entry.file_size = 0;
|
||||
|
||||
const char *id = json_object_get_string(json_object_object_get(file, "id"));
|
||||
const char *name = json_object_get_string(json_object_object_get(file, "name"));
|
||||
const char *mime_type = json_object_get_string(json_object_object_get(file, "mimeType"));
|
||||
const char *modified_time = json_object_get_string(json_object_object_get(file, "modifiedTime"));
|
||||
|
||||
snprintf(entry.name, 255, "%s", name);
|
||||
if (path.length() > 0 && path[path.length() - 1] == '/')
|
||||
{
|
||||
snprintf(entry.path, 767, "%s%s", path.c_str(), entry.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.path, "%s/%s", path.c_str(), entry.name);
|
||||
}
|
||||
path_id_map.insert(std::make_pair(entry.path, id));
|
||||
|
||||
if (strncmp(mime_type, "application/vnd.google-apps.folder", 35) != 0)
|
||||
{
|
||||
entry.file_size = json_object_get_uint64(json_object_object_get(file, "size"));
|
||||
entry.isDir = false;
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.isDir = true;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
}
|
||||
|
||||
std::vector<std::string> date_time_arr = Util::Split(modified_time, "T");
|
||||
std::vector<std::string> adate = Util::Split(date_time_arr[0], "-");
|
||||
std::vector<std::string> atime = Util::Split(Util::Split(date_time_arr[1], ".")[0], ":");
|
||||
OrbisDateTime utc, local;
|
||||
utc.year = std::atoi(adate[0].c_str());
|
||||
utc.month = std::atoi(adate[1].c_str());
|
||||
utc.day = std::atoi(adate[2].c_str());
|
||||
utc.hour = std::atoi(atime[0].c_str());
|
||||
utc.minute = std::atoi(atime[1].c_str());
|
||||
utc.second = std::atoi(atime[2].c_str());
|
||||
|
||||
convertUtcToLocalTime(&utc, &local);
|
||||
|
||||
entry.modified.year = local.year;
|
||||
entry.modified.month = local.month;
|
||||
entry.modified.day = local.day;
|
||||
entry.modified.hours = local.hour;
|
||||
entry.modified.minutes = local.minute;
|
||||
entry.modified.seconds = local.second;
|
||||
|
||||
out.push_back(entry);
|
||||
}
|
||||
}
|
||||
if (next_page_token != nullptr)
|
||||
next_page_url = base_url + "&pageToken=" + BaseClient::EncodeUrl(json_object_get_string(next_page_token));
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
ClientType GDriveClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_GOOGLE;
|
||||
}
|
||||
|
||||
uint32_t GDriveClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
}
|
||||
|
||||
void *GDriveClient::RefreshTokenThread(void *argp)
|
||||
{
|
||||
while (refresh_token_running)
|
||||
{
|
||||
OrbisTick tick;
|
||||
memset(&tick, 0, sizeof(OrbisTick));
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
if (tick.mytick >= (remote_settings->gg_account.token_expiry - 300000000) &&
|
||||
remote_settings->type == CLIENT_TYPE_GOOGLE) // refresh token 5mins before expiry
|
||||
{
|
||||
RefreshAccessToken();
|
||||
}
|
||||
sceKernelUsleep(500000); // check every 0.5s
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void GDriveClient::StartRefreshToken()
|
||||
{
|
||||
if (refresh_token_running)
|
||||
return;
|
||||
|
||||
refresh_token_running = true;
|
||||
int ret = pthread_create(&refresh_token_thid, NULL, RefreshTokenThread, NULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
refresh_token_running = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GDriveClient::StopRefreshToken()
|
||||
{
|
||||
refresh_token_running = false;
|
||||
}
|
||||
|
||||
int GDriveClient::Quit()
|
||||
{
|
||||
StopRefreshToken();
|
||||
if (client != nullptr)
|
||||
{
|
||||
delete client;
|
||||
client = nullptr;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GDriveClient::SetAccessToken(const std::string &token)
|
||||
{
|
||||
if (this->client != nullptr)
|
||||
this->client->set_bearer_token_auth(token);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef GDRIVE_H
|
||||
#define GDRIVE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
|
||||
static pthread_t refresh_token_thid;
|
||||
static bool refresh_token_running = false;
|
||||
extern int login_state;
|
||||
|
||||
class GDriveClient : public BaseClient
|
||||
{
|
||||
public:
|
||||
GDriveClient();
|
||||
int Connect(const std::string &url, const std::string &user, const std::string &pass);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int 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);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Mkdir(const std::string &path);
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Delete(const std::string &path);
|
||||
bool FileExists(const std::string &path);
|
||||
void SetAccessToken(const std::string &token);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
static void *RefreshTokenThread(void *argp);
|
||||
static void StartRefreshToken();
|
||||
static void StopRefreshToken();
|
||||
ClientType clientType();
|
||||
uint32_t SupportedActions();
|
||||
int Quit();
|
||||
|
||||
private:
|
||||
int RequestAuthorization();
|
||||
std::string GetDriveId(const std::string path);
|
||||
std::map<std::string, std::string> path_id_map;
|
||||
std::map<std::string, std::string> shared_drive_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <fstream>
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
#include "http/iis.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/iis.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
@@ -16,21 +16,7 @@ std::vector<DirEntry> IISClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path[path.length() - 1] == '/' && path.length() > 1)
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
if (auto res = client->Get(GetFullPath(path)))
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "http/baseclient.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class IISClient : public BaseClient
|
||||
{
|
||||
@@ -4,8 +4,8 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
#include "http/nginx.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/nginx.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
@@ -23,21 +23,7 @@ std::vector<DirEntry> NginxClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path[path.length() - 1] == '/' && path.length() > 1)
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
if (auto res = client->Get(GetFullPath(path)))
|
||||
@@ -95,9 +81,10 @@ std::vector<DirEntry> NginxClient::ListDir(const std::string &path)
|
||||
tmp = std::string((const char *)value, value_len);
|
||||
if (tmp.compare("a") == 0)
|
||||
{
|
||||
value = lxb_dom_node_text_content(node, &value_len);
|
||||
value = lxb_dom_element_get_attribute(lxb_dom_interface_element(node), (const lxb_char_t *)"href", 4, &value_len);
|
||||
tmp = std::string((const char *)value, value_len);
|
||||
tmp = Util::Rtrim(tmp, "/");
|
||||
tmp = BaseClient::DecodeUrl(tmp);
|
||||
if (tmp.compare("..") != 0)
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "http/baseclient.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
#include "clients/remote_client.h"
|
||||
|
||||
class NginxClient : public BaseClient
|
||||
{
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <lexbor/dom/interfaces/element.h>
|
||||
#include <fstream>
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
#include "http/npxserve.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/npxserve.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
@@ -16,21 +16,7 @@ std::vector<DirEntry> NpxServeClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path[path.length() - 1] == '/' && path.length() > 1)
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
if (auto res = client->Get(GetFullPath(path)))
|
||||
@@ -4,9 +4,9 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "http/httplib.h"
|
||||
#include "http/baseclient.h"
|
||||
#include "clients/baseclient.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
class NpxServeClient : public BaseClient
|
||||
{
|
||||
@@ -17,7 +17,9 @@ enum RemoteActions
|
||||
REMOTE_ACTION_DOWNLOAD = 64,
|
||||
REMOTE_ACTION_UPLOAD = 128,
|
||||
REMOTE_ACTION_INSTALL = 256,
|
||||
REMOTE_ACTION_ALL = 511
|
||||
REMOTE_ACTION_EDIT = 512,
|
||||
REMOTE_ACTION_NEW_FILE = 1024,
|
||||
REMOTE_ACTION_ALL = 2047
|
||||
};
|
||||
|
||||
enum ClientType
|
||||
@@ -26,6 +28,7 @@ enum ClientType
|
||||
CLIENT_TYPE_SMB,
|
||||
CLIENT_TYPE_WEBDAV,
|
||||
CLIENT_TYPE_HTTP_SERVER,
|
||||
CLIENT_TYPE_GOOGLE,
|
||||
CLINET_TYPE_UNKNOWN
|
||||
};
|
||||
|
||||
@@ -45,6 +48,7 @@ public:
|
||||
virtual int Copy(const std::string &from, const std::string &to) = 0;
|
||||
virtual int Move(const std::string &from, const std::string &to) = 0;
|
||||
virtual int Head(const std::string &path, void *buffer, uint64_t len) = 0;
|
||||
virtual int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset) = 0;
|
||||
virtual bool FileExists(const std::string &path) = 0;
|
||||
virtual std::vector<DirEntry> ListDir(const std::string &path) = 0;
|
||||
virtual std::string GetPath(std::string path1, std::string path2) = 0;
|
||||
@@ -0,0 +1,610 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
#include "common.h"
|
||||
#include "clients/remote_client.h"
|
||||
#include "clients/sftpclient.h"
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
#include "util.h"
|
||||
#include "windows.h"
|
||||
#include "system.h"
|
||||
|
||||
#define FTP_CLIENT_BUFSIZ 1048576
|
||||
|
||||
SFTPClient::SFTPClient()
|
||||
{
|
||||
session = nullptr;
|
||||
sftp_session = nullptr;
|
||||
sock = 0;
|
||||
};
|
||||
|
||||
SFTPClient::~SFTPClient(){};
|
||||
|
||||
int SFTPClient::Connect(const std::string &url, const std::string &username, const std::string &password)
|
||||
{
|
||||
int port = 22;
|
||||
std::string host = url.substr(7);
|
||||
size_t colon_pos = host.find(":");
|
||||
if (colon_pos != std::string::npos)
|
||||
{
|
||||
port = std::atoi(host.substr(colon_pos + 1).c_str());
|
||||
host = host.substr(0, colon_pos);
|
||||
}
|
||||
|
||||
struct hostent *he;
|
||||
struct in_addr **addr_list;
|
||||
char ip[20];
|
||||
int i;
|
||||
|
||||
if (strcmp(host.c_str(), "localhost") == 0)
|
||||
{
|
||||
sprintf(ip, "%s", "127.0.0.1");
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((he = gethostbyname(host.c_str())) == NULL)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_COULD_NOT_RESOLVE_HOST]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_list = (struct in_addr **)he->h_addr_list;
|
||||
for (i = 0; addr_list[i] != NULL; i++)
|
||||
{
|
||||
strcpy(ip, inet_ntoa(*addr_list[i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
in_addr dst_addr;
|
||||
sockaddr_in server_addr;
|
||||
int on = 1;
|
||||
int32_t retval;
|
||||
|
||||
memset(&server_addr, 0, sizeof(server_addr));
|
||||
inet_pton(AF_INET, ip, (void *)&dst_addr);
|
||||
server_addr.sin_addr = dst_addr;
|
||||
server_addr.sin_port = htons(port);
|
||||
server_addr.sin_family = AF_INET;
|
||||
|
||||
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
retval = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on));
|
||||
int const size = FTP_CLIENT_BUFSIZ;
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) == -1)
|
||||
{
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1)
|
||||
{
|
||||
close(sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (connect(sock, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr_in)) != 0)
|
||||
{
|
||||
sprintf(this->response, "%s", "Failed to connect!");
|
||||
return 0;
|
||||
}
|
||||
/* Create a session instance
|
||||
*/
|
||||
session = libssh2_session_init();
|
||||
libssh2_session_set_blocking(session, 1);
|
||||
libssh2_keepalive_config(session, 1, 5);
|
||||
|
||||
if (!session)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ... start it up. This will trade welcome banners, exchange keys,
|
||||
* and setup crypto, compression, and MAC layers
|
||||
*/
|
||||
sceKernelUsleep(100000);
|
||||
int rc = libssh2_session_handshake(session, sock);
|
||||
if (rc)
|
||||
{
|
||||
sprintf(this->response, "Failed SSL handshake %d", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* At this point we havn't yet authenticated. The first thing to do
|
||||
* is check the hostkey's fingerprint against our known hosts Your app
|
||||
* may have it hard coded, may go to a file, may present it to the
|
||||
* user, that's your call
|
||||
*/
|
||||
const char *fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
|
||||
|
||||
/* check what authentication methods are available */
|
||||
char *userauthlist = libssh2_userauth_list(session, username.c_str(), username.length());
|
||||
|
||||
int auth_pw = 0;
|
||||
if (strstr(userauthlist, "password") != NULL)
|
||||
{
|
||||
auth_pw |= 1;
|
||||
}
|
||||
if (strstr(userauthlist, "keyboard-interactive") != NULL)
|
||||
{
|
||||
auth_pw |= 2;
|
||||
}
|
||||
if (strstr(userauthlist, "publickey") != NULL)
|
||||
{
|
||||
auth_pw |= 4;
|
||||
}
|
||||
|
||||
bool use_identity = password.find("file://") != std::string::npos;
|
||||
if (auth_pw & 1 && !use_identity)
|
||||
{
|
||||
/* We could authenticate via password */
|
||||
if (libssh2_userauth_password(session, username.c_str(), password.c_str()))
|
||||
{
|
||||
sprintf(this->response, "%s", "Authentication by password failed!");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
else if (auth_pw & 4 && use_identity)
|
||||
{
|
||||
/* Or by public key */
|
||||
std::string publickey = password.substr(7) + "/id_rsa.pub";
|
||||
std::string privatekey = password.substr(7) + "/id_rsa";
|
||||
if (!FS::FileExists(publickey.c_str()))
|
||||
{
|
||||
sprintf(response, "SSH public key %s is not found", publickey.c_str());
|
||||
goto shutdown;
|
||||
}
|
||||
if (!FS::FileExists(privatekey.c_str()))
|
||||
{
|
||||
sprintf(response, "SSH private key %s is not found", privatekey.c_str());
|
||||
goto shutdown;
|
||||
}
|
||||
if (libssh2_userauth_publickey_fromfile(session, username.c_str(), publickey.c_str(), privatekey.c_str(), ""))
|
||||
{
|
||||
sprintf(this->response, "%s", "Authentication by public key failed!");
|
||||
goto shutdown;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(this->response, "%s", "No supported authentication methods found!");
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
sftp_session = libssh2_sftp_init(session);
|
||||
this->connected = true;
|
||||
return 1;
|
||||
|
||||
shutdown:
|
||||
libssh2_session_disconnect(session, "Normal Shutdown");
|
||||
libssh2_session_free(session);
|
||||
close(sock);
|
||||
libssh2_exit();
|
||||
session = nullptr;
|
||||
sock = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SFTPClient::Mkdir(const std::string &path)
|
||||
{
|
||||
int rc = libssh2_sftp_mkdir(sftp_session, path.c_str(),
|
||||
LIBSSH2_SFTP_S_IRWXU | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IXGRP | LIBSSH2_SFTP_S_IROTH | LIBSSH2_SFTP_S_IXOTH);
|
||||
if (rc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Rmdir(const std::string &path, bool recursive)
|
||||
{
|
||||
if (stop_activity)
|
||||
return 1;
|
||||
|
||||
std::vector<DirEntry> list = ListDir(path);
|
||||
int ret;
|
||||
for (int i = 0; i < list.size(); i++)
|
||||
{
|
||||
if (stop_activity)
|
||||
return 1;
|
||||
|
||||
if (list[i].isDir && recursive)
|
||||
{
|
||||
if (strcmp(list[i].name, "..") == 0)
|
||||
continue;
|
||||
ret = Rmdir(list[i].path, recursive);
|
||||
if (ret == 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_DIR_MSG], list[i].path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(activity_message, "%s %s\n", lang_strings[STR_DELETING], list[i].path);
|
||||
ret = Delete(list[i].path);
|
||||
if (ret == 0)
|
||||
{
|
||||
sprintf(status_message, "%s %s", lang_strings[STR_FAIL_DEL_FILE_MSG], list[i].path);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = Rmdir(path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Rmdir(const std::string &path)
|
||||
{
|
||||
int rc = libssh2_sftp_rmdir(sftp_session, path.c_str());
|
||||
if (rc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Size(const std::string &path, int64_t *size)
|
||||
{
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||
int rc = libssh2_sftp_stat(sftp_session, path.c_str(), &attrs);
|
||||
if (rc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*size = attrs.filesize;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset)
|
||||
{
|
||||
if (!Size(path, &bytes_to_download))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FILE *out = FS::Create(outputfile);
|
||||
if (out == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
int rc, count = 0;
|
||||
bytes_transfered = 0;
|
||||
do
|
||||
{
|
||||
rc = libssh2_sftp_read(sftp_handle, buff, FTP_CLIENT_BUFSIZ);
|
||||
if (rc > 0)
|
||||
{
|
||||
bytes_transfered += rc;
|
||||
FS::Write(out, buff, rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
FS::Close(out);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
int64_t filesize;
|
||||
if (!Size(path.c_str(), &filesize))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
|
||||
if (!sftp_handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset)
|
||||
{
|
||||
char *ptr, *buff;
|
||||
int rc;
|
||||
|
||||
bytes_to_download = FS::GetSize(inputfile);
|
||||
if (bytes_to_download < 0)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *in = FS::OpenRead(inputfile);
|
||||
if (in == NULL)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_FAILED]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_open(sftp_session, path.c_str(),
|
||||
LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
|
||||
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR |
|
||||
LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH);
|
||||
|
||||
if (!sftp_handle)
|
||||
{
|
||||
sprintf(response, "%s", "Unable to open file with SFTP");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buff = (char *)malloc(FTP_CLIENT_BUFSIZ);
|
||||
int nread, count = 0;
|
||||
bytes_transfered = 0;
|
||||
do
|
||||
{
|
||||
nread = FS::Read(in, buff, FTP_CLIENT_BUFSIZ);
|
||||
if (nread <= 0)
|
||||
{
|
||||
/* end of file */
|
||||
break;
|
||||
}
|
||||
ptr = buff;
|
||||
|
||||
do
|
||||
{
|
||||
/* write data in a loop until we block */
|
||||
rc = libssh2_sftp_write(sftp_handle, ptr, nread);
|
||||
|
||||
if (rc < 0)
|
||||
break;
|
||||
ptr += rc;
|
||||
nread -= rc;
|
||||
bytes_transfered += rc;
|
||||
} while (nread);
|
||||
} while (rc > 0);
|
||||
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
FS::Close(in);
|
||||
free(buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Rename(const std::string &src, const std::string &dst)
|
||||
{
|
||||
int rc = libssh2_sftp_rename_ex(sftp_session, src.c_str(), src.length(),
|
||||
dst.c_str(), dst.length(), LIBSSH2_SFTP_RENAME_ATOMIC | LIBSSH2_SFTP_RENAME_NATIVE);
|
||||
if (rc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Delete(const std::string &path)
|
||||
{
|
||||
int rc = libssh2_sftp_unlink(sftp_session, path.c_str());
|
||||
if (rc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SFTPClient::Copy(const std::string &from, const std::string &to)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SFTPClient::Move(const std::string &from, const std::string &to)
|
||||
{
|
||||
sprintf(this->response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SFTPClient::Head(const std::string &path, void *buffer, uint64_t len)
|
||||
{
|
||||
if (!Size(path.c_str(), &bytes_to_download))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_open(sftp_session, path.c_str(), LIBSSH2_FXF_READ, 0);
|
||||
if (!sftp_handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int count = libssh2_sftp_read(sftp_handle, (char *)buffer, len);
|
||||
libssh2_sftp_close(sftp_handle);
|
||||
if (count != len)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool SFTPClient::FileExists(const std::string &path)
|
||||
{
|
||||
int64_t file_size;
|
||||
return Size(path, &file_size);
|
||||
}
|
||||
|
||||
std::vector<DirEntry> SFTPClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
/* Request a dir listing via SFTP */
|
||||
LIBSSH2_SFTP_HANDLE *sftp_handle = libssh2_sftp_opendir(sftp_session, path.c_str());
|
||||
if (!sftp_handle)
|
||||
{
|
||||
return out;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
char mem[512];
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
entry.selectable = true;
|
||||
|
||||
/* loop until we fail */
|
||||
int rc = libssh2_sftp_readdir(sftp_handle, mem, sizeof(mem), &attrs);
|
||||
if (rc > 0)
|
||||
{
|
||||
std::string new_path = std::string(mem, rc);
|
||||
if (new_path.compare(".") == 0 || new_path.compare("..") == 0)
|
||||
continue;
|
||||
;
|
||||
|
||||
if (!show_hidden_files && new_path[0] == '.')
|
||||
continue;
|
||||
|
||||
sprintf(entry.name, "%s", new_path.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);
|
||||
}
|
||||
|
||||
if (LIBSSH2_SFTP_S_ISDIR(attrs.permissions))
|
||||
{
|
||||
entry.isDir = true;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
}
|
||||
else if (LIBSSH2_SFTP_S_ISREG(attrs.permissions))
|
||||
{
|
||||
entry.file_size = attrs.filesize;
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
entry.isDir = false;
|
||||
}
|
||||
else if (LIBSSH2_SFTP_S_ISLNK(attrs.permissions))
|
||||
{
|
||||
entry.file_size = 0;
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_LINK]);
|
||||
entry.isDir = false;
|
||||
entry.isLink = true;
|
||||
entry.selectable = false;
|
||||
}
|
||||
else // skip any files that aren't regular files/directory
|
||||
{
|
||||
entry.file_size = attrs.filesize;
|
||||
DirEntry::SetDisplaySize(&entry);
|
||||
entry.isDir = false;
|
||||
entry.selectable = false;
|
||||
}
|
||||
|
||||
struct tm tm = *localtime((const time_t *)&attrs.mtime);
|
||||
OrbisDateTime gmt;
|
||||
OrbisDateTime lt;
|
||||
|
||||
gmt.day = tm.tm_mday;
|
||||
gmt.month = tm.tm_mon + 1;
|
||||
gmt.year = tm.tm_year + 1900;
|
||||
gmt.hour = tm.tm_hour;
|
||||
gmt.minute = tm.tm_min;
|
||||
gmt.second = tm.tm_sec;
|
||||
|
||||
convertUtcToLocalTime(&gmt, <);
|
||||
|
||||
entry.modified.day = lt.day;
|
||||
entry.modified.month = lt.month;
|
||||
entry.modified.year = lt.year;
|
||||
entry.modified.hours = lt.hour;
|
||||
entry.modified.minutes = lt.minute;
|
||||
entry.modified.seconds = lt.second;
|
||||
|
||||
out.push_back(entry);
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
} while (1);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string SFTPClient::GetPath(std::string ppath1, std::string ppath2)
|
||||
{
|
||||
std::string path1 = ppath1;
|
||||
std::string path2 = ppath2;
|
||||
path1 = Util::Rtrim(Util::Trim(path1, " "), "/");
|
||||
path2 = Util::Rtrim(Util::Trim(path2, " "), "/");
|
||||
path1 = path1 + "/" + path2;
|
||||
return path1;
|
||||
}
|
||||
|
||||
bool SFTPClient::IsConnected()
|
||||
{
|
||||
return this->connected;
|
||||
}
|
||||
|
||||
bool SFTPClient::Ping()
|
||||
{
|
||||
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||
int rc = libssh2_sftp_stat(sftp_session, "/", &attrs);
|
||||
if (rc)
|
||||
{
|
||||
this->connected = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *SFTPClient::LastResponse()
|
||||
{
|
||||
return this->response;
|
||||
}
|
||||
|
||||
int SFTPClient::Quit()
|
||||
{
|
||||
if (sftp_session != nullptr)
|
||||
libssh2_sftp_shutdown(sftp_session);
|
||||
if (session != nullptr)
|
||||
{
|
||||
libssh2_session_disconnect(session, "Normal Shutdown");
|
||||
libssh2_session_free(session);
|
||||
close(sock);
|
||||
libssh2_exit();
|
||||
}
|
||||
session = nullptr;
|
||||
sftp_session = nullptr;
|
||||
sock = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ClientType SFTPClient::clientType()
|
||||
{
|
||||
return CLIENT_TYPE_FTP;
|
||||
}
|
||||
|
||||
uint32_t SFTPClient::SupportedActions()
|
||||
{
|
||||
return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
#ifndef SFTPCLIENT_H
|
||||
#define SFTPCLIENT_H
|
||||
|
||||
#include <libssh2.h>
|
||||
#include <libssh2_sftp.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "clients/remote_client.h"
|
||||
#include "common.h"
|
||||
|
||||
class SFTPClient : public RemoteClient
|
||||
{
|
||||
public:
|
||||
SFTPClient();
|
||||
~SFTPClient();
|
||||
int Connect(const std::string &url, const std::string &username, const std::string &password);
|
||||
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 GetRange(const std::string &path, void *buffer, 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);
|
||||
bool FileExists(const std::string &path);
|
||||
std::vector<DirEntry> ListDir(const std::string &path);
|
||||
std::string GetPath(std::string path1, std::string path2);
|
||||
bool IsConnected();
|
||||
bool Ping();
|
||||
const char *LastResponse();
|
||||
int Quit();
|
||||
ClientType clientType();
|
||||
uint32_t SupportedActions();
|
||||
|
||||
protected:
|
||||
LIBSSH2_SESSION *session;
|
||||
LIBSSH2_SFTP *sftp_session;
|
||||
int sock;
|
||||
char response[512];
|
||||
bool connected = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -12,12 +12,10 @@
|
||||
#include <orbis/Net.h>
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
#include "smbclient.h"
|
||||
#include "clients/smbclient.h"
|
||||
#include "windows.h"
|
||||
#include "util.h"
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
|
||||
SmbClient::SmbClient()
|
||||
{
|
||||
}
|
||||
@@ -228,6 +226,32 @@ int SmbClient::Get(const std::string &outputfile, const std::string &ppath, uint
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SmbClient::GetRange(const std::string &ppath, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
std::string path = std::string(ppath);
|
||||
path = Util::Trim(path, "/");
|
||||
int64_t filesize;
|
||||
if (!Size(path.c_str(), &filesize))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 count = smb2_read(smb2, in, (uint8_t*)buffer, size);
|
||||
smb2_close(smb2, in);
|
||||
if (count != size)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SmbClient::Copy(const std::string &ffrom, const std::string &tto)
|
||||
{
|
||||
sprintf(response, "%s", lang_strings[STR_UNSUPPORTED_OPERATION_MSG]);
|
||||
@@ -396,21 +420,7 @@ std::vector<DirEntry> SmbClient::ListDir(const std::string &path)
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path.length() > 1 && path[path.length() - 1] == '/')
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
struct smb2dir *dir;
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <vector>
|
||||
#include <smb2/smb2.h>
|
||||
#include <smb2/libsmb2.h>
|
||||
#include "clients/remote_client.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
#define SMB_CLIENT_MAX_FILENAME_LEN 256
|
||||
|
||||
@@ -23,6 +23,7 @@ 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 GetRange(const std::string &path, void *buffer, 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);
|
||||
@@ -9,12 +9,10 @@
|
||||
#include <fcntl.h>
|
||||
#include "lang.h"
|
||||
#include "webdav/client.hpp"
|
||||
#include "webdavclient.h"
|
||||
#include "clients/webdavclient.h"
|
||||
#include "windows.h"
|
||||
#include "util.h"
|
||||
#include "rtc.h"
|
||||
|
||||
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
|
||||
#include "system.h"
|
||||
|
||||
static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
||||
|
||||
@@ -202,6 +200,21 @@ namespace WebDAV
|
||||
return ret;
|
||||
}
|
||||
|
||||
int WebDavClient::GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset)
|
||||
{
|
||||
char *buffer_ptr = nullptr;
|
||||
unsigned long long buffer_size = 0;
|
||||
|
||||
bool ret = client->download_range_to(path, buffer_ptr, buffer_size, offset, offset+size-1);
|
||||
sprintf(response, "Http Code %ld", client->status_code());
|
||||
if (buffer_size != size)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
memcpy(buffer, buffer_ptr, size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Put - issue a PUT command and send data from input
|
||||
*
|
||||
@@ -256,21 +269,7 @@ namespace WebDAV
|
||||
{
|
||||
std::vector<DirEntry> out;
|
||||
DirEntry entry;
|
||||
memset(&entry, 0, sizeof(DirEntry));
|
||||
if (path.length() > 1 && path[path.length() - 1] == '/')
|
||||
{
|
||||
strlcpy(entry.directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry.directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry.name, "..");
|
||||
sprintf(entry.path, "%s", entry.directory);
|
||||
sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry.file_size = 0;
|
||||
entry.isDir = true;
|
||||
entry.selectable = false;
|
||||
Util::SetupPreviousFolder(path, &entry);
|
||||
out.push_back(entry);
|
||||
|
||||
WebDAV::dict_items_t files = client->list(path);
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include "webdav/client.hpp"
|
||||
#include "clients/remote_client.h"
|
||||
#include "common.h"
|
||||
#include "remote_client.h"
|
||||
|
||||
namespace WebDAV
|
||||
{
|
||||
@@ -28,6 +28,7 @@ namespace WebDAV
|
||||
int Rmdir(const std::string &path, bool recursive);
|
||||
int Size(const std::string &path, int64_t *size);
|
||||
int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0);
|
||||
int GetRange(const std::string &path, void *buffer, uint64_t size, uint64_t offset);
|
||||
int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0);
|
||||
int Rename(const std::string &src, const std::string &dst);
|
||||
int Delete(const std::string &path);
|
||||
@@ -5,6 +5,10 @@
|
||||
#include <vector>
|
||||
#include <string.h>
|
||||
|
||||
#define HTTP_SUCCESS(x) (x >= 200 && x < 300)
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t year;
|
||||
|
||||
+215
-58
@@ -1,12 +1,17 @@
|
||||
#include <orbis/UserService.h>
|
||||
#include <orbis/Net.h>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
#include <stdlib.h>
|
||||
#include "server/http_server.h"
|
||||
#include "config.h"
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
#include "crypt.h"
|
||||
#include "base64.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -23,14 +28,53 @@ char display_site[32];
|
||||
char language[128];
|
||||
std::vector<std::string> sites;
|
||||
std::vector<std::string> http_servers;
|
||||
std::set<std::string> text_file_extensions;
|
||||
std::set<std::string> image_file_extensions;
|
||||
std::map<std::string, RemoteSettings> site_settings;
|
||||
PackageUrlInfo install_pkg_url;
|
||||
char favorite_urls[MAX_FAVORITE_URLS][512];
|
||||
bool auto_delete_tmp_pkg;
|
||||
int max_edit_file_size;
|
||||
GoogleAppInfo gg_app;
|
||||
bool show_hidden_files;
|
||||
|
||||
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'};
|
||||
|
||||
RemoteClient *remoteclient;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
int Encrypt(const std::string &text, std::string &encrypt_text)
|
||||
{
|
||||
unsigned char tmp_encrypt_text[text.length() * 2];
|
||||
int encrypt_text_len;
|
||||
memset(tmp_encrypt_text, 0, sizeof(tmp_encrypt_text));
|
||||
int ret = openssl_encrypt((unsigned char *)text.c_str(), text.length(), cipher_key, cipher_iv, tmp_encrypt_text, &encrypt_text_len);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
return Base64::Encode(std::string((const char *)tmp_encrypt_text, encrypt_text_len), encrypt_text);
|
||||
}
|
||||
|
||||
int Decrypt(const std::string &text, std::string &decrypt_text)
|
||||
{
|
||||
std::string tmp_decode_text;
|
||||
int ret = Base64::Decode(text, tmp_decode_text);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
unsigned char tmp_decrypt_text[tmp_decode_text.length() * 2];
|
||||
int decrypt_text_len;
|
||||
memset(tmp_decrypt_text, 0, sizeof(tmp_decrypt_text));
|
||||
ret = openssl_decrypt((unsigned char *)tmp_decode_text.c_str(), tmp_decode_text.length(), cipher_key, cipher_iv, tmp_decrypt_text, &decrypt_text_len);
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
decrypt_text.clear();
|
||||
decrypt_text.append(std::string((const char *)tmp_decrypt_text, decrypt_text_len));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SetClientType(RemoteSettings *setting)
|
||||
{
|
||||
@@ -38,7 +82,7 @@ namespace CONFIG
|
||||
{
|
||||
setting->type = CLIENT_TYPE_SMB;
|
||||
}
|
||||
else if (strncmp(setting->server, "ftp://", 6) == 0)
|
||||
else if (strncmp(setting->server, "ftp://", 6) == 0 || strncmp(setting->server, "sftp://", 7) == 0)
|
||||
{
|
||||
setting->type = CLIENT_TYPE_FTP;
|
||||
}
|
||||
@@ -46,6 +90,10 @@ namespace CONFIG
|
||||
{
|
||||
setting->type = CLIENT_TYPE_WEBDAV;
|
||||
}
|
||||
else if (strncmp(setting->server, "https://drive.google.com", 24) == 0)
|
||||
{
|
||||
setting->type = CLIENT_TYPE_GOOGLE;
|
||||
}
|
||||
else if (strncmp(setting->server, "http://", 7) == 0 || strncmp(setting->server, "https://", 8) == 0)
|
||||
{
|
||||
setting->type = CLIENT_TYPE_HTTP_SERVER;
|
||||
@@ -56,8 +104,37 @@ namespace CONFIG
|
||||
}
|
||||
}
|
||||
|
||||
void LoadCipherKeys()
|
||||
{
|
||||
// Get the key and iv for encryption. Inject the account_id/MAC address as part of the key and iv.
|
||||
int user_id;
|
||||
uint64_t account_id = 0;
|
||||
sceUserServiceGetForegroundUser(&user_id);
|
||||
sceUserServiceGetNpAccountId(user_id, &account_id);
|
||||
unsigned char data[sizeof(account_id)];
|
||||
memcpy(data, &account_id, sizeof(account_id));
|
||||
OrbisNetEtherAddr addr;
|
||||
memset(&addr, 0x0, sizeof(OrbisNetEtherAddr));
|
||||
sceNetGetMacAddress(&addr, 0);
|
||||
for (int i = 0; i < sizeof(data); i++)
|
||||
{
|
||||
cipher_key[i] = data[i];
|
||||
cipher_key[i + 16] = data[i];
|
||||
cipher_iv[i] = data[i];
|
||||
}
|
||||
int offset = sizeof(data);
|
||||
for (int i = 0; i < sizeof(addr.data); i++)
|
||||
{
|
||||
cipher_key[offset + i] = addr.data[i];
|
||||
cipher_key[offset + i + 16] = data[i];
|
||||
cipher_iv[offset + i] = addr.data[i];
|
||||
}
|
||||
}
|
||||
|
||||
void LoadConfig()
|
||||
{
|
||||
LoadCipherKeys();
|
||||
|
||||
if (!FS::FolderExists(DATA_PATH))
|
||||
{
|
||||
FS::MkDirs(DATA_PATH);
|
||||
@@ -66,7 +143,9 @@ namespace CONFIG
|
||||
sites = {"Site 1", "Site 2", "Site 3", "Site 4", "Site 5", "Site 6", "Site 7", "Site 8", "Site 9", "Site 10",
|
||||
"Site 11", "Site 12", "Site 13", "Site 14", "Site 15", "Site 16", "Site 17", "Site 18", "Site 19", "Site 20"};
|
||||
|
||||
http_servers = { HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE};
|
||||
http_servers = {HTTP_SERVER_APACHE, HTTP_SERVER_MS_IIS, HTTP_SERVER_NGINX, HTTP_SERVER_NPX_SERVE};
|
||||
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
|
||||
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
|
||||
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
|
||||
@@ -85,19 +164,50 @@ namespace CONFIG
|
||||
sprintf(local_directory, "%s", ReadString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, "/"));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, local_directory);
|
||||
|
||||
sprintf(remote_directory, "%s", ReadString(CONFIG_GLOBAL, CONFIG_REMOTE_DIRECTORY, "/"));
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_REMOTE_DIRECTORY, remote_directory);
|
||||
|
||||
auto_delete_tmp_pkg = ReadBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, true);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
|
||||
|
||||
max_edit_file_size = ReadInt(CONFIG_GLOBAL, CONFIG_MAX_EDIT_FILE_SIZE, MAX_EDIT_FILE_SIZE);
|
||||
WriteInt(CONFIG_GLOBAL, CONFIG_MAX_EDIT_FILE_SIZE, max_edit_file_size);
|
||||
|
||||
show_hidden_files = ReadBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, false);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
|
||||
|
||||
// Load Google Account Info
|
||||
sprintf(gg_app.client_id, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, ""));
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
|
||||
|
||||
// Client Secret
|
||||
char tmp_gg_secret[512];
|
||||
sprintf(tmp_gg_secret, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, ""));
|
||||
std::string encrypted_secret;
|
||||
if (strlen(tmp_gg_secret) > 0)
|
||||
{
|
||||
std::string decrypted_secret;
|
||||
int ret = Decrypt(tmp_gg_secret, decrypted_secret);
|
||||
if (ret == 0)
|
||||
sprintf(gg_app.client_secret, "%s", tmp_gg_secret);
|
||||
else
|
||||
sprintf(gg_app.client_secret, "%s", decrypted_secret.c_str());
|
||||
Encrypt(gg_app.client_secret, encrypted_secret);
|
||||
}
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str());
|
||||
|
||||
sprintf(gg_app.permissions, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, GOOGLE_DEFAULT_PERMISSIONS));
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions);
|
||||
|
||||
// Http Server Info
|
||||
http_server_port = ReadInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, 8080);
|
||||
WriteInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, http_server_port);
|
||||
|
||||
for (int i = 0; i < sites.size(); i++)
|
||||
{
|
||||
RemoteSettings setting;
|
||||
memset(&setting, 0, sizeof(RemoteSettings));
|
||||
sprintf(setting.site_name, "%s", sites[i].c_str());
|
||||
|
||||
sprintf(setting.server, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_URL, ""));
|
||||
if (conversion_needed && strlen(setting.server)>0)
|
||||
if (conversion_needed && strlen(setting.server) > 0)
|
||||
{
|
||||
std::string tmp = std::string(setting.server);
|
||||
tmp = std::regex_replace(tmp, std::regex("http://"), "webdav://");
|
||||
@@ -109,8 +219,20 @@ namespace CONFIG
|
||||
sprintf(setting.username, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_USER, ""));
|
||||
WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_USER, setting.username);
|
||||
|
||||
sprintf(setting.password, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, ""));
|
||||
WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, setting.password);
|
||||
char tmp_password[128];
|
||||
sprintf(tmp_password, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, ""));
|
||||
std::string encrypted_password;
|
||||
if (strlen(tmp_password) > 0)
|
||||
{
|
||||
std::string decrypted_password;
|
||||
int ret = Decrypt(tmp_password, decrypted_password);
|
||||
if (ret == 0)
|
||||
sprintf(setting.password, "%s", tmp_password);
|
||||
else
|
||||
sprintf(setting.password, "%s", decrypted_password.c_str());
|
||||
Encrypt(setting.password, encrypted_password);
|
||||
}
|
||||
WriteString(sites[i].c_str(), CONFIG_REMOTE_SERVER_PASSWORD, encrypted_password.c_str());
|
||||
|
||||
setting.http_port = ReadInt(sites[i].c_str(), CONFIG_REMOTE_SERVER_HTTP_PORT, 80);
|
||||
WriteInt(sites[i].c_str(), CONFIG_REMOTE_SERVER_HTTP_PORT, setting.http_port);
|
||||
@@ -121,6 +243,43 @@ namespace CONFIG
|
||||
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);
|
||||
|
||||
sprintf(setting.default_directory, "%s", ReadString(sites[i].c_str(), CONFIG_REMOTE_DEFAULT_DIRECTORY, "/"));
|
||||
WriteString(sites[i].c_str(), CONFIG_REMOTE_DEFAULT_DIRECTORY, setting.default_directory);
|
||||
|
||||
// Token Expiry
|
||||
setting.gg_account.token_expiry = ReadLong(sites[i].c_str(), CONFIG_GOOGLE_TOKEN_EXPIRY, 0);
|
||||
WriteLong(sites[i].c_str(), CONFIG_GOOGLE_TOKEN_EXPIRY, setting.gg_account.token_expiry);
|
||||
|
||||
// Access Token
|
||||
sprintf(tmp_gg_secret, "%s", ReadString(sites[i].c_str(), CONFIG_GOOGLE_ACCESS_TOKEN, ""));
|
||||
std::string encrypted_token;
|
||||
if (strlen(tmp_gg_secret) > 0)
|
||||
{
|
||||
std::string decrypted_secret;
|
||||
int ret = Decrypt(tmp_gg_secret, decrypted_secret);
|
||||
if (ret == 0)
|
||||
sprintf(setting.gg_account.access_token, "%s", tmp_gg_secret);
|
||||
else
|
||||
sprintf(setting.gg_account.access_token, "%s", decrypted_secret.c_str());
|
||||
Encrypt(setting.gg_account.access_token, encrypted_token);
|
||||
}
|
||||
WriteString(sites[i].c_str(), CONFIG_GOOGLE_ACCESS_TOKEN, encrypted_token.c_str());
|
||||
|
||||
// Refresh Token
|
||||
sprintf(tmp_gg_secret, "%s", ReadString(sites[i].c_str(), CONFIG_GOOGLE_REFRESH_TOKEN, ""));
|
||||
std::string encrypted_refresh_token;
|
||||
if (strlen(tmp_gg_secret) > 0)
|
||||
{
|
||||
std::string decrypted_secret;
|
||||
int ret = Decrypt(tmp_gg_secret, decrypted_secret);
|
||||
if (ret == 0)
|
||||
sprintf(setting.gg_account.refresh_token, "%s", tmp_gg_secret);
|
||||
else
|
||||
sprintf(setting.gg_account.refresh_token, "%s", decrypted_secret.c_str());
|
||||
Encrypt(setting.gg_account.refresh_token, encrypted_refresh_token);
|
||||
}
|
||||
WriteString(sites[i].c_str(), CONFIG_GOOGLE_REFRESH_TOKEN, encrypted_refresh_token.c_str());
|
||||
|
||||
SetClientType(&setting);
|
||||
site_settings.insert(std::make_pair(sites[i], setting));
|
||||
}
|
||||
@@ -129,6 +288,7 @@ namespace CONFIG
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LAST_SITE, last_site);
|
||||
|
||||
remote_settings = &site_settings[std::string(last_site)];
|
||||
sprintf(remote_directory, "%s", remote_settings->default_directory);
|
||||
|
||||
for (int i = 0; i < MAX_FAVORITE_URLS; i++)
|
||||
{
|
||||
@@ -136,7 +296,6 @@ namespace CONFIG
|
||||
sprintf(favorite_urls[i], "%s", ReadString(CONFIG_FAVORITE_URLS, index, ""));
|
||||
WriteString(CONFIG_FAVORITE_URLS, index, favorite_urls[i]);
|
||||
}
|
||||
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
@@ -145,14 +304,60 @@ namespace CONFIG
|
||||
{
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
|
||||
std::string encrypted_text;
|
||||
if (strlen(remote_settings->password) > 0)
|
||||
Encrypt(remote_settings->password, encrypted_text);
|
||||
else
|
||||
encrypted_text = std::string(remote_settings->password);
|
||||
WriteString(last_site, CONFIG_REMOTE_SERVER_URL, remote_settings->server);
|
||||
WriteString(last_site, CONFIG_REMOTE_SERVER_USER, remote_settings->username);
|
||||
WriteString(last_site, CONFIG_REMOTE_SERVER_PASSWORD, remote_settings->password);
|
||||
WriteString(last_site, CONFIG_REMOTE_SERVER_PASSWORD, encrypted_text.c_str());
|
||||
WriteInt(last_site, CONFIG_REMOTE_SERVER_HTTP_PORT, remote_settings->http_port);
|
||||
WriteBool(last_site, CONFIG_ENABLE_RPI, remote_settings->enable_rpi);
|
||||
WriteString(last_site, CONFIG_REMOTE_HTTP_SERVER_TYPE, remote_settings->http_server_type);
|
||||
WriteString(last_site, CONFIG_REMOTE_DEFAULT_DIRECTORY, remote_settings->default_directory);
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LAST_SITE, last_site);
|
||||
|
||||
std::string encrypted_token;
|
||||
if (strlen(remote_settings->gg_account.access_token) > 0)
|
||||
Encrypt(remote_settings->gg_account.access_token, encrypted_token);
|
||||
else
|
||||
encrypted_token = std::string(remote_settings->gg_account.access_token);
|
||||
WriteString(last_site, CONFIG_GOOGLE_ACCESS_TOKEN, encrypted_token.c_str());
|
||||
|
||||
std::string encrypted_refresh_token;
|
||||
if (strlen(remote_settings->gg_account.refresh_token) > 0)
|
||||
Encrypt(remote_settings->gg_account.refresh_token, encrypted_refresh_token);
|
||||
else
|
||||
encrypted_refresh_token = std::string(remote_settings->gg_account.refresh_token);
|
||||
WriteString(last_site, CONFIG_GOOGLE_REFRESH_TOKEN, encrypted_refresh_token.c_str());
|
||||
WriteLong(last_site, CONFIG_GOOGLE_TOKEN_EXPIRY, remote_settings->gg_account.token_expiry);
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
|
||||
void SaveGlobalConfig()
|
||||
{
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
|
||||
std::string encrypted_secret;
|
||||
if (strlen(gg_app.client_secret) > 0)
|
||||
Encrypt(gg_app.client_secret, encrypted_secret);
|
||||
else
|
||||
encrypted_secret = std::string(gg_app.client_secret);
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str());
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id);
|
||||
WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_SHOW_HIDDEN_FILES, show_hidden_files);
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
|
||||
void SaveLocalDirecotry(const std::string &path)
|
||||
{
|
||||
OpenIniFile(CONFIG_INI_FILE);
|
||||
WriteString(CONFIG_GLOBAL, CONFIG_LOCAL_DIRECTORY, path.c_str());
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
@@ -165,52 +370,4 @@ namespace CONFIG
|
||||
WriteIniFile(CONFIG_INI_FILE);
|
||||
CloseIniFile();
|
||||
}
|
||||
|
||||
void ParseMultiValueString(const char *prefix_list, std::vector<std::string> &prefixes, bool toLower)
|
||||
{
|
||||
std::string prefix = "";
|
||||
int length = strlen(prefix_list);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
char c = prefix_list[i];
|
||||
if (c != ' ' && c != '\t' && c != ',')
|
||||
{
|
||||
if (toLower)
|
||||
{
|
||||
prefix += std::tolower(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
prefix += c;
|
||||
}
|
||||
}
|
||||
|
||||
if (c == ',' || i == length - 1)
|
||||
{
|
||||
prefixes.push_back(prefix);
|
||||
prefix = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetMultiValueString(std::vector<std::string> &multi_values)
|
||||
{
|
||||
std::string vts = std::string("");
|
||||
if (multi_values.size() > 0)
|
||||
{
|
||||
for (int i = 0; i < multi_values.size() - 1; i++)
|
||||
{
|
||||
vts.append(multi_values[i]).append(",");
|
||||
}
|
||||
vts.append(multi_values[multi_values.size() - 1]);
|
||||
}
|
||||
return vts;
|
||||
}
|
||||
|
||||
void RemoveFromMultiValues(std::vector<std::string> &multi_values, std::string value)
|
||||
{
|
||||
auto itr = std::find(multi_values.begin(), multi_values.end(), value);
|
||||
if (itr != multi_values.end())
|
||||
multi_values.erase(itr);
|
||||
}
|
||||
}
|
||||
|
||||
+61
-6
@@ -3,18 +3,48 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "remote_client.h"
|
||||
#include "clients/remote_client.h"
|
||||
|
||||
#define APP_ID "ezremote-client"
|
||||
#define DATA_PATH "/data/" APP_ID
|
||||
#define CONFIG_INI_FILE DATA_PATH "/config.ini"
|
||||
#define COOKIE_FILE DATA_PATH "/cookies.txt"
|
||||
#define TMP_EDITOR_FILE DATA_PATH "/tmp_editor.txt"
|
||||
#define TMP_SFO_PATH DATA_PATH "/tmp_pkg.sfo"
|
||||
#define TMP_ICON_PATH DATA_PATH "/tmp_icon.png"
|
||||
|
||||
#define CONFIG_GLOBAL "Global"
|
||||
|
||||
#define CONFIG_SHOW_HIDDEN_FILES "show_hidden_files"
|
||||
|
||||
#define CONFIG_GOOGLE "Google"
|
||||
#define CONFIG_GOOGLE_CLIENT_ID "google_client_id"
|
||||
#define CONFIG_GOOGLE_CLIENT_SECRET "google_client_secret"
|
||||
#define CONFIG_GOOGLE_PERMISSIONS "google_client_permissions"
|
||||
#define CONFIG_GOOGLE_ACCESS_TOKEN "google_access_token"
|
||||
#define CONFIG_GOOGLE_REFRESH_TOKEN "google_refresh_token"
|
||||
#define CONFIG_GOOGLE_TOKEN_EXPIRY "google_token_expiry"
|
||||
|
||||
#define GOOGLE_OAUTH_HOST "https://oauth2.googleapis.com"
|
||||
#define GOOGLE_AUTH_URL "https://accounts.google.com/o/oauth2/v2/auth"
|
||||
#define GOOGLE_API_URL "https://www.googleapis.com"
|
||||
#define GOOGLE_DRIVE_API_PATH "/drive/v2/files"
|
||||
#define GOOGLE_DRIVE_BASE_URL "https://drive.google.com"
|
||||
#define GOOGLE_PERM_DRIVE "drive"
|
||||
#define GOOGLE_PERM_DRIVE_APPDATA "drive.appdata"
|
||||
#define GOOGLE_PERM_DRIVE_FILE "drive.file"
|
||||
#define GOOGLE_PERM_DRIVE_METADATA "drive.metadata"
|
||||
#define GOOGLE_PERM_DRIVE_METADATA_RO "drive.metadata.readonly"
|
||||
#define GOOGLE_DEFAULT_PERMISSIONS GOOGLE_PERM_DRIVE
|
||||
|
||||
#define CONFIG_HTTP_SERVER "HttpServer"
|
||||
#define CONFIG_HTTP_SERVER_PORT "http_server_port"
|
||||
|
||||
#define CONFIG_REMOTE_SERVER_NAME "remote_server_name"
|
||||
#define CONFIG_REMOTE_SERVER_URL "remote_server_url"
|
||||
#define CONFIG_REMOTE_SERVER_USER "remote_server_user"
|
||||
@@ -22,18 +52,19 @@
|
||||
#define CONFIG_REMOTE_SERVER_HTTP_PORT "remote_server_http_port"
|
||||
#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_VERSION "config_version"
|
||||
#define CONFIG_VERSION_NUM 1
|
||||
|
||||
#define CONFIG_FAVORITE_URLS "favorite_urls"
|
||||
#define MAX_FAVORITE_URLS 30
|
||||
#define CONFIG_MAX_EDIT_FILE_SIZE "max_edit_file_size"
|
||||
|
||||
#define CONFIG_LAST_SITE "last_site"
|
||||
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
|
||||
|
||||
#define CONFIG_LOCAL_DIRECTORY "local_directory"
|
||||
#define CONFIG_REMOTE_DIRECTORY "remote_directory"
|
||||
|
||||
#define CONFIG_LANGUAGE "language"
|
||||
|
||||
@@ -42,17 +73,35 @@
|
||||
#define HTTP_SERVER_NGINX "Nginx"
|
||||
#define HTTP_SERVER_NPX_SERVE "Serve"
|
||||
|
||||
#define MAX_EDIT_FILE_SIZE 32768
|
||||
|
||||
struct GoogleAccountInfo
|
||||
{
|
||||
char access_token[256];
|
||||
char refresh_token[256];
|
||||
uint64_t token_expiry;
|
||||
};
|
||||
|
||||
struct GoogleAppInfo
|
||||
{
|
||||
char client_id[140];
|
||||
char client_secret[64];
|
||||
char permissions[92];
|
||||
};
|
||||
|
||||
struct RemoteSettings
|
||||
{
|
||||
char site_name[32];
|
||||
char server[256];
|
||||
char username[33];
|
||||
char password[25];
|
||||
char password[128];
|
||||
int http_port;
|
||||
ClientType type;
|
||||
bool enable_rpi;
|
||||
uint32_t supported_actions;
|
||||
char http_server_type[24];
|
||||
GoogleAccountInfo gg_account;
|
||||
char default_directory[256];
|
||||
};
|
||||
|
||||
struct PackageUrlInfo
|
||||
@@ -64,6 +113,8 @@ struct PackageUrlInfo
|
||||
|
||||
extern std::vector<std::string> sites;
|
||||
extern std::vector<std::string> http_servers;
|
||||
extern std::set<std::string> text_file_extensions;
|
||||
extern std::set<std::string> image_file_extensions;
|
||||
extern std::map<std::string, RemoteSettings> site_settings;
|
||||
extern char local_directory[255];
|
||||
extern char remote_directory[255];
|
||||
@@ -76,15 +127,19 @@ extern RemoteClient *remoteclient;
|
||||
extern PackageUrlInfo install_pkg_url;
|
||||
extern char favorite_urls[MAX_FAVORITE_URLS][512];
|
||||
extern bool auto_delete_tmp_pkg;
|
||||
extern int max_edit_file_size;
|
||||
extern unsigned char cipher_key[32];
|
||||
extern unsigned char cipher_iv[16];
|
||||
extern GoogleAppInfo gg_app;
|
||||
extern bool show_hidden_files;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
void LoadConfig();
|
||||
void SaveConfig();
|
||||
void SaveGlobalConfig();
|
||||
void SaveLocalDirecotry(const std::string &path);
|
||||
void SaveFavoriteUrl(int index, char *url);
|
||||
void SetClientType(RemoteSettings *settings);
|
||||
void RemoveFromMultiValues(std::vector<std::string> &multi_values, std::string value);
|
||||
void ParseMultiValueString(const char *prefix_list, std::vector<std::string> &prefixes, bool toLower);
|
||||
std::string GetMultiValueString(std::vector<std::string> &multi_values);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "crypt.h"
|
||||
|
||||
int openssl_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *ciphertext, int *ciphertext_len)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
int len;
|
||||
|
||||
/* Create and initialise the context */
|
||||
if (!(ctx = EVP_CIPHER_CTX_new()))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Initialise the encryption operation. IMPORTANT - ensure you use a key
|
||||
* and IV size appropriate for your cipher
|
||||
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
|
||||
* IV size for *most* modes is the same as the block size. For AES this
|
||||
* is 128 bits
|
||||
*/
|
||||
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Provide the message to be encrypted, and obtain the encrypted output.
|
||||
* EVP_EncryptUpdate can be called multiple times if necessary
|
||||
*/
|
||||
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
|
||||
return 0;
|
||||
*ciphertext_len = len;
|
||||
|
||||
/*
|
||||
* Finalise the encryption. Further ciphertext bytes may be written at
|
||||
* this stage.
|
||||
*/
|
||||
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
|
||||
return 0;
|
||||
*ciphertext_len += len;
|
||||
|
||||
/* Clean up */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int openssl_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *plaintext, int *plaintext_len)
|
||||
{
|
||||
EVP_CIPHER_CTX *ctx;
|
||||
|
||||
int len;
|
||||
|
||||
/* Create and initialise the context */
|
||||
if (!(ctx = EVP_CIPHER_CTX_new()))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Initialise the decryption operation. IMPORTANT - ensure you use a key
|
||||
* and IV size appropriate for your cipher
|
||||
* In this example we are using 256 bit AES (i.e. a 256 bit key). The
|
||||
* IV size for *most* modes is the same as the block size. For AES this
|
||||
* is 128 bits
|
||||
*/
|
||||
if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Provide the message to be decrypted, and obtain the plaintext output.
|
||||
* EVP_DecryptUpdate can be called multiple times if necessary.
|
||||
*/
|
||||
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
|
||||
return 0;
|
||||
*plaintext_len = len;
|
||||
|
||||
/*
|
||||
* Finalise the decryption. Further plaintext bytes may be written at
|
||||
* this stage.
|
||||
*/
|
||||
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
|
||||
return 0;
|
||||
*plaintext_len += len;
|
||||
|
||||
/* Clean up */
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int openssl_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *ciphertext, int *ciphertext_len);
|
||||
|
||||
int openssl_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
||||
unsigned char *iv, unsigned char *plaintext, int *plaintext_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+66
-8
@@ -11,7 +11,7 @@
|
||||
|
||||
#include "util.h"
|
||||
#include "lang.h"
|
||||
#include "rtc.h"
|
||||
#include "system.h"
|
||||
#include "windows.h"
|
||||
|
||||
namespace FS
|
||||
@@ -131,25 +131,83 @@ namespace FS
|
||||
|
||||
std::vector<char> Load(const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "r");
|
||||
FILE *fd = fopen(path.c_str(), "rb");
|
||||
if (fd == nullptr)
|
||||
return std::vector<char>(0);
|
||||
|
||||
const auto size = fseek(fd, 0, SEEK_END);
|
||||
fseek(fd, 0, SEEK_SET);
|
||||
|
||||
const auto size = GetSize(path);
|
||||
std::vector<char> data(size);
|
||||
|
||||
const auto read = fread(data.data(), data.size(), 1, fd);
|
||||
const auto read = fread(data.data(), 1, data.size(), fd);
|
||||
fclose(fd);
|
||||
if (read < 0)
|
||||
return std::vector<char>(0);
|
||||
|
||||
data.resize(read);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
bool LoadText(std::vector<std::string> *lines, const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "rb");
|
||||
if (fd == nullptr)
|
||||
return false;
|
||||
|
||||
lines->clear();
|
||||
|
||||
char buffer[1024];
|
||||
short bytes_read;
|
||||
std::vector<char> line = std::vector<char>(0);
|
||||
do
|
||||
{
|
||||
bytes_read = fread(buffer, sizeof(char), 1024, fd);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
fclose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (short i = 0; i < bytes_read; i++)
|
||||
{
|
||||
if (buffer[i] != '\r' && buffer[i] != '\n')
|
||||
{
|
||||
line.push_back(buffer[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
lines->push_back(std::string(line.data(), line.size()));
|
||||
line = std::vector<char>(0);
|
||||
if (buffer[i] == '\r' && buffer[i+1] == '\n')
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} while (bytes_read == 1024);
|
||||
if (line.size()>0)
|
||||
lines->push_back(std::string(line.data(), line.size()));
|
||||
|
||||
fclose(fd);
|
||||
if (lines->size() == 0)
|
||||
lines->push_back("");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveText(std::vector<std::string> *lines, const std::string &path)
|
||||
{
|
||||
FILE *fd = OpenRW(path);
|
||||
if (fd == nullptr)
|
||||
return false;
|
||||
|
||||
char nl[1] = {'\n'};
|
||||
for (int i=0; i < lines->size(); i++)
|
||||
{
|
||||
Write(fd, lines->at(i).c_str(), lines->at(i).length());
|
||||
Write(fd, nl, 1);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Save(const std::string &path, const void *data, uint32_t size)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "w+");
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace FS
|
||||
int Write(FILE *f, const void *buffer, uint32_t size);
|
||||
|
||||
std::vector<char> Load(const std::string &path);
|
||||
bool LoadText(std::vector<std::string> *lines, const std::string &path);
|
||||
bool SaveText(std::vector<std::string> *lines, const std::string &path);
|
||||
|
||||
void Save(const std::string &path, const void *data, uint32_t size);
|
||||
|
||||
std::vector<std::string> ListFiles(const std::string &path);
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ namespace GUI
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
}
|
||||
|
||||
GImGui->GcCompactAll = true;
|
||||
ImGui_ImplSDLRenderer_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
@@ -932,6 +932,10 @@ socket_t create_client_socket(
|
||||
tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
|
||||
setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv));
|
||||
#endif
|
||||
|
||||
int const size = 1048576;
|
||||
setsockopt(sock2, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||
setsockopt(sock2, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||
}
|
||||
|
||||
error = Error::Success;
|
||||
|
||||
@@ -1637,6 +1637,9 @@ inline void default_socket_options(socket_t sock) {
|
||||
sizeof(yes));
|
||||
#endif
|
||||
#endif
|
||||
int const size = 1048576;
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
|
||||
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#include "ime_dialog.h"
|
||||
|
||||
static int ime_dialog_running = 0;
|
||||
static uint16_t inputTextBuffer[512+1];
|
||||
static uint8_t storebuffer[512];
|
||||
static char initial_ime_text[512];
|
||||
static uint16_t inputTextBuffer[1024+1];
|
||||
static uint8_t storebuffer[1024];
|
||||
static char initial_ime_text[1024];
|
||||
static int max_text_length;
|
||||
|
||||
static void utf16_to_utf8(const uint16_t *src, uint8_t *dst)
|
||||
@@ -83,7 +83,7 @@ namespace Dialog
|
||||
|
||||
uint16_t title[100];
|
||||
|
||||
if ((initialTextBuffer && strlen(initialTextBuffer) > 511) || (Title && strlen(Title) > 99))
|
||||
if ((initialTextBuffer && strlen(initialTextBuffer) > 1023) || (Title && strlen(Title) > 99))
|
||||
{
|
||||
ime_dialog_running = 0;
|
||||
return -1;
|
||||
@@ -95,7 +95,7 @@ namespace Dialog
|
||||
|
||||
if (initialTextBuffer)
|
||||
{
|
||||
snprintf(initial_ime_text, 511, "%s", initialTextBuffer);
|
||||
snprintf(initial_ime_text, 1023, "%s", initialTextBuffer);
|
||||
}
|
||||
|
||||
// converts the multibyte string src to a wide-character string starting at dest.
|
||||
|
||||
@@ -1200,7 +1200,7 @@ typedef ImBitArray<ImGuiKey_NamedKey_COUNT, -ImGuiKey_NamedKey_BEGIN> ImBitAr
|
||||
#define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1
|
||||
#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown
|
||||
#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight
|
||||
#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft
|
||||
#define ImGuiKey_NavGamepadMenu ImGuiKey_Keypad0
|
||||
#define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp
|
||||
|
||||
enum ImGuiInputEventType
|
||||
+34
-13
@@ -52,7 +52,7 @@
|
||||
|
||||
------------------------------------------------------------------------
|
||||
Copyright (c) 2000 Carsten Breuer
|
||||
/************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
/* defines for, or consts and inline functions for C++ */
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
struct ENTRY *Entry = NULL;
|
||||
struct ENTRY *CurEntry = NULL;
|
||||
char Result[4096] =
|
||||
char Result[520] =
|
||||
{""};
|
||||
FILE *IniFile;
|
||||
|
||||
@@ -84,7 +84,7 @@ struct ENTRY *MakeNewEntry(void);
|
||||
strupr -de-
|
||||
-------------------------------------------------------------------------
|
||||
Job : String to Uppercase 22.03.2001 Dieter Engelbrecht dieter@wintop.net
|
||||
/*========================================================================*/
|
||||
*========================================================================*/
|
||||
#ifdef DONT_HAVE_STRUPR
|
||||
/* DONT_HAVE_STRUPR is set when INI_REMOVE_CR is defined */
|
||||
void strupr(char *str)
|
||||
@@ -99,6 +99,7 @@ void strupr(char *str)
|
||||
str++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
|
||||
/*=========================================================================
|
||||
@@ -109,10 +110,10 @@ void strupr(char *str)
|
||||
|
||||
Att : Be sure to call CloseIniFile to free all mem allocated during
|
||||
operation!
|
||||
/*========================================================================*/
|
||||
*========================================================================*/
|
||||
bool OpenIniFile(cchr *FileName)
|
||||
{
|
||||
char Str[5120];
|
||||
char Str[512];
|
||||
char *pStr;
|
||||
struct ENTRY *pEntry;
|
||||
|
||||
@@ -127,7 +128,7 @@ bool OpenIniFile(cchr *FileName)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (fgets(Str, 5120, IniFile) != NULL)
|
||||
while (fgets(Str, 512, IniFile) != NULL)
|
||||
{
|
||||
pStr = strchr(Str, '\n');
|
||||
if (pStr != NULL)
|
||||
@@ -191,7 +192,7 @@ bool OpenIniFile(cchr *FileName)
|
||||
Job : Frees the memory and closes the ini file without any
|
||||
modifications. If you want to write the file use
|
||||
WriteIniFile instead.
|
||||
/*========================================================================*/
|
||||
*========================================================================*/
|
||||
void CloseIniFile(void)
|
||||
{
|
||||
FreeAllMem();
|
||||
@@ -207,7 +208,7 @@ void CloseIniFile(void)
|
||||
-------------------------------------------------------------------------
|
||||
Job : Writes the iniFile to the disk and close it. Frees all memory
|
||||
allocated by WriteIniFile;
|
||||
/*========================================================================*/
|
||||
==========================================================================*/
|
||||
bool WriteIniFile(const char *FileName)
|
||||
{
|
||||
struct ENTRY *pEntry = Entry;
|
||||
@@ -242,7 +243,7 @@ bool WriteIniFile(const char *FileName)
|
||||
void WriteString(cchr *Section, cchr *pKey, cchr *Value)
|
||||
{
|
||||
EFIND List;
|
||||
char Str[5120];
|
||||
char Str[512];
|
||||
|
||||
if (ArePtrValid(Section, pKey, Value) == FALSE)
|
||||
{
|
||||
@@ -291,6 +292,16 @@ void WriteInt(cchr *Section, cchr *pKey, int Value)
|
||||
WriteString(Section, pKey, Val);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteLong : Writes an long to the ini file
|
||||
*========================================================================*/
|
||||
void WriteLong(cchr *Section, cchr *pKey, long Value)
|
||||
{
|
||||
char Val[22]; /* 64bit maximum + sign + \0 */
|
||||
sprintf(Val, "%ld", Value);
|
||||
WriteString(Section, pKey, Val);
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
WriteDouble : Writes a double to the ini file
|
||||
*========================================================================*/
|
||||
@@ -343,6 +354,16 @@ int ReadInt(cchr *Section, cchr *pKey, int Default)
|
||||
return (atoi(ReadString(Section, pKey, Val)));
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
ReadLong : Reads a long from the ini file
|
||||
*========================================================================*/
|
||||
long ReadLong(cchr *Section, cchr *pKey, long Default)
|
||||
{
|
||||
char Val[22];
|
||||
sprintf(Val, "%ld", Default);
|
||||
return (atol(ReadString(Section, pKey, Val)));
|
||||
}
|
||||
|
||||
/*=========================================================================
|
||||
ReadDouble : Reads a double from the ini file
|
||||
*========================================================================*/
|
||||
@@ -463,7 +484,7 @@ bool FindpKey(cchr *Section, cchr *pKey, EFIND *List)
|
||||
{
|
||||
char Search[130];
|
||||
char Found[130];
|
||||
char Text[5120];
|
||||
char Text[512];
|
||||
char *pText;
|
||||
struct ENTRY *pEntry;
|
||||
List->pSec = NULL;
|
||||
@@ -595,7 +616,7 @@ bool AddItemAt(struct ENTRY *EntryAt, char Mode, cchr *Text)
|
||||
*========================================================================*/
|
||||
bool AddSectionAndpKey(cchr *Section, cchr *pKey, cchr *Value)
|
||||
{
|
||||
char Text[5120];
|
||||
char Text[512];
|
||||
sprintf(Text, "[%s]", Section);
|
||||
if (AddItem(tpSECTION, Text) == FALSE)
|
||||
{
|
||||
@@ -610,7 +631,7 @@ bool AddSectionAndpKey(cchr *Section, cchr *pKey, cchr *Value)
|
||||
*========================================================================*/
|
||||
void AddpKey(struct ENTRY *SecEntry, cchr *pKey, cchr *Value)
|
||||
{
|
||||
char Text[5120];
|
||||
char Text[512];
|
||||
sprintf(Text, "%s=%s", pKey, Value);
|
||||
AddItemAt(SecEntry, tpKEYVALUE, Text);
|
||||
}
|
||||
@@ -678,7 +699,7 @@ void GetSections(char *sections[])
|
||||
{
|
||||
if (pEntry->Type == tpSECTION)
|
||||
{
|
||||
sprintf(sections[i], pEntry->Text);
|
||||
sprintf(sections[i], "%s", pEntry->Text);
|
||||
i++;
|
||||
}
|
||||
pEntry = pEntry->pNext;
|
||||
|
||||
+3
-1
@@ -5,7 +5,7 @@
|
||||
Author(s) : Carsten Breuer
|
||||
------------------------------------------------------------------------
|
||||
Copyright (c) 2000 by Carsten Breuer (C.Breuer@openwin.de)
|
||||
/************************************************************************/
|
||||
************************************************************************/
|
||||
|
||||
#ifndef INIFILE_H
|
||||
#define INIFILE_H
|
||||
@@ -54,11 +54,13 @@ bool OpenIniFile(cchr *FileName);
|
||||
|
||||
bool ReadBool(cchr *Section, cchr *Key, bool Default);
|
||||
int ReadInt(cchr *Section, cchr *Key, int Default);
|
||||
long ReadLong(cchr *Section, cchr *Key, long Default);
|
||||
double ReadDouble(cchr *Section, cchr *Key, double Default);
|
||||
cchr *ReadString(cchr *Section, cchr *Key, cchr *Default);
|
||||
|
||||
void WriteBool(cchr *Section, cchr *Key, bool Value);
|
||||
void WriteInt(cchr *Section, cchr *Key, int Value);
|
||||
void WriteLong(cchr *Section, cchr *Key, long Value);
|
||||
void WriteDouble(cchr *Section, cchr *Key, double Value);
|
||||
void WriteString(cchr *Section, cchr *Key, cchr *Value);
|
||||
|
||||
|
||||
+174
-13
@@ -17,9 +17,9 @@
|
||||
#include "config.h"
|
||||
#include "windows.h"
|
||||
#include "lang.h"
|
||||
#include "rtc.h"
|
||||
#include "system.h"
|
||||
#include "fs.h"
|
||||
#include "webdavclient.h"
|
||||
#include "clients/webdavclient.h"
|
||||
|
||||
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace INSTALLER
|
||||
s_bgft_initialized = false;
|
||||
}
|
||||
|
||||
std::string getRemoteUrl(const std::string filename)
|
||||
std::string getRemoteUrl(const std::string filename, bool encodeUrl)
|
||||
{
|
||||
if (remoteclient->clientType() == CLIENT_TYPE_WEBDAV || remoteclient->clientType() == CLIENT_TYPE_HTTP_SERVER)
|
||||
{
|
||||
@@ -109,10 +109,13 @@ namespace INSTALLER
|
||||
std::string host = full_url.substr(0, root_pos);
|
||||
std::string path = full_url.substr(root_pos);
|
||||
|
||||
Web::Urn::Path uri(path);
|
||||
CURL *curl = curl_easy_init();
|
||||
path = uri.quote(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
if (encodeUrl)
|
||||
{
|
||||
Web::Urn::Path uri(path);
|
||||
CURL *curl = curl_easy_init();
|
||||
path = uri.quote(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
return host + path;
|
||||
}
|
||||
@@ -129,9 +132,12 @@ namespace INSTALLER
|
||||
host = host.substr(0, port_pos);
|
||||
|
||||
std::string path = std::string(filename);
|
||||
Web::Urn::Path uri(path);
|
||||
CURL *curl = curl_easy_init();
|
||||
path = uri.quote(curl);
|
||||
if (encodeUrl)
|
||||
{
|
||||
Web::Urn::Path uri(path);
|
||||
CURL *curl = curl_easy_init();
|
||||
path = uri.quote(curl);
|
||||
}
|
||||
return "http://" + host + ":" + std::to_string(remote_settings->http_port) + path;
|
||||
}
|
||||
|
||||
@@ -161,6 +167,7 @@ namespace INSTALLER
|
||||
tmp_client.Connect(host.c_str(), "", "", false);
|
||||
WebDAV::dict_t response_headers{};
|
||||
int ret = tmp_client.GetHeaders(path.c_str(), &response_headers);
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
sprintf(confirm_message, "%s %s", lang_strings[STR_CANNOT_CONNECT_REMOTE_MSG], lang_strings[STR_DOWNLOAD_INSTALL_MSG]);
|
||||
@@ -173,7 +180,7 @@ namespace INSTALLER
|
||||
|
||||
int InstallRemotePkg(const std::string &filename, pkg_header *header)
|
||||
{
|
||||
std::string url = getRemoteUrl(filename);
|
||||
std::string url = getRemoteUrl(filename, true);
|
||||
if (url.empty())
|
||||
return 0;
|
||||
|
||||
@@ -258,7 +265,8 @@ namespace INSTALLER
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
else if (ret > 0) goto err;
|
||||
else if (ret > 0)
|
||||
goto err;
|
||||
|
||||
ret = sceBgftServiceDownloadStartTask(task_id);
|
||||
if (ret)
|
||||
@@ -333,8 +341,14 @@ namespace INSTALLER
|
||||
goto err;
|
||||
goto retry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (auto_delete_tmp_pkg)
|
||||
FS::Rm(filename);
|
||||
}
|
||||
}
|
||||
else if (ret > 0) goto err;
|
||||
else if (ret > 0)
|
||||
goto err;
|
||||
|
||||
ret = sceBgftServiceDownloadStartTask(task_id);
|
||||
if (ret)
|
||||
@@ -368,4 +382,151 @@ namespace INSTALLER
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ExtractLocalPkg(const std::string &filename, const std::string sfo_path, const std::string icon_path)
|
||||
{
|
||||
pkg_header tmp_hdr;
|
||||
FS::Head(filename, &tmp_hdr, sizeof(pkg_header));
|
||||
|
||||
size_t entry_count = BE32(tmp_hdr.pkg_entry_count);
|
||||
uint32_t entry_table_offset = BE32(tmp_hdr.pkg_table_offset);
|
||||
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
|
||||
void *entry_table_data = malloc(entry_table_size);
|
||||
|
||||
FILE *fd = FS::OpenRead(filename);
|
||||
FS::Seek(fd, entry_table_offset);
|
||||
FS::Read(fd, entry_table_data, entry_table_size);
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = NULL;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
void *icon0_png_data = NULL;
|
||||
uint32_t icon0_png_offset = 0;
|
||||
uint32_t icon0_png_size = 0;
|
||||
short items = 0;
|
||||
for (size_t i = 0; i < entry_count; ++i)
|
||||
{
|
||||
switch (BE32(entries[i].id))
|
||||
{
|
||||
case PKG_ENTRY_ID__PARAM_SFO:
|
||||
param_sfo_offset = BE32(entries[i].offset);
|
||||
param_sfo_size = BE32(entries[i].size);
|
||||
items++;
|
||||
break;
|
||||
case PKG_ENTRY_ID__ICON0_PNG:
|
||||
icon0_png_offset = BE32(entries[i].offset);
|
||||
icon0_png_size = BE32(entries[i].size);
|
||||
items++;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (items == 2)
|
||||
break;
|
||||
}
|
||||
free(entry_table_data);
|
||||
|
||||
if (param_sfo_offset > 0 && param_sfo_size > 0)
|
||||
{
|
||||
param_sfo_data = malloc(param_sfo_size);
|
||||
FILE *out = FS::Create(sfo_path);
|
||||
FS::Seek(fd, param_sfo_offset);
|
||||
FS::Read(fd, param_sfo_data, param_sfo_size);
|
||||
FS::Write(out, param_sfo_data, param_sfo_size);
|
||||
FS::Close(out);
|
||||
free(param_sfo_data);
|
||||
}
|
||||
|
||||
if (icon0_png_offset > 0 && icon0_png_size > 0)
|
||||
{
|
||||
icon0_png_data = malloc(icon0_png_size);
|
||||
FILE *out = FS::Create(icon_path);
|
||||
FS::Seek(fd, icon0_png_offset);
|
||||
FS::Read(fd, icon0_png_data, icon0_png_size);
|
||||
FS::Write(out, icon0_png_data, icon0_png_size);
|
||||
FS::Close(out);
|
||||
free(icon0_png_data);
|
||||
}
|
||||
|
||||
FS::Close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractRemotePkg(const std::string &filename, const std::string sfo_path, const std::string icon_path)
|
||||
{
|
||||
pkg_header tmp_hdr;
|
||||
if (!remoteclient->Head(filename, &tmp_hdr, sizeof(pkg_header)))
|
||||
return false;
|
||||
|
||||
size_t entry_count = BE32(tmp_hdr.pkg_entry_count);
|
||||
uint32_t entry_table_offset = BE32(tmp_hdr.pkg_table_offset);
|
||||
uint64_t entry_table_size = entry_count * sizeof(pkg_table_entry);
|
||||
void *entry_table_data = malloc(entry_table_size);
|
||||
|
||||
if (!remoteclient->GetRange(filename, entry_table_data, entry_table_size, entry_table_offset))
|
||||
return false;
|
||||
|
||||
pkg_table_entry *entries = (pkg_table_entry *)entry_table_data;
|
||||
void* param_sfo_data = NULL;
|
||||
uint32_t param_sfo_offset = 0;
|
||||
uint32_t param_sfo_size = 0;
|
||||
void *icon0_png_data = NULL;
|
||||
uint32_t icon0_png_offset = 0;
|
||||
uint32_t icon0_png_size = 0;
|
||||
short items = 0;
|
||||
for (size_t i = 0; i < entry_count; ++i)
|
||||
{
|
||||
switch (BE32(entries[i].id))
|
||||
{
|
||||
case PKG_ENTRY_ID__PARAM_SFO:
|
||||
param_sfo_offset = BE32(entries[i].offset);
|
||||
param_sfo_size = BE32(entries[i].size);
|
||||
items++;
|
||||
break;
|
||||
case PKG_ENTRY_ID__ICON0_PNG:
|
||||
icon0_png_offset = BE32(entries[i].offset);
|
||||
icon0_png_size = BE32(entries[i].size);
|
||||
items++;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (items == 2)
|
||||
break;
|
||||
}
|
||||
free(entry_table_data);
|
||||
|
||||
if (param_sfo_offset > 0 && param_sfo_size > 0)
|
||||
{
|
||||
param_sfo_data = malloc(param_sfo_size);
|
||||
FILE *out = FS::Create(sfo_path);
|
||||
if (!remoteclient->GetRange(filename, param_sfo_data, param_sfo_size, param_sfo_offset))
|
||||
{
|
||||
FS::Close(out);
|
||||
return false;
|
||||
}
|
||||
FS::Write(out, param_sfo_data, param_sfo_size);
|
||||
FS::Close(out);
|
||||
free(param_sfo_data);
|
||||
}
|
||||
|
||||
if (icon0_png_offset > 0 && icon0_png_size > 0)
|
||||
{
|
||||
icon0_png_data = malloc(icon0_png_size);
|
||||
FILE *out = FS::Create(icon_path);
|
||||
if (!remoteclient->GetRange(filename, icon0_png_data, icon0_png_size, icon0_png_offset))
|
||||
{
|
||||
FS::Close(out);
|
||||
return false;
|
||||
}
|
||||
FS::Write(out, icon0_png_data, icon0_png_size);
|
||||
FS::Close(out);
|
||||
free(icon0_png_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+41
-30
@@ -1,30 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#define SWAP16(x) \
|
||||
((uint16_t)( \
|
||||
(((uint16_t)(x) & UINT16_C(0x00FF)) << 8) | \
|
||||
(((uint16_t)(x) & UINT16_C(0xFF00)) >> 8) \
|
||||
))
|
||||
#define SWAP16(x) \
|
||||
((uint16_t)((((uint16_t)(x)&UINT16_C(0x00FF)) << 8) | \
|
||||
(((uint16_t)(x)&UINT16_C(0xFF00)) >> 8)))
|
||||
|
||||
#define SWAP32(x) \
|
||||
((uint32_t)( \
|
||||
(((uint32_t)(x) & UINT32_C(0x000000FF)) << 24) | \
|
||||
(((uint32_t)(x) & UINT32_C(0x0000FF00)) << 8) | \
|
||||
(((uint32_t)(x) & UINT32_C(0x00FF0000)) >> 8) | \
|
||||
(((uint32_t)(x) & UINT32_C(0xFF000000)) >> 24) \
|
||||
))
|
||||
#define SWAP32(x) \
|
||||
((uint32_t)((((uint32_t)(x)&UINT32_C(0x000000FF)) << 24) | \
|
||||
(((uint32_t)(x)&UINT32_C(0x0000FF00)) << 8) | \
|
||||
(((uint32_t)(x)&UINT32_C(0x00FF0000)) >> 8) | \
|
||||
(((uint32_t)(x)&UINT32_C(0xFF000000)) >> 24)))
|
||||
|
||||
#define SWAP64(x) \
|
||||
((uint64_t)( \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x00000000000000FF)) << 56) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x000000000000FF00)) << 40) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x0000000000FF0000)) << 24) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x00000000FF000000)) << 8) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x000000FF00000000)) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x0000FF0000000000)) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0x00FF000000000000)) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(x) & UINT64_C(0xFF00000000000000)) >> 56) \
|
||||
))
|
||||
#define SWAP64(x) \
|
||||
((uint64_t)((uint64_t)(((uint64_t)(x)&UINT64_C(0x00000000000000FF)) << 56) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0x000000000000FF00)) << 40) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0x0000000000FF0000)) << 24) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0x00000000FF000000)) << 8) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0x000000FF00000000)) >> 8) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0x0000FF0000000000)) >> 24) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0x00FF000000000000)) >> 40) | \
|
||||
(uint64_t)(((uint64_t)(x)&UINT64_C(0xFF00000000000000)) >> 56)))
|
||||
|
||||
#define LE16(x) (x)
|
||||
#define LE32(x) (x)
|
||||
@@ -47,6 +41,9 @@
|
||||
#define PKG_CONTENT_FLAGS_DELTA_PATCH 0x41000000
|
||||
#define PKG_CONTENT_FLAGS_CUMULATIVE_PATCH 0x60000000
|
||||
|
||||
#define PKG_ENTRY_ID__PARAM_SFO 0x1000
|
||||
#define PKG_ENTRY_ID__ICON0_PNG 0x1200
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t pkg_magic; // 0x000 - 0x7F434E54
|
||||
@@ -98,11 +95,23 @@ typedef struct
|
||||
unsigned char pkg_digest[0x20]; // 0xFE0
|
||||
} pkg_header;
|
||||
|
||||
enum pkg_content_type {
|
||||
PKG_CONTENT_TYPE_GD = 0x1A, /* pkg_ps4_app, pkg_ps4_patch, pkg_ps4_remaster */
|
||||
PKG_CONTENT_TYPE_AC = 0x1B, /* pkg_ps4_ac_data, pkg_ps4_sf_theme, pkg_ps4_theme */
|
||||
PKG_CONTENT_TYPE_AL = 0x1C, /* pkg_ps4_ac_nodata */
|
||||
PKG_CONTENT_TYPE_DP = 0x1E, /* pkg_ps4_delta_patch */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t id; // File ID, useful for files without a filename entry
|
||||
uint32_t filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is located
|
||||
uint32_t flags1; // Flags including encrypted flag, etc
|
||||
uint32_t flags2; // Flags including encryption key index, etc
|
||||
uint32_t offset; // Offset into PKG to find the file
|
||||
uint32_t size; // Size of the file
|
||||
uint64_t padding; // blank padding
|
||||
} pkg_table_entry;
|
||||
|
||||
enum pkg_content_type
|
||||
{
|
||||
PKG_CONTENT_TYPE_GD = 0x1A, /* pkg_ps4_app, pkg_ps4_patch, pkg_ps4_remaster */
|
||||
PKG_CONTENT_TYPE_AC = 0x1B, /* pkg_ps4_ac_data, pkg_ps4_sf_theme, pkg_ps4_theme */
|
||||
PKG_CONTENT_TYPE_AL = 0x1C, /* pkg_ps4_ac_nodata */
|
||||
PKG_CONTENT_TYPE_DP = 0x1E, /* pkg_ps4_delta_patch */
|
||||
};
|
||||
|
||||
namespace INSTALLER
|
||||
@@ -111,7 +120,9 @@ namespace INSTALLER
|
||||
void Exit(void);
|
||||
|
||||
bool canInstallRemotePkg(const std::string &url);
|
||||
std::string getRemoteUrl(const std::string filename);
|
||||
std::string getRemoteUrl(const std::string filename, bool encodeUrl = false);
|
||||
int InstallRemotePkg(const std::string &filename, pkg_header *header);
|
||||
int InstallLocalPkg(const std::string &filename, pkg_header *header, bool remove_after_install=false);
|
||||
int InstallLocalPkg(const std::string &filename, pkg_header *header, bool remove_after_install = false);
|
||||
bool ExtractLocalPkg(const std::string &filename, const std::string sfo_path, const std::string icon_path);
|
||||
bool ExtractRemotePkg(const std::string &filename, const std::string sfo_path, const std::string icon_path);
|
||||
}
|
||||
+31
-3
@@ -119,7 +119,7 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"Operation not supported", // STR_UNSUPPORTED_OPERATION_MSG
|
||||
"Http Port", // STR_HTTP_PORT
|
||||
"The content has already been installed. Do you want to continue installing", // STR_REINSTALL_CONFIRM_MSG
|
||||
"Remote server requires at least a username.", // STR_REMOTE_NOT_SUPPORT_MSG
|
||||
"Remote package installation is not supported for protected servers.", // STR_REMOTE_NOT_SUPPORT_MSG
|
||||
"Remote HTTP Server not reachable.", // STR_CANNOT_CONNECT_REMOTE_MSG
|
||||
"Remote Package Install not possible. Would you like to download package and install?", // STR_DOWNLOAD_INSTALL_MSG
|
||||
"Checking remote server for Remote Package Install.", // STR_CHECKING_REMOTE_SERVER_MSG
|
||||
@@ -127,8 +127,36 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"This option enables Remote Package Installation. "
|
||||
"This requires a HTTP Server setup on the same host sharing the same folder with anonymous access.", // STR_ENABLE_RPI_FTP_SMB_MSG
|
||||
"This option enables Remote Package Installation. "
|
||||
"This requires the Server with anonymous access that does not need username/password.", // STR_ENABLE_RPI_WEBDAV_MSG
|
||||
"Files", // STR_FILES
|
||||
"This requires the Server with anonymous access that does not need username/password.", // STR_ENABLE_RPI_WEBDAV_MSG
|
||||
"Files", // STR_FILES
|
||||
"Editor", // STR_EDITOR
|
||||
"Save", // STR_SAVE
|
||||
"Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG
|
||||
"Delete Selected Line", // STR_DELETE_LINE
|
||||
"Insert Below Selected Line", // STR_INSERT_LINE
|
||||
"Modified", // STR_MODIFIED
|
||||
"Failed to obtain an access token from", // STR_FAIL_GET_TOKEN_MSG
|
||||
"Login Success. You may close the browser and return to the application", // STR_GET_TOKEN_SUCCESS_MSG
|
||||
"See, edit, create, and delete all of your Google Drive files", // STR_PERM_DRIVE
|
||||
"See, create, and delete its own configuration data in your Google Drive", // STR_PERM_DRIVE_APPDATA
|
||||
"See, edit, create, and delete only the specific Google Drive files you use with this app", // STR_PERM_DRIVE_FILE
|
||||
"View and manage metadata of files in your Google Drive", // STR_PERM_DRIVE_METADATA
|
||||
"See information about your Google Drive files", // STR_PERM_DRIVE_METADATA_RO
|
||||
"Google login failed", // STR_GOOGLE_LOGIN_FAIL_MSG
|
||||
"Google login timed out", // STR_GOOGLE_LOGIN_TIMEOUT_MSG
|
||||
"New File", // STR_NEW_FILE
|
||||
"Settings", // STR_SETTINGS
|
||||
"Client ID", // STR_CLIENT_ID
|
||||
"Client Secret", // STR_CLIENT_SECRET
|
||||
"Global", // STR_GLOBAL
|
||||
"Google", // STR_GOOGLE
|
||||
"Copy selected line", // STR_COPY_LINE
|
||||
"Paste into selected line", // STR_PASTE_LINE
|
||||
"Show hidden files", // STR_SHOW_HIDDEN_FILES
|
||||
"Set Default Folder", // STR_SET_DEFAULT_DIRECTORY
|
||||
"has being set as default direcotry", // STR_SET_DEFAULT_DIRECTORY_MSG
|
||||
"View Image", // STR_VIEW_IMAGE
|
||||
"Package Information", // STR_VIEW_PKG_INFO
|
||||
};
|
||||
|
||||
bool needs_extended_font = false;
|
||||
|
||||
+30
-2
@@ -120,7 +120,35 @@
|
||||
FUNC(STR_ENABLE_RPI) \
|
||||
FUNC(STR_ENABLE_RPI_FTP_SMB_MSG) \
|
||||
FUNC(STR_ENABLE_RPI_WEBDAV_MSG) \
|
||||
FUNC(STR_FILES)
|
||||
FUNC(STR_FILES) \
|
||||
FUNC(STR_EDITOR) \
|
||||
FUNC(STR_SAVE) \
|
||||
FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \
|
||||
FUNC(STR_DELETE_LINE) \
|
||||
FUNC(STR_INSERT_LINE) \
|
||||
FUNC(STR_MODIFIED) \
|
||||
FUNC(STR_FAIL_GET_TOKEN_MSG) \
|
||||
FUNC(STR_GET_TOKEN_SUCCESS_MSG) \
|
||||
FUNC(STR_PERM_DRIVE) \
|
||||
FUNC(STR_PERM_DRIVE_APPDATA) \
|
||||
FUNC(STR_PERM_DRIVE_FILE) \
|
||||
FUNC(STR_PERM_DRIVE_METADATA) \
|
||||
FUNC(STR_PERM_DRIVE_METADATA_RO) \
|
||||
FUNC(STR_GOOGLE_LOGIN_FAIL_MSG) \
|
||||
FUNC(STR_GOOGLE_LOGIN_TIMEOUT_MSG) \
|
||||
FUNC(STR_NEW_FILE) \
|
||||
FUNC(STR_SETTINGS) \
|
||||
FUNC(STR_CLIENT_ID) \
|
||||
FUNC(STR_CLIENT_SECRET) \
|
||||
FUNC(STR_GLOBAL) \
|
||||
FUNC(STR_GOOGLE) \
|
||||
FUNC(STR_COPY_LINE) \
|
||||
FUNC(STR_PASTE_LINE) \
|
||||
FUNC(STR_SHOW_HIDDEN_FILES) \
|
||||
FUNC(STR_SET_DEFAULT_DIRECTORY) \
|
||||
FUNC(STR_SET_DEFAULT_DIRECTORY_MSG) \
|
||||
FUNC(STR_VIEW_IMAGE) \
|
||||
FUNC(STR_VIEW_PKG_INFO)
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
@@ -130,7 +158,7 @@ enum
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 117
|
||||
#define LANG_STRINGS_NUM 145
|
||||
#define LANG_ID_SIZE 64
|
||||
#define LANG_STR_SIZE 384
|
||||
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
|
||||
|
||||
+24
-9
@@ -17,12 +17,15 @@
|
||||
#include "SDL2/SDL.h"
|
||||
#include "imgui_impl_sdl.h"
|
||||
#include "imgui_impl_sdlrenderer.h"
|
||||
#include "server/http_server.h"
|
||||
#include "clients/gdrive.h"
|
||||
#include "config.h"
|
||||
#include "lang.h"
|
||||
#include "gui.h"
|
||||
#include "util.h"
|
||||
#include "installer.h"
|
||||
#include "rtc.h"
|
||||
#include "system.h"
|
||||
#include "textures.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -97,7 +100,7 @@ void InitImgui()
|
||||
0,
|
||||
};
|
||||
|
||||
static const ImWchar icons[] {
|
||||
static const ImWchar fa_icons[] {
|
||||
0xF07B, 0xF07B, // folder
|
||||
0xF65E, 0xF65E, // new folder
|
||||
0xF15B, 0xF15B, // file
|
||||
@@ -111,13 +114,23 @@ void InitImgui()
|
||||
0xE0AC, 0xE0AC, // rename
|
||||
0xE5A1, 0xE5A1, // delete
|
||||
0xF002, 0xF002, // search
|
||||
0x2699, 0x2699, // settings
|
||||
0xF013, 0xF013, // settings
|
||||
0xF0ED, 0xF0ED, // download
|
||||
0xF0EE, 0xF0EE, // upload
|
||||
0xF56E, 0xF56E, // extract
|
||||
0xF56F, 0xF56F, // compress
|
||||
0xF0F6, 0xF0F6, // properties
|
||||
0xF112, 0xF112, // cancel
|
||||
0xF0DA, 0xF0DA, // arrow right
|
||||
0x0031, 0x0031, // 1
|
||||
0x004C, 0x004C, // L
|
||||
0x0052, 0x0052, // R
|
||||
0,
|
||||
};
|
||||
|
||||
static const ImWchar of_icons[] {
|
||||
0xE0CB, 0xE0CB, // square
|
||||
0xE0DE, 0xE0DE, // triangle
|
||||
0,
|
||||
};
|
||||
|
||||
@@ -171,7 +184,8 @@ void InitImgui()
|
||||
ImFontConfig config;
|
||||
config.MergeMode = true;
|
||||
config.GlyphMinAdvanceX = 13.0f; // Use if you want to make the icon monospaced
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/fa-solid-900.ttf", 20.0f, &config, icons);
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/fa-solid-900.ttf", 20.0f, &config, fa_icons);
|
||||
io.Fonts->AddFontFromFileTTF("/app0/assets/fonts/OpenFontIcons.ttf", 20.0f, &config, of_icons);
|
||||
io.Fonts->Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;
|
||||
io.Fonts->Build();
|
||||
|
||||
@@ -240,7 +254,7 @@ void InitImgui()
|
||||
colors[ImGuiCol_PlotHistogramHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_ModalWindowDimBg] = bgColorBlur;
|
||||
colors[ImGuiCol_DragDropTarget] = bgColor;
|
||||
colors[ImGuiCol_NavHighlight] = bgColor;
|
||||
colors[ImGuiCol_NavHighlight] = titleColor;
|
||||
colors[ImGuiCol_Tab] = bgColor;
|
||||
colors[ImGuiCol_TabActive] = panelActiveColor;
|
||||
colors[ImGuiCol_TabUnfocused] = bgColor;
|
||||
@@ -284,6 +298,7 @@ int main()
|
||||
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);
|
||||
@@ -294,30 +309,30 @@ int main()
|
||||
if (renderer == NULL)
|
||||
return 0;
|
||||
|
||||
Textures::Init(renderer);
|
||||
InitImgui();
|
||||
|
||||
// Setup Platform/Renderer backends
|
||||
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
|
||||
ImGui_ImplSDLRenderer_Init(renderer);
|
||||
ImGui_ImplSDLRenderer_CreateFontsTexture();
|
||||
ImGui_ImplSDL2_DisableButton(SDL_CONTROLLER_BUTTON_X, true);
|
||||
|
||||
if (!initialize_jbc())
|
||||
{
|
||||
terminate();
|
||||
}
|
||||
|
||||
if (load_rtc_module() != 0)
|
||||
if (load_sys_modules() != 0)
|
||||
return 0;
|
||||
|
||||
atexit(terminate);
|
||||
|
||||
GUI::RenderLoop(renderer);
|
||||
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
Textures::Exit();
|
||||
|
||||
ImGui::DestroyContext();
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Sysmodule.h>
|
||||
|
||||
#include "rtc.h"
|
||||
|
||||
int (*sceRtcGetTick)(const OrbisDateTime *inOrbisDateTime, OrbisTick *outTick);
|
||||
int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *inputTick);
|
||||
int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc);
|
||||
int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time);
|
||||
int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time);
|
||||
|
||||
void convertUtcToLocalTime(const OrbisDateTime *utc, OrbisDateTime *local_time)
|
||||
{
|
||||
OrbisTick utc_tick;
|
||||
OrbisTick local_tick;
|
||||
sceRtcGetTick(utc, &utc_tick);
|
||||
sceRtcConvertUtcToLocalTime(&utc_tick, &local_tick);
|
||||
sceRtcSetTick(local_time, &local_tick);
|
||||
}
|
||||
|
||||
void convertLocalTimeToUtc(const OrbisDateTime *local_time, OrbisDateTime *utc)
|
||||
{
|
||||
OrbisTick utc_tick;
|
||||
OrbisTick local_tick;
|
||||
sceRtcGetTick(local_time, &local_tick);
|
||||
sceRtcConvertLocalTimeToUtc(&local_tick, &utc_tick);
|
||||
sceRtcSetTick(utc, &utc_tick);
|
||||
}
|
||||
|
||||
int load_rtc_module()
|
||||
{
|
||||
int rtc_handle = sceKernelLoadStartModule("/system/common/lib/libSceRtc.sprx", 0, NULL, 0, NULL, NULL);
|
||||
if (rtc_handle == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcGetTick", (void **)&sceRtcGetTick);
|
||||
if (sceRtcGetTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcSetTick", (void **)&sceRtcSetTick);
|
||||
if (sceRtcSetTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcConvertLocalTimeToUtc", (void **)&sceRtcConvertLocalTimeToUtc);
|
||||
if (sceRtcConvertLocalTimeToUtc == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcConvertUtcToLocalTime", (void **)&sceRtcConvertUtcToLocalTime);
|
||||
if (sceRtcConvertUtcToLocalTime == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(rtc_handle, "sceRtcGetCurrentClockLocalTime", (void **)&sceRtcGetCurrentClockLocalTime);
|
||||
if (sceRtcGetCurrentClockLocalTime == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
#include <string>
|
||||
#include <json-c/json.h>
|
||||
#include "http/httplib.h"
|
||||
#include "server/http_server.h"
|
||||
#include "clients/gdrive.h"
|
||||
#include "config.h"
|
||||
#include "windows.h"
|
||||
#include "lang.h"
|
||||
#include "system.h"
|
||||
|
||||
#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt"
|
||||
#define SERVER_PRIVATE_KEY_FILE "/app0/assets/certs/domain.key"
|
||||
#define SERVER_PRIVATE_KEY_PASSWORD "12345678"
|
||||
|
||||
using namespace httplib;
|
||||
SSLServer *svr;
|
||||
int http_server_port = 8080;
|
||||
|
||||
namespace HttpServer
|
||||
{
|
||||
std::string dump_headers(const Headers &headers)
|
||||
{
|
||||
std::string s;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
for (auto it = headers.begin(); it != headers.end(); ++it)
|
||||
{
|
||||
const auto &x = *it;
|
||||
snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str());
|
||||
s += buf;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string log(const Request &req, const Response &res)
|
||||
{
|
||||
std::string s;
|
||||
char buf[BUFSIZ];
|
||||
|
||||
s += "================================\n";
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(),
|
||||
req.version.c_str(), req.path.c_str());
|
||||
s += buf;
|
||||
|
||||
std::string query;
|
||||
for (auto it = req.params.begin(); it != req.params.end(); ++it)
|
||||
{
|
||||
const auto &x = *it;
|
||||
snprintf(buf, sizeof(buf), "%c%s=%s",
|
||||
(it == req.params.begin()) ? '?' : '&', x.first.c_str(),
|
||||
x.second.c_str());
|
||||
query += buf;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%s\n", query.c_str());
|
||||
s += buf;
|
||||
|
||||
s += dump_headers(req.headers);
|
||||
|
||||
s += "--------------------------------\n";
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str());
|
||||
s += buf;
|
||||
s += dump_headers(res.headers);
|
||||
s += "\n";
|
||||
|
||||
if (!res.body.empty())
|
||||
{
|
||||
s += res.body;
|
||||
}
|
||||
|
||||
s += "\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void *ServerThread(void *argp)
|
||||
{
|
||||
svr->Get("/google_auth", [](const Request &req, Response &res)
|
||||
{
|
||||
std::string auth_code = req.get_param_value("code");
|
||||
Client client(GOOGLE_OAUTH_HOST);
|
||||
client.set_follow_location(true);
|
||||
client.enable_server_certificate_verification(false);
|
||||
|
||||
std::string url = std::string("/token");
|
||||
std::string post_data = std::string("code=") + auth_code +
|
||||
"&client_id=" + gg_app.client_id +
|
||||
"&client_secret=" + gg_app.client_secret +
|
||||
"&redirect_uri=https%3A//localhost%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"))
|
||||
{
|
||||
if (HTTP_SUCCESS(result->status))
|
||||
{
|
||||
json_object *jobj = json_tokener_parse(result.value().body.c_str());
|
||||
enum json_type type;
|
||||
json_object_object_foreach(jobj, key, val)
|
||||
{
|
||||
if (strcmp(key, "access_token")==0)
|
||||
snprintf(remote_settings->gg_account.access_token, 255, "%s", json_object_get_string(val));
|
||||
else if (strcmp(key, "refresh_token")==0)
|
||||
snprintf(remote_settings->gg_account.refresh_token, 255, "%s", json_object_get_string(val));
|
||||
else if (strcmp(key, "expires_in")==0)
|
||||
{
|
||||
OrbisTick tick;
|
||||
sceRtcGetCurrentTick(&tick);
|
||||
remote_settings->gg_account.token_expiry = tick.mytick + (json_object_get_uint64(val)*1000000);
|
||||
}
|
||||
}
|
||||
CONFIG::SaveConfig();
|
||||
login_state = 1;
|
||||
res.set_content(lang_strings[STR_GET_TOKEN_SUCCESS_MSG], "text/plain");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
login_state = -1;
|
||||
std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google";
|
||||
res.set_content(str.c_str(), "text/plain");
|
||||
}
|
||||
}
|
||||
login_state = -1;
|
||||
std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google";
|
||||
res.set_content(str.c_str(), "text/plain");
|
||||
});
|
||||
|
||||
svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/)
|
||||
{
|
||||
svr->stop();
|
||||
});
|
||||
|
||||
svr->set_error_handler([](const Request & /*req*/, Response &res)
|
||||
{
|
||||
const char *fmt = "<p>Error Status: <span style='color:red;'>%d</span></p>";
|
||||
char buf[BUFSIZ];
|
||||
snprintf(buf, sizeof(buf), fmt, res.status);
|
||||
res.set_content(buf, "text/html");
|
||||
});
|
||||
|
||||
/*
|
||||
svr->set_logger([](const Request &req, const Response &res)
|
||||
{
|
||||
dbglogger_log("%s", log(req, res).c_str());
|
||||
});
|
||||
*/
|
||||
|
||||
svr->listen("127.0.0.1", http_server_port);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (svr == nullptr)
|
||||
svr = new SSLServer(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, nullptr, nullptr, SERVER_PRIVATE_KEY_PASSWORD);
|
||||
if (!svr->is_valid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
int ret = pthread_create(&http_server_thid, NULL, ServerThread, NULL);
|
||||
}
|
||||
|
||||
void Stop()
|
||||
{
|
||||
if (svr != nullptr)
|
||||
svr->stop();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef HTTP_SERVER_H
|
||||
#define HTTP_SERVER_H
|
||||
|
||||
#include "http/httplib.h"
|
||||
|
||||
using namespace httplib;
|
||||
extern SSLServer *svr;
|
||||
|
||||
static pthread_t http_server_thid;
|
||||
extern int http_server_port;
|
||||
|
||||
namespace HttpServer
|
||||
{
|
||||
void *ServerThread(void *argp);
|
||||
void Start();
|
||||
void Stop();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <cstring>
|
||||
#include "sfo.h"
|
||||
|
||||
static constexpr uint32_t SFO_MAGIC = 0x46535000;
|
||||
|
||||
namespace SFO {
|
||||
const char* GetString(const char* buffer, size_t size, const char *name)
|
||||
{
|
||||
if (size < sizeof(SfoHeader))
|
||||
return nullptr;
|
||||
|
||||
const SfoHeader* header = reinterpret_cast<const SfoHeader*>(buffer);
|
||||
const SfoEntry* entries =
|
||||
reinterpret_cast<const SfoEntry*>(buffer + sizeof(SfoHeader));
|
||||
|
||||
if (header->magic != SFO_MAGIC)
|
||||
return nullptr;
|
||||
|
||||
if (size < sizeof(SfoHeader) + header->count * sizeof(SfoEntry))
|
||||
return nullptr;
|
||||
|
||||
for (uint32_t i = 0; i < header->count; i++) {
|
||||
const char* key = reinterpret_cast<const char*>(buffer + header->keyofs + entries[i].nameofs);
|
||||
if (strcmp(key, name) == 0)
|
||||
return reinterpret_cast<const char*>(buffer + header->valofs + entries[i].dataofs);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> GetParams(const char* buffer, size_t size)
|
||||
{
|
||||
std::map<std::string, std::string> out;
|
||||
|
||||
if (size < sizeof(SfoHeader))
|
||||
return out;
|
||||
|
||||
const SfoHeader* header = reinterpret_cast<const SfoHeader*>(buffer);
|
||||
const SfoEntry* entries =
|
||||
reinterpret_cast<const SfoEntry*>(buffer + sizeof(SfoHeader));
|
||||
|
||||
if (header->magic != SFO_MAGIC)
|
||||
return out;
|
||||
|
||||
if (size < sizeof(SfoHeader) + header->count * sizeof(SfoEntry))
|
||||
return out;
|
||||
|
||||
for (uint32_t i = 0; i < header->count; i++) {
|
||||
const char* key = reinterpret_cast<const char*>(buffer + header->keyofs + entries[i].nameofs);
|
||||
if (entries[i].type == 2)
|
||||
{
|
||||
const char* value = reinterpret_cast<const char*>(buffer + header->valofs + entries[i].dataofs);
|
||||
out.insert(std::make_pair(key, value));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t *value = (uint32_t *)(buffer + header->valofs + entries[i].dataofs);
|
||||
out.insert(std::make_pair(key, std::to_string(*value)));
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef LAUNCHER_SFO_H
|
||||
#define LAUNCHER_SFO_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
struct SfoHeader
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t version;
|
||||
uint32_t keyofs;
|
||||
uint32_t valofs;
|
||||
uint32_t count;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct SfoEntry
|
||||
{
|
||||
uint16_t nameofs;
|
||||
uint8_t alignment;
|
||||
uint8_t type;
|
||||
uint32_t valsize;
|
||||
uint32_t totalsize;
|
||||
uint32_t dataofs;
|
||||
} __attribute__((packed));
|
||||
|
||||
namespace SFO {
|
||||
const char* GetString(const char* buffer, size_t size, const char *name);
|
||||
std::map<std::string, std::string> GetParams(const char* buffer, size_t size);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <stdlib.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include <orbis/Sysmodule.h>
|
||||
|
||||
#include "system.h"
|
||||
|
||||
int (*sceRtcGetTick)(const OrbisDateTime *inOrbisDateTime, OrbisTick *outTick);
|
||||
int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *inputTick);
|
||||
int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc);
|
||||
int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time);
|
||||
int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time);
|
||||
int (*sceRtcGetCurrentTick)(OrbisTick *outTick);
|
||||
unsigned int (*sceRtcGetTickResolution)();
|
||||
int (*sceShellUIUtilLaunchByUri)(const char *uri, SceShellUIUtilLaunchByUriParam *param);
|
||||
int (*sceShellUIUtilInitialize)();
|
||||
|
||||
void convertUtcToLocalTime(const OrbisDateTime *utc, OrbisDateTime *local_time)
|
||||
{
|
||||
OrbisTick utc_tick;
|
||||
OrbisTick local_tick;
|
||||
sceRtcGetTick(utc, &utc_tick);
|
||||
sceRtcConvertUtcToLocalTime(&utc_tick, &local_tick);
|
||||
sceRtcSetTick(local_time, &local_tick);
|
||||
}
|
||||
|
||||
void convertLocalTimeToUtc(const OrbisDateTime *local_time, OrbisDateTime *utc)
|
||||
{
|
||||
OrbisTick utc_tick;
|
||||
OrbisTick local_tick;
|
||||
sceRtcGetTick(local_time, &local_tick);
|
||||
sceRtcConvertLocalTimeToUtc(&local_tick, &utc_tick);
|
||||
sceRtcSetTick(utc, &utc_tick);
|
||||
}
|
||||
|
||||
int load_sys_modules()
|
||||
{
|
||||
int handle = sceKernelLoadStartModule("/system/common/lib/libSceRtc.sprx", 0, NULL, 0, NULL, NULL);
|
||||
if (handle == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcGetTick", (void **)&sceRtcGetTick);
|
||||
if (sceRtcGetTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcSetTick", (void **)&sceRtcSetTick);
|
||||
if (sceRtcSetTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcConvertLocalTimeToUtc", (void **)&sceRtcConvertLocalTimeToUtc);
|
||||
if (sceRtcConvertLocalTimeToUtc == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcConvertUtcToLocalTime", (void **)&sceRtcConvertUtcToLocalTime);
|
||||
if (sceRtcConvertUtcToLocalTime == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcGetCurrentClockLocalTime", (void **)&sceRtcGetCurrentClockLocalTime);
|
||||
if (sceRtcGetCurrentClockLocalTime == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcGetCurrentTick", (void **)&sceRtcGetCurrentTick);
|
||||
if (sceRtcGetCurrentTick == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceRtcGetTickResolution", (void **)&sceRtcGetTickResolution);
|
||||
if (sceRtcGetTickResolution == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle = sceKernelLoadStartModule("/system/common/lib/libSceShellUIUtil.sprx", 0, NULL, 0, 0, 0);
|
||||
if (handle == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceShellUIUtilInitialize", (void **)&sceShellUIUtilInitialize);
|
||||
if (sceShellUIUtilInitialize == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
sceKernelDlsym(handle, "sceShellUIUtilLaunchByUri", (void **)&sceShellUIUtilLaunchByUri);
|
||||
if (sceShellUIUtilLaunchByUri == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (sceShellUIUtilInitialize() < 0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -4,6 +4,12 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int size;
|
||||
uint32_t userId;
|
||||
} SceShellUIUtilLaunchByUriParam;
|
||||
|
||||
typedef struct OrbisTick {
|
||||
uint64_t mytick;
|
||||
} OrbisTick;
|
||||
@@ -22,9 +28,13 @@ extern int (*sceRtcGetTick)(const OrbisDateTime *inOrbisDateTime, OrbisTick *out
|
||||
extern int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *inputTick);
|
||||
extern int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc);
|
||||
extern int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time);
|
||||
extern int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time) ;
|
||||
extern int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time);
|
||||
extern int (*sceRtcGetCurrentTick)(OrbisTick *outTick);
|
||||
extern unsigned int (*sceRtcGetTickResolution)();
|
||||
extern int (*sceShellUIUtilLaunchByUri)(const char *uri, SceShellUIUtilLaunchByUriParam *param);
|
||||
extern int (*sceShellUIUtilInitialize)();
|
||||
|
||||
int load_rtc_module();
|
||||
int load_sys_modules();
|
||||
void convertUtcToLocalTime(const OrbisDateTime *utc, OrbisDateTime *local_time);
|
||||
void convertLocalTimeToUtc(const OrbisDateTime *local_time, OrbisDateTime *utc);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "textures.h"
|
||||
|
||||
static SDL_Renderer *renderer;
|
||||
|
||||
namespace Textures {
|
||||
|
||||
bool LoadImageFile(const std::string filename, Tex *texture)
|
||||
{
|
||||
// Load from file
|
||||
SDL_Surface *image = IMG_Load(filename.c_str());
|
||||
if (image == nullptr)
|
||||
return false;
|
||||
SDL_Surface *formated_image = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_RGBA8888, 0);
|
||||
if (formated_image == nullptr)
|
||||
{
|
||||
SDL_FreeSurface(image);
|
||||
}
|
||||
SDL_Texture *sdl_texture = SDL_CreateTextureFromSurface(renderer, formated_image);
|
||||
if (sdl_texture == nullptr)
|
||||
{
|
||||
SDL_FreeSurface(formated_image);
|
||||
SDL_FreeSurface(image);
|
||||
return false;
|
||||
}
|
||||
texture->id = sdl_texture;
|
||||
texture->height = formated_image->h;
|
||||
texture->width = formated_image->w;
|
||||
|
||||
SDL_FreeSurface(formated_image);
|
||||
SDL_FreeSurface(image);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Init(SDL_Renderer *p_renderer) {
|
||||
renderer = p_renderer;
|
||||
IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_WEBP);
|
||||
}
|
||||
|
||||
void Exit(void) {
|
||||
IMG_Quit();
|
||||
}
|
||||
|
||||
void Free(Tex *texture) {
|
||||
if (texture->id != nullptr)
|
||||
{
|
||||
SDL_DestroyTexture(texture->id);
|
||||
texture->id = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef LAUNCHER_TEXTURES_H
|
||||
#define LAUNCHER_TEXTURES_H
|
||||
|
||||
#include <string>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_image.h>
|
||||
|
||||
typedef struct {
|
||||
SDL_Texture *id;
|
||||
int width;
|
||||
int height;
|
||||
} Tex;
|
||||
|
||||
namespace Textures {
|
||||
bool LoadImageFile(const std::string filename, Tex *texture);
|
||||
void Init(SDL_Renderer *renderer);
|
||||
void Exit(void);
|
||||
void Free(Tex *texture);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <algorithm>
|
||||
#include <stdarg.h>
|
||||
#include <orbis/libkernel.h>
|
||||
#include "lang.h"
|
||||
|
||||
namespace Util
|
||||
{
|
||||
@@ -81,5 +82,23 @@ namespace Util
|
||||
sceKernelSendNotificationRequest(0, &request, sizeof(request), 0);
|
||||
}
|
||||
|
||||
static inline void SetupPreviousFolder(const std::string &path, DirEntry *entry)
|
||||
{
|
||||
memset(entry, 0, sizeof(DirEntry));
|
||||
if (path[path.length() - 1] == '/' && path.length() > 1)
|
||||
{
|
||||
strlcpy(entry->directory, path.c_str(), path.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(entry->directory, "%s", path.c_str());
|
||||
}
|
||||
sprintf(entry->name, "%s", "..");
|
||||
sprintf(entry->path, "%s", entry->directory);
|
||||
sprintf(entry->display_size, "%s", lang_strings[STR_FOLDER]);
|
||||
entry->file_size = 0;
|
||||
entry->isDir = true;
|
||||
entry->selectable = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+691
-94
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@ extern ACTIONS action_to_take;
|
||||
extern bool file_transfering;
|
||||
extern char extract_zip_folder[];
|
||||
extern char zip_file_path[];
|
||||
extern std::vector<std::string> edit_buffer;
|
||||
|
||||
static ImVector<ImRect> s_GroupPanelLabelStack;
|
||||
|
||||
@@ -208,6 +209,7 @@ namespace Windows
|
||||
void AfterZipFileCallback(int ime_result);
|
||||
void AferServerChangeCallback(int ime_result);
|
||||
void AfterHttpPortChangeCallback(int ime_result);
|
||||
void AfterEditorCallback(int ime_result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
#include "common.h"
|
||||
#include "fs.h"
|
||||
#include "lang.h"
|
||||
#include "rtc.h"
|
||||
#include "system.h"
|
||||
#include "windows.h"
|
||||
#include "zip_util.h"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user