Compare commits

..

22 Commits

Author SHA1 Message Date
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
10 changed files with 684 additions and 22 deletions
+3 -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
@@ -57,7 +58,7 @@ add_executable(ezremote_client
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.04" 32 0)
target_link_libraries(ezremote_client
c
@@ -77,6 +78,7 @@ target_link_libraries(ezremote_client
un7zip
unrar
json-c
ssh2
kernel
SceShellCoreUtil
SceSysmodule
+20 -5
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://"**
```
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,16 @@ 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.
- 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.
## Installation
Copy the **ezremote_client.pkg** in to a FAT32 format usb drive then install from package installer
@@ -167,6 +178,10 @@ Build libunrar - https://github.com/cy33hc/libunrar-ps3
Build libun7zip - https://github.com/cy33hc/libun7zip
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
+3 -1
View File
@@ -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,5 @@ 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
+10 -4
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]);
@@ -1180,6 +1185,7 @@ namespace Actions
remote_files.clear();
sprintf(remote_directory, "%s", "/");
sprintf(status_message, "%s", "");
delete remoteclient;
remoteclient = nullptr;
}
}
@@ -1269,7 +1275,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 +1290,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 +1539,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)
{
+584
View File
@@ -0,0 +1,584 @@
#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::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;
;
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;
}
+46
View File
@@ -0,0 +1,46 @@
#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 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
+2 -2
View File
@@ -79,7 +79,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;
}
@@ -214,7 +214,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)
+1 -1
View File
@@ -89,7 +89,7 @@ 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;
+1 -1
View File
@@ -152,7 +152,7 @@ namespace FS
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;
+14 -7
View File
@@ -393,9 +393,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;
}
@@ -801,7 +801,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;
@@ -1571,7 +1571,9 @@ namespace Windows
ImGui::SameLine();
ImGui::SetCursorPosX(163);
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(580, 0)))
{
ResetImeCallbacks();
ime_single_field = gg_app.client_id;
@@ -1584,7 +1586,6 @@ namespace Windows
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15);
ImGui::Text("%s", lang_strings[STR_CLIENT_SECRET]);
ImGui::SameLine();
char id[128];
ImGui::SetCursorPosX(163);
if (strlen(gg_app.client_secret) > 0)
sprintf(id, "%s", "*********************************************##client_secret_input");
@@ -1679,8 +1680,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 +1704,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 +1716,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 +1726,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 +1735,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 +1863,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 +1883,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)