Compare commits

..

45 Commits

Author SHA1 Message Date
Chee Yee c022615e1e update readme 2023-04-07 17:20:32 -07:00
Chee Yee 87ad8bf9b3 update readme 2023-04-07 17:00:44 -07:00
Chee Yee 57248f797e add missing string 2023-04-07 17:00:31 -07:00
Chee Yee 4a7ab7e131 changed to use the OPTIONS button to exit application 2023-04-07 17:00:05 -07:00
Chee Yee e563f422c0 close dialog with circle button 2023-04-07 01:50:02 -07:00
Chee Yee ff802d0a62 add ability to view package icon and information 2023-04-07 01:03:42 -07:00
Chee Yee 4aabf850b8 add ability to view remote image file 2023-04-04 20:39:10 -07:00
Chee Yee 4ea584e092 add ability to view images 2023-04-04 01:31:43 -07:00
Chee Yee 15597ccfc1 fix all operations for shared drive files 2023-04-01 23:33:43 -07:00
Chee Yee e600715164 add support for shared drive 2023-04-01 21:42:55 -07:00
Chee Yee a46f3f4cca save current folder as default folder 2023-03-31 01:13:02 -07:00
Chee Yee 751011d08b implement shared team drives and set default local/remote folders 2023-03-31 00:56:53 -07:00
cy33hc d34df2cf94 Update README.md 2023-03-14 11:59:03 -07:00
Chee Yee f6cf00974b changed RPI install message 2023-03-13 22:35:03 -07:00
Chee Yee 9788b7e963 disable upload if remote server does not support it 2023-03-13 22:24:20 -07:00
Chee Yee aa9ef34991 some bug fixes related to RPI and add option to show hidden files 2023-03-13 22:07:57 -07:00
Chee Yee fc96b76260 fix for bug #7 2023-03-13 19:39:14 -07:00
Chee Yee c54fc8fcbc Merge branch 'master' of github.com:cy33hc/ps4-ezremote-client 2023-03-13 04:56:12 -07:00
Chee Yee 5ca56b47df add copy/paste function in text editor 2023-03-13 04:56:04 -07:00
cy33hc 05d253edd8 Update README.md 2023-03-11 18:36:16 -08:00
cy33hc d752dd8fed Update README.md 2023-03-11 18:35:08 -08:00
cy33hc 45320ed2ca Update README.md 2023-03-10 23:30:36 -08:00
cy33hc 8aef5d0233 Update README.md 2023-03-10 21:08:40 -08:00
cy33hc 2c9d31fbcc Update README.md 2023-03-10 18:05:41 -08:00
Chee Yee a4510e0b47 missed set the date of files 2023-03-10 01:35:53 -08:00
Chee Yee d6ec9ac1a5 more fixes 2023-03-10 01:13:49 -08:00
Chee Yee 2975f736de fix copy of empty folders 2023-03-10 01:05:48 -08:00
Chee Yee 9a9308244c Merge branch 'master' of github.com:cy33hc/ps4-ezremote-client 2023-03-09 23:55:19 -08:00
Chee Yee 649f6daac2 open fine in binary mode 2023-03-09 23:55:12 -08:00
cy33hc cc541c6da5 Update README.md 2023-03-09 23:07:49 -08:00
Chee Yee ec7b845bdc add SFTP support 2023-03-09 23:05:58 -08:00
Chee Yee eed0e5193b forgot to delete object 2023-03-03 23:51:59 -08:00
Chee Yee 9d7e46dcc6 clear activity_message 2023-03-02 22:52:28 -08:00
Chee Yee 2164443969 update strings 2023-03-02 22:34:41 -08:00
Chee Yee d3f8cdc774 add missing string 2023-03-02 22:27:58 -08:00
Chee Yee f58e9fdecd put dialog at correct position 2023-03-02 22:20:30 -08:00
Chee Yee ea768a3528 Merge branch 'master' of github.com:cy33hc/ps4-ezremote-client 2023-03-02 22:06:48 -08:00
Chee Yee 6371c6fd29 fix crash when client_id is empty 2023-03-02 22:06:37 -08:00
cy33hc 456b1aa075 Update README.md 2023-03-02 19:40:15 -08:00
cy33hc e654667621 Update README.md 2023-03-02 19:39:43 -08:00
cy33hc a4ac55ca88 Update README.md 2023-03-01 21:35:16 -08:00
cy33hc f0c291eb0c Update README.md 2023-03-01 21:32:09 -08:00
cy33hc d96734aeeb Update README.md 2023-03-01 21:30:48 -08:00
cy33hc 4aa6b7c02a Update README.md 2023-03-01 21:30:15 -08:00
cy33hc c632f0d7cb Update README.md 2023-03-01 21:29:54 -08:00
37 changed files with 1961 additions and 215 deletions
+8 -1
View File
@@ -37,6 +37,7 @@ add_executable(ezremote_client
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
@@ -51,21 +52,26 @@ add_executable(ezremote_client
source/main.cpp
source/orbis_jbc.c
source/system.cpp
source/sfo.cpp
source/textures.cpp
source/windows.cpp
source/zip_util.cpp
)
add_self(ezremote_client)
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.02" 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
@@ -77,6 +83,7 @@ target_link_libraries(ezremote_client
un7zip
unrar
json-c
ssh2
kernel
SceShellCoreUtil
SceSysmodule
+29 -9
View File
@@ -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.
![Preview](/screenshot.jpg)
## 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.
@@ -56,13 +64,18 @@ Remote Package Installation only works if the WebDAV server allow anonymous acce
- 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 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.
Binary file not shown.
+12 -3
View File
@@ -107,9 +107,9 @@ 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.
@@ -120,6 +120,7 @@ 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
@@ -133,4 +134,12 @@ STR_NEW_FILE=New File
STR_SETTINGS=Settings
STR_CLIENT_ID=Client ID
STR_CLIENT_SECRET=Client Secret
STR_GLOBAL=Global
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
+141 -61
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
#pragma once
#define ICON_OF_SQUARE "\xee\x83\x8b" // U+E0CB
#define ICON_OF_TRIANGLE "\xee\x83\x9e" // U+E0CB
+10 -5
View File
@@ -12,6 +12,7 @@
#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"
@@ -820,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));
@@ -1141,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]);
@@ -1178,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;
}
}
@@ -1269,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)
@@ -1284,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)
{
@@ -1533,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)
{
+7 -1
View File
@@ -50,7 +50,13 @@ enum ACTIONS
ACTION_REMOTE_PASTE,
ACTION_REMOTE_EDIT,
ACTION_NEW_LOCAL_FILE,
ACTION_NEW_REMOTE_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
+31
View File
@@ -94,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]);
@@ -176,6 +205,8 @@ std::string BaseClient::GetPath(std::string ppath1, std::string ppath2)
path1 = Util::Trim(Util::Trim(path1, " "), "/");
path2 = Util::Trim(Util::Trim(path2, " "), "/");
path1 = this->base_path + ((this->base_path.length() > 0) ? "/" : "") + path1 + "/" + path2;
if (path1[0] != '/')
path1 = "/" + path1;
return path1;
}
+1
View File
@@ -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);
+34 -1
View File
@@ -16,7 +16,6 @@
#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
*
+1
View File
@@ -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);
+191 -17
View File
@@ -14,9 +14,9 @@
#include "system.h"
#define GOOGLE_BUF_SIZE 262144
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
static std::string shared_with_me("Shared with me");
static std::string my_drive("My Drive");
using namespace httplib;
@@ -71,7 +71,7 @@ int RefreshAccessToken()
}
if (remoteclient != nullptr && remoteclient->clientType() == CLIENT_TYPE_GOOGLE)
{
GDriveClient *client = (GDriveClient*)remoteclient;
GDriveClient *client = (GDriveClient *)remoteclient;
client->SetAccessToken(remote_settings->gg_account.access_token);
}
CONFIG::SaveConfig();
@@ -144,11 +144,19 @@ int GDriveClient::RequestAuthorization()
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("/", "root"));
path_id_map.insert(std::make_pair("/"+shared_with_me, shared_with_me));
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)
@@ -176,16 +184,47 @@ int GDriveClient::Connect(const std::string &url, const std::string &user, const
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)
if (src.find("/" + shared_with_me) != std::string::npos || dst.find("/" + shared_with_me) != std::string::npos)
return 0;
std::string id = GetValue(path_id_map, src);
std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id);
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"))
@@ -194,7 +233,7 @@ int GDriveClient::Rename(const std::string &src, const std::string &dst)
if (HTTP_SUCCESS(res->status))
{
path_id_map.erase(src);
path_id_map.insert(std::make_pair(dst, id));
path_id_map.insert(std::make_pair(dst, src_id));
}
else
return 0;
@@ -235,7 +274,11 @@ 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,
@@ -244,7 +287,7 @@ int GDriveClient::Head(const std::string &path, void *buffer, uint64_t len)
body.insert(body.end(), data, data + data_length);
bytes_read += data_length;
if (bytes_read > len)
return false;
return false;
return true;
}))
{
@@ -266,7 +309,10 @@ int GDriveClient::Get(const std::string &outputfile, const std::string &path, ui
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)
{
@@ -285,6 +331,41 @@ int GDriveClient::Get(const std::string &outputfile, const std::string &path, ui
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);
@@ -294,8 +375,11 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
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)));
@@ -352,7 +436,7 @@ int GDriveClient::Update(const std::string &inputfile, const std::string &path)
int GDriveClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset)
{
if (path.find(shared_with_me) != std::string::npos)
if (path.find("/" + shared_with_me) != std::string::npos || path.compare("/") == 0)
return 0;
if (FileExists(path))
@@ -373,9 +457,15 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
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";
std::string post_data = std::string("{'name': '") + filename + "', 'parents': ['" + parent_id + "']}";
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)));
@@ -433,7 +523,10 @@ int GDriveClient::Put(const std::string &inputfile, const std::string &path, uin
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);
@@ -455,9 +548,9 @@ int GDriveClient::Size(const std::string &path, int64_t *size)
int GDriveClient::Mkdir(const std::string &path)
{
if (path.find(shared_with_me) != std::string::npos)
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;
@@ -471,6 +564,7 @@ int GDriveClient::Mkdir(const std::string &path)
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())
@@ -480,8 +574,11 @@ int GDriveClient::Mkdir(const std::string &path)
}
std::string url = std::string("/drive/v3/files?fields=id");
if (!drive_id.empty())
url += "&supportsAllDrives=true";
std::string folder_metadata = "{'name' : '" + folder_name + "'," +
"'parents' : ['" + parent_id + "']," +
(drive_id.empty() ? "" : "'driveId' : '" + drive_id + "',") +
"'mimeType' : 'application/vnd.google-apps.folder'}";
if (auto res = client->Post(url, folder_metadata.c_str(), folder_metadata.length(), "application/json; charset=UTF-8"))
@@ -510,9 +607,15 @@ int GDriveClient::Mkdir(const std::string &path)
*/
int GDriveClient::Rmdir(const std::string &path, bool recursive)
{
if (path.find(shared_with_me) != std::string::npos)
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)
{
@@ -533,10 +636,13 @@ int GDriveClient::Rmdir(const std::string &path, bool recursive)
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))
@@ -567,6 +673,18 @@ void SetupSharedWithMeFolder(DirEntry *entry)
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;
@@ -578,11 +696,67 @@ std::vector<DirEntry> GDriveClient::ListDir(const std::string &path)
{
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");
"&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)
{
+3
View File
@@ -19,6 +19,7 @@ public:
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);
@@ -38,7 +39,9 @@ public:
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 -1
View File
@@ -81,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());
+1
View File
@@ -48,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;
+610
View File
@@ -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, &lt);
entry.modified.day = lt.day;
entry.modified.month = lt.month;
entry.modified.year = lt.year;
entry.modified.hours = lt.hour;
entry.modified.minutes = lt.minute;
entry.modified.seconds = lt.second;
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;
}
+47
View File
@@ -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
+26 -2
View File
@@ -16,8 +16,6 @@
#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]);
+1
View File
@@ -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);
+15 -2
View File
@@ -14,8 +14,6 @@
#include "util.h"
#include "system.h"
#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y))
static const char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
namespace WebDAV
@@ -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
*
+1
View File
@@ -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);
+2
View File
@@ -6,6 +6,8 @@
#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
{
+26 -6
View File
@@ -28,12 +28,15 @@ 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'};
@@ -79,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;
}
@@ -141,6 +144,8 @@ namespace CONFIG
"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};
text_file_extensions = { ".txt", ".ini", ".log", ".json", ".xml", ".html", ".xhtml", ".conf", ".config" };
image_file_extensions = { ".bmp", ".jpg", ".jpeg", ".png", ".webp" };
OpenIniFile(CONFIG_INI_FILE);
@@ -159,15 +164,15 @@ 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);
@@ -214,7 +219,7 @@ 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);
char tmp_password[64];
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)
@@ -238,6 +243,9 @@ 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);
@@ -280,6 +288,8 @@ 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++)
{
const char *index = std::to_string(i).c_str();
@@ -305,8 +315,9 @@ namespace CONFIG
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);
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
std::string encrypted_token;
if (strlen(remote_settings->gg_account.access_token) > 0)
Encrypt(remote_settings->gg_account.access_token, encrypted_token);
@@ -338,6 +349,15 @@ namespace CONFIG
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();
}
+12 -2
View File
@@ -6,6 +6,7 @@
#include <string>
#include <algorithm>
#include <map>
#include <set>
#include "clients/remote_client.h"
@@ -14,9 +15,13 @@
#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"
@@ -47,6 +52,7 @@
#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
@@ -59,7 +65,6 @@
#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"
@@ -89,13 +94,14 @@ struct RemoteSettings
char site_name[32];
char server[256];
char username[33];
char password[64];
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
@@ -107,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];
@@ -123,12 +131,14 @@ 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);
}
+4 -8
View File
@@ -131,28 +131,24 @@ 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(), "r");
FILE *fd = fopen(path.c_str(), "rb");
if (fd == nullptr)
return false;
+1 -1
View File
@@ -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
+167 -11
View File
@@ -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)
@@ -339,7 +347,8 @@ namespace INSTALLER
FS::Rm(filename);
}
}
else if (ret > 0) goto err;
else if (ret > 0)
goto err;
ret = sceBgftServiceDownloadStartTask(task_id);
if (ret)
@@ -373,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
View File
@@ -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);
}
+8 -1
View File
@@ -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
@@ -150,6 +150,13 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
"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;
+9 -2
View File
@@ -141,7 +141,14 @@
FUNC(STR_CLIENT_ID) \
FUNC(STR_CLIENT_SECRET) \
FUNC(STR_GLOBAL) \
FUNC(STR_GOOGLE)
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,
@@ -151,7 +158,7 @@ enum
FOREACH_STR(GET_VALUE)
};
#define LANG_STRINGS_NUM 138
#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];
+12 -3
View File
@@ -25,6 +25,7 @@
#include "util.h"
#include "installer.h"
#include "system.h"
#include "textures.h"
extern "C"
{
@@ -99,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
@@ -127,6 +128,12 @@ void InitImgui()
0,
};
static const ImWchar of_icons[] {
0xE0CB, 0xE0CB, // square
0xE0DE, 0xE0DE, // triangle
0,
};
std::string lang = std::string(language);
int32_t lang_idx;
sceSystemServiceParamGetInt( ORBIS_SYSTEM_SERVICE_PARAM_ID_LANG, &lang_idx );
@@ -177,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();
@@ -301,13 +309,13 @@ 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())
{
@@ -322,6 +330,7 @@ int main()
GUI::RenderLoop(renderer);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
Textures::Exit();
ImGui::DestroyContext();
+64
View File
@@ -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;
}
}
+34
View File
@@ -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
+52
View File
@@ -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;
}
}
}
+21
View File
@@ -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
+333 -48
View File
@@ -3,6 +3,8 @@
#include <stdio.h>
#include <algorithm>
#include <set>
#include "clients/gdrive.h"
#include "server/http_server.h"
#include "imgui.h"
#include "windows.h"
#include "fs.h"
@@ -13,8 +15,12 @@
#include "lang.h"
#include "ime_dialog.h"
#include "IconsFontAwesome6.h"
#include "server/http_server.h"
#include "clients/gdrive.h"
#include "OpenFontIcons.h"
#include "textures.h"
#include "sfo.h"
#define MAX_IMAGE_HEIGHT 980
#define MAX_IMAGE_WIDTH 1820
extern "C"
{
@@ -77,6 +83,14 @@ char label[256];
bool editor_modified = false;
char edit_file[256];
int edit_line_to_select = -1;
std::string copy_text;
// Images varaibles
bool view_image= false;
Tex texture;
bool show_pkg_info = false;
std::map<std::string, std::string> sfo_params;
// Overwrite dialog variables
bool dont_prompt_overwrite = false;
@@ -123,7 +137,7 @@ namespace Windows
cur_down[SDL_CONTROLLER_BUTTON_X] = SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_X);
cur_down[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
cur_down[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] = SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
cur_down[SDL_CONTROLLER_BUTTON_START] = SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_START);
cur_down[SDL_CONTROLLER_BUTTON_BACK] = SDL_GameControllerGetButton(game_controller, SDL_CONTROLLER_BUTTON_BACK);
if (prev_down[SDL_CONTROLLER_BUTTON_X] && !cur_down[SDL_CONTROLLER_BUTTON_X] && !paused)
{
@@ -163,7 +177,7 @@ namespace Windows
set_focus_to_local = true;
}
if (prev_down[SDL_CONTROLLER_BUTTON_START] && !cur_down[SDL_CONTROLLER_BUTTON_START] && !paused)
if (prev_down[SDL_CONTROLLER_BUTTON_BACK] && !cur_down[SDL_CONTROLLER_BUTTON_BACK] && !paused)
{
selected_action = ACTION_DISCONNECT_AND_EXIT;
}
@@ -171,7 +185,7 @@ namespace Windows
prev_down[SDL_CONTROLLER_BUTTON_X] = cur_down[SDL_CONTROLLER_BUTTON_X];
prev_down[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] = cur_down[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER];
prev_down[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] = cur_down[SDL_CONTROLLER_BUTTON_LEFTSHOULDER];
prev_down[SDL_CONTROLLER_BUTTON_START] = cur_down[SDL_CONTROLLER_BUTTON_START];
prev_down[SDL_CONTROLLER_BUTTON_BACK] = cur_down[SDL_CONTROLLER_BUTTON_BACK];
}
void SetModalMode(bool modal)
@@ -304,6 +318,7 @@ namespace Windows
sprintf(last_site, "%s", sites[n].c_str());
sprintf(display_site, "%s", site_id);
remote_settings = &site_settings[sites[n]];
sprintf(remote_directory, "%s", remote_settings->default_directory);
sprintf(txt_http_port, "%d", remote_settings->http_port);
}
@@ -393,9 +408,9 @@ namespace Windows
{
ime_single_field = remote_settings->password;
ResetImeCallbacks();
ime_field_size = 24;
ime_field_size = 127;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_PASSWORD], remote_settings->password, 24, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y);
Dialog::initImeDialog(lang_strings[STR_PASSWORD], remote_settings->password, 127, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y);
gui_mode = GUI_MODE_IME;
}
@@ -564,11 +579,32 @@ namespace Windows
}
if (ImGui::Selectable(item.name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(919, 0)))
{
selected_local_file = item;
if (item.isDir)
{
selected_local_file = item;
selected_action = ACTION_CHANGE_LOCAL_DIRECTORY;
}
else
{
std::string filename = Util::ToLower(selected_local_file.name);
size_t dot_pos = filename.find_last_of(".");
if (dot_pos != std::string::npos)
{
std::string ext = filename.substr(dot_pos);
if (image_file_extensions.find(ext) != image_file_extensions.end())
{
selected_action = ACTION_VIEW_LOCAL_IMAGE;
}
else if (text_file_extensions.find(ext) != text_file_extensions.end())
{
selected_action = ACTION_LOCAL_EDIT;
}
else if (ext.compare(".pkg") == 0)
{
selected_action = ACTION_VIEW_LOCAL_PKG;
}
}
}
}
ImGui::PopID();
if (ImGui::IsItemFocused())
@@ -709,11 +745,32 @@ namespace Windows
ImGui::PushID(i);
if (ImGui::Selectable(item.name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(919, 0)))
{
selected_remote_file = item;
if (item.isDir)
{
selected_remote_file = item;
selected_action = ACTION_CHANGE_REMOTE_DIRECTORY;
}
else
{
std::string filename = Util::ToLower(selected_remote_file.name);
size_t dot_pos = filename.find_last_of(".");
if (dot_pos != std::string::npos)
{
std::string ext = filename.substr(dot_pos);
if (image_file_extensions.find(ext) != image_file_extensions.end())
{
selected_action = ACTION_VIEW_REMOTE_IMAGE;
}
else if (text_file_extensions.find(ext) != text_file_extensions.end())
{
selected_action = ACTION_REMOTE_EDIT;
}
else if (ext.compare(".pkg") == 0)
{
selected_action = ACTION_VIEW_REMOTE_PKG;
}
}
}
}
if (ImGui::IsItemFocused())
{
@@ -801,7 +858,7 @@ namespace Windows
ImVec4 *colors = style->Colors;
int flags;
if (ImGui::IsKeyDown(ImGuiKey_GamepadFaceUp))
if (ImGui::IsKeyDown(ImGuiKey_GamepadFaceUp) && !paused)
{
if (!paused)
saved_selected_browser = selected_browser;
@@ -817,13 +874,13 @@ namespace Windows
bool remote_browser_selected = saved_selected_browser & REMOTE_BROWSER;
if (local_browser_selected)
{
ImGui::SetNextWindowPos(ImVec2(410, 280));
ImGui::SetNextWindowPos(ImVec2(410, 250));
}
else if (remote_browser_selected)
{
ImGui::SetNextWindowPos(ImVec2(1330, 280));
ImGui::SetNextWindowPos(ImVec2(1330, 250));
}
ImGui::SetNextWindowSizeConstraints(ImVec2(230, 150), ImVec2(230, 625), NULL, NULL);
ImGui::SetNextWindowSizeConstraints(ImVec2(230, 150), ImVec2(230, 660), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_ACTIONS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::PushID("Select All##settings");
@@ -938,6 +995,19 @@ namespace Windows
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("setdefaultfolder##settings");
if (ImGui::Selectable(lang_strings[STR_SET_DEFAULT_DIRECTORY], false, ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
if (local_browser_selected)
selected_action = ACTION_SET_DEFAULT_LOCAL_FOLDER;
else if (remote_browser_selected)
selected_action = ACTION_SET_DEFAULT_REMOTE_FOLDER;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::PopID();
ImGui::Separator();
ImGui::PushID("New Folder##settings");
flags = ImGuiSelectableFlags_None;
if (remote_browser_selected && remoteclient != nullptr && !(remoteclient->SupportedActions() & REMOTE_ACTION_NEW_FOLDER))
@@ -983,32 +1053,14 @@ namespace Windows
}
if (ImGui::Selectable(lang_strings[STR_EDIT], false, flags | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
{
bool can_edit = true;
if (local_browser_selected)
{
if (selected_local_file.file_size > max_edit_file_size)
can_edit = false;
else
{
snprintf(edit_file, 255, "%s", selected_local_file.path);
FS::LoadText(&edit_buffer, selected_local_file.path);
}
selected_action = ACTION_LOCAL_EDIT;
}
else
{
if (selected_remote_file.file_size > max_edit_file_size)
can_edit = false;
else if (remoteclient != nullptr && remoteclient->Get(TMP_EDITOR_FILE, selected_remote_file.path))
{
snprintf(edit_file, 255, "%s", selected_remote_file.path);
FS::LoadText(&edit_buffer, TMP_EDITOR_FILE);
}
selected_action = ACTION_REMOTE_EDIT;
}
if (can_edit)
editor_inprogress = true;
else
sprintf(status_message, "%s %d", lang_strings[STR_MAX_EDIT_FILE_SIZE_MSG], max_edit_file_size);
editor_modified = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
@@ -1057,7 +1109,7 @@ namespace Windows
ImGui::Separator();
flags = getSelectableFlag(REMOTE_ACTION_UPLOAD);
if (remote_browser_selected && remoteclient != nullptr && !(remoteclient->SupportedActions() & REMOTE_ACTION_UPLOAD))
if (local_browser_selected && remoteclient != nullptr && !(remoteclient->SupportedActions() & REMOTE_ACTION_UPLOAD))
{
flags = ImGuiSelectableFlags_Disabled;
}
@@ -1144,6 +1196,13 @@ namespace Windows
{
ImGui::SetItemDefaultFocus();
}
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
{
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
@@ -1519,6 +1578,15 @@ namespace Windows
editor_modified = true;
edit_line_to_select = j;
}
else if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceLeft, false))
{
copy_text = std::string(it->c_str());
}
else if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceUp, false))
{
it->clear();
it->append(copy_text);
}
}
j++;
}
@@ -1534,7 +1602,9 @@ namespace Windows
ImGui::Text("%s%s", (editor_modified ? "**" : ""), edit_file);
ImGui::Separator();
ImGui::Text("L1 - %s R1 - %s", lang_strings[STR_DELETE_LINE], lang_strings[STR_INSERT_LINE]);
ImGui::Text("L1 - %s R1 - %s %s - %s %s - %s", lang_strings[STR_DELETE_LINE], lang_strings[STR_INSERT_LINE],
ICON_OF_SQUARE, lang_strings[STR_COPY_LINE], ICON_OF_TRIANGLE, lang_strings[STR_PASTE_LINE]);
ImGui::EndPopup();
}
}
@@ -1552,8 +1622,8 @@ namespace Windows
SetModalMode(true);
ImGui::OpenPopup(lang_strings[STR_SETTINGS]);
ImGui::SetNextWindowPos(ImVec2(1150, 80));
ImGui::SetNextWindowSizeConstraints(ImVec2(750, 80), ImVec2(750, 400), NULL, NULL);
ImGui::SetNextWindowPos(ImVec2(1050, 80));
ImGui::SetNextWindowSizeConstraints(ImVec2(850, 80), ImVec2(850, 400), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]);
@@ -1561,48 +1631,62 @@ namespace Windows
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_AUTO_DELETE_TMP_PKG]);
ImGui::SameLine();
ImGui::SetCursorPosX(705);
ImGui::SetCursorPosX(805);
ImGui::Checkbox("##auto_delete_tmp_pkg", &auto_delete_tmp_pkg);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_SHOW_HIDDEN_FILES]);
ImGui::SameLine();
ImGui::SetCursorPosX(805);
ImGui::Checkbox("##show_hidden_files", &show_hidden_files);
ImGui::Separator();
ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GOOGLE]);
ImGui::Separator();
ImVec2 id_size, secret_size;
id_size = ImGui::CalcTextSize(lang_strings[STR_CLIENT_ID]);
secret_size = ImGui::CalcTextSize(lang_strings[STR_CLIENT_SECRET]);
float width = MAX(id_size.x, secret_size.x) + 45;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_CLIENT_ID]);
ImGui::SameLine();
ImGui::SetCursorPosX(163);
ImGui::SetCursorPosX(width);
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
if (ImGui::Button(gg_app.client_id, ImVec2(580, 0)))
char id[192];
sprintf(id, "%s##client_id_input", gg_app.client_id);
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = gg_app.client_id;
ime_field_size = 139;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_CLIENT_ID], gg_app.client_id, 139, ORBIS_TYPE_BASIC_LATIN, 1150, 80);
Dialog::initImeDialog(lang_strings[STR_CLIENT_ID], gg_app.client_id, 139, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_CLIENT_SECRET]);
ImGui::SameLine();
char id[128];
ImGui::SetCursorPosX(163);
ImGui::SetCursorPosX(width);
if (strlen(gg_app.client_secret) > 0)
sprintf(id, "%s", "*********************************************##client_secret_input");
else
sprintf(id, "%s", "##client_secret_input");
if (ImGui::Button(id, ImVec2(580, 0)))
if (ImGui::Button(id, ImVec2(835-width, 0)))
{
ResetImeCallbacks();
ime_single_field = gg_app.client_secret;
ime_field_size = 63;
ime_callback = SingleValueImeCallback;
Dialog::initImeDialog(lang_strings[STR_CLIENT_SECRET], gg_app.client_secret, 63, ORBIS_TYPE_BASIC_LATIN, 1150, 80);
Dialog::initImeDialog(lang_strings[STR_CLIENT_SECRET], gg_app.client_secret, 63, ORBIS_TYPE_BASIC_LATIN, 1050, 80);
gui_mode = GUI_MODE_IME;
}
ImGui::PopStyleVar();
ImGui::Separator();
sprintf(id, "%s##settings", lang_strings[STR_CLOSE]);
if (ImGui::Button(id, ImVec2(735, 0)))
if (ImGui::Button(id, ImVec2(835, 0)))
{
show_settings = false;
CONFIG::SaveGlobalConfig();
@@ -1614,6 +1698,130 @@ namespace Windows
ImGui::SetItemDefaultFocus();
}
ImGui::SameLine();
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
{
show_settings = false;
CONFIG::SaveGlobalConfig();
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
}
void ShowImageDialog()
{
if (view_image)
{
ImGuiIO &io = ImGui::GetIO();
(void)io;
ImGuiStyle *style = &ImGui::GetStyle();
ImVec4 *colors = style->Colors;
ImVec2 image_size;
ImVec2 image_pos;
ImVec2 view_size;
image_size.x = texture.width;
image_size.y = texture.height;
if (texture.width > MAX_IMAGE_WIDTH || texture.height > MAX_IMAGE_HEIGHT)
{
if (texture.width > texture.height)
{
image_size.x = MAX_IMAGE_WIDTH;
image_size.y = (texture.height * 1.0f / texture.width * 1.0f) * MAX_IMAGE_WIDTH;
}
else
{
image_size.y = MAX_IMAGE_HEIGHT;
image_size.x = (texture.width * 1.0f / texture.height * 1.0f) * MAX_IMAGE_HEIGHT;
}
}
view_size.x = image_size.x + 50;
view_size.y = image_size.y + 50;
image_pos.x = (1920 - view_size.x) / 2;
image_pos.y = (1080 - view_size.y) / 2;
SetModalMode(true);
ImGui::OpenPopup(lang_strings[STR_VIEW_IMAGE]);
ImGui::SetNextWindowPos(image_pos);
ImGui::SetNextWindowSizeConstraints(image_size, view_size, NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_VIEW_IMAGE], NULL, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Image(texture.id, image_size);
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
{
view_image = false;
SetModalMode(false);
Textures::Free(&texture);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
}
void ShowPackageInfoDialog()
{
if (!paused)
saved_selected_browser = selected_browser;
if (show_pkg_info)
{
ImGuiIO &io = ImGui::GetIO();
(void)io;
ImGuiStyle *style = &ImGui::GetStyle();
ImVec4 *colors = style->Colors;
SetModalMode(true);
ImGui::OpenPopup(lang_strings[STR_VIEW_PKG_INFO]);
ImGui::SetNextWindowPos(ImVec2(360, 240));
ImGui::SetNextWindowSizeConstraints(ImVec2(1200, 300), ImVec2(1200, 600), NULL, NULL);
if (ImGui::BeginPopupModal(lang_strings[STR_VIEW_PKG_INFO], NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Image(texture.id, ImVec2(400, 400));
ImGui::SameLine();
BeginGroupPanel("SFO Attributes", ImVec2(780, 600));
ImGui::PushTextWrapPos(1180);
for (std::map<std::string, std::string>::iterator it = sfo_params.begin(); it != sfo_params.end(); ++it)
{
if (!it->second.empty())
{
ImGui::TextColored(colors[ImGuiCol_ButtonHovered],"%s:", it->first.c_str());
ImGui::SameLine();
ImGui::Text("%s", it->second.c_str());
}
}
ImGui::PopTextWrapPos();
EndGroupPanel();
if (saved_selected_browser & REMOTE_BROWSER ||
(saved_selected_browser & LOCAL_BROWSER && (strncmp(selected_local_file.path, "/data/", 6) == 0 || strncmp(selected_local_file.path, "/mnt/usb", 8) == 0)))
{
ImGui::SetCursorPos(ImVec2(7, 420));
if (ImGui::Button(lang_strings[STR_INSTALL], ImVec2(400, 0)))
{
if (saved_selected_browser & REMOTE_BROWSER)
selected_action = ACTION_INSTALL_REMOTE_PKG;
else
selected_action = ACTION_INSTALL_LOCAL_PKG;
show_pkg_info = false;
SetModalMode(false);
ImGui::CloseCurrentPopup();
}
}
if (ImGui::IsKeyPressed(ImGuiKey_GamepadFaceRight, false))
{
show_pkg_info = false;
SetModalMode(false);
Textures::Free(&texture);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
@@ -1638,12 +1846,15 @@ namespace Windows
ShowFavoriteUrlsDialog();
ShowEditorDialog();
ShowSettingsDialog();
ShowImageDialog();
ShowPackageInfoDialog();
}
ImGui::End();
}
void ExecuteActions()
{
std::vector<char> sfo;
switch (selected_action)
{
case ACTION_CHANGE_LOCAL_DIRECTORY:
@@ -1679,8 +1890,8 @@ namespace Windows
ime_after_update = AfterFolderNameCallback;
ime_cancelled = CancelActionCallBack;
ime_callback = SingleValueImeCallback;
ImVec2 pos = selected_action == ACTION_NEW_LOCAL_FOLDER ? ImVec2(410, 350) : ImVec2(1330, 350);
Dialog::initImeDialog(lang_strings[STR_NEW_FOLDER], dialog_editor_text, 128, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y);
ImVec2 pos = (selected_action == ACTION_NEW_LOCAL_FOLDER || selected_action == ACTION_NEW_LOCAL_FILE) ? ImVec2(410, 350) : ImVec2(1330, 350);
Dialog::initImeDialog((selected_action == ACTION_NEW_LOCAL_FILE || selected_action == ACTION_NEW_REMOTE_FILE)? lang_strings[STR_NEW_FILE]: lang_strings[STR_NEW_FOLDER], dialog_editor_text, 128, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y);
gui_mode = GUI_MODE_IME;
}
break;
@@ -1703,6 +1914,7 @@ namespace Windows
if (dont_prompt_overwrite || (!dont_prompt_overwrite && confirm_transfer_state == 1))
{
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
Actions::UploadFiles();
confirm_transfer_state = -1;
@@ -1714,6 +1926,7 @@ namespace Windows
if (dont_prompt_overwrite || (!dont_prompt_overwrite && confirm_transfer_state == 1))
{
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
Actions::DownloadFiles();
confirm_transfer_state = -1;
@@ -1723,6 +1936,7 @@ namespace Windows
case ACTION_EXTRACT_LOCAL_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = true;
selected_action = ACTION_NONE;
@@ -1731,6 +1945,7 @@ namespace Windows
case ACTION_CREATE_LOCAL_ZIP:
sprintf(status_message, "%s", "");
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
file_transfering = true;
selected_action = ACTION_NONE;
@@ -1858,6 +2073,7 @@ namespace Windows
if (dont_prompt_overwrite || (!dont_prompt_overwrite && confirm_transfer_state == 1))
{
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
confirm_transfer_state = -1;
if (paste_action == ACTION_LOCAL_CUT)
@@ -1877,6 +2093,7 @@ namespace Windows
if (dont_prompt_overwrite || (!dont_prompt_overwrite && confirm_transfer_state == 1))
{
activity_inprogess = true;
sprintf(activity_message, "%s", "");
stop_activity = false;
confirm_transfer_state = -1;
if (paste_action == ACTION_REMOTE_CUT)
@@ -1890,6 +2107,74 @@ namespace Windows
selected_action = ACTION_NONE;
}
break;
case ACTION_SET_DEFAULT_LOCAL_FOLDER:
CONFIG::SaveLocalDirecotry(local_directory);
sprintf(status_message, "\"%s\" %s", local_directory, lang_strings[STR_SET_DEFAULT_DIRECTORY_MSG]);
selected_action = ACTION_NONE;
break;
case ACTION_SET_DEFAULT_REMOTE_FOLDER:
sprintf(remote_settings->default_directory, "%s", remote_directory);
CONFIG::SaveConfig();
sprintf(status_message, "\"%s\" %s", remote_directory, lang_strings[STR_SET_DEFAULT_DIRECTORY_MSG]);
selected_action = ACTION_NONE;
break;
case ACTION_VIEW_LOCAL_IMAGE:
if (Textures::LoadImageFile(selected_local_file.path, &texture))
{
view_image = true;
}
selected_action = ACTION_NONE;
break;
case ACTION_VIEW_REMOTE_IMAGE:
remoteclient->Get(TMP_ICON_PATH, selected_remote_file.path);
if (Textures::LoadImageFile(TMP_ICON_PATH, &texture))
{
view_image = true;
}
selected_action = ACTION_NONE;
break;
case ACTION_LOCAL_EDIT:
if (selected_local_file.file_size > max_edit_file_size)
sprintf(status_message, "%s %d", lang_strings[STR_MAX_EDIT_FILE_SIZE_MSG], max_edit_file_size);
else
{
snprintf(edit_file, 255, "%s", selected_local_file.path);
FS::LoadText(&edit_buffer, selected_local_file.path);
editor_inprogress = true;
}
editor_modified = false;
selected_action = ACTION_NONE;
break;
case ACTION_REMOTE_EDIT:
if (selected_remote_file.file_size > max_edit_file_size)
sprintf(status_message, "%s %d", lang_strings[STR_MAX_EDIT_FILE_SIZE_MSG], max_edit_file_size);
else if (remoteclient != nullptr && remoteclient->Get(TMP_EDITOR_FILE, selected_remote_file.path))
{
snprintf(edit_file, 255, "%s", selected_remote_file.path);
FS::LoadText(&edit_buffer, TMP_EDITOR_FILE);
editor_inprogress = true;
}
editor_modified = false;
selected_action = ACTION_NONE;
break;
case ACTION_VIEW_LOCAL_PKG:
INSTALLER::ExtractLocalPkg(selected_local_file.path, TMP_SFO_PATH, TMP_ICON_PATH);
Textures::LoadImageFile(TMP_ICON_PATH, &texture);
sfo = FS::Load(TMP_SFO_PATH);
sfo_params = SFO::GetParams(sfo.data(), sfo.size());
show_pkg_info = true;
selected_action = ACTION_NONE;
break;
case ACTION_VIEW_REMOTE_PKG:
if (INSTALLER::ExtractRemotePkg(selected_remote_file.path, TMP_SFO_PATH, TMP_ICON_PATH))
{
Textures::LoadImageFile(TMP_ICON_PATH, &texture);
sfo = FS::Load(TMP_SFO_PATH);
sfo_params = SFO::GetParams(sfo.data(), sfo.size());
show_pkg_info = true;
}
selected_action = ACTION_NONE;
break;
default:
break;
}