diff --git a/CMakeLists.txt b/CMakeLists.txt index 15c5477..b2dae6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,16 +28,20 @@ add_executable(ezremote_client source/web/urn.cpp source/webdav/client.cpp source/http/httplib.cpp - source/http/baseclient.cpp - source/http/apache.cpp - source/http/iis.cpp - source/http/nginx.cpp - source/http/npxserve.cpp + source/clients/baseclient.cpp + source/clients/apache.cpp + source/clients/ftpclient.cpp + source/clients/gdrive.cpp + source/clients/iis.cpp + source/clients/nginx.cpp + source/clients/npxserve.cpp + source/clients/smbclient.cpp + source/clients/webdavclient.cpp + source/server/http_server.cpp source/actions.cpp source/config.cpp source/crypt.c source/fs.cpp - source/ftpclient.cpp source/gui.cpp source/getentropy.c source/ime_dialog.cpp @@ -46,10 +50,8 @@ add_executable(ezremote_client source/lang.cpp source/main.cpp source/orbis_jbc.c - source/sys_modules.cpp - source/smbclient.cpp + source/system.cpp source/windows.cpp - source/webdavclient.cpp source/zip_util.cpp ) @@ -58,7 +60,6 @@ add_self(ezremote_client) add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.02" 32 0) target_link_libraries(ezremote_client - dbglogger c c++ png @@ -75,6 +76,7 @@ target_link_libraries(ezremote_client minizip un7zip unrar + json-c kernel SceShellCoreUtil SceSysmodule diff --git a/data/assets/certs/domain.crt b/data/assets/certs/domain.crt new file mode 100644 index 0000000..a588daa --- /dev/null +++ b/data/assets/certs/domain.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIUSlUxeW2iMsLD8Lk3+ffGUfxej6QwDQYJKoZIhvcNAQEL +BQAwYzELMAkGA1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQ +MA4GA1UECgwHTWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxv +Y2FsaG9zdDAgFw0yMzAyMjUwNzAyMTNaGA8yMDUzMDIxNzA3MDIxM1owYzELMAkG +A1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQMA4GA1UECgwH +TWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxvY2FsaG9zdDCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOWQx+pfhpDqd2wPkV5BL6Yf +8UVTCsP13+1YlxZiD93VHhcK23T/YYqSxx6tDHAR4sA/oKELT+dFuhMhC/QE5Sw6 +HD/FwCwdNJ7Ke3z+iUActtInDU5URC0XwdW7wTAt1MLx4T9j7CkoVHsaiDlf6LTG +165bIXD8JKzud26WXHmTCCBCgIU3zcq13jpFeb4Po4rJtuDLwb3gloZzEzdS9S6O +mjVNUSlZeb+ksep3TbJHIACy6WrPJZ+u2aScDOBOt9Gv/UeOYHcvGIFHXddG+kHl +/ay6b7JxNbBNWL57/PswmXcpB16gkBNWCfL1PDmDFEkvd6uJTnPUnMge7CBNzX8C +AwEAAaNSMFAwHwYDVR0jBBgwFoAUeCZ0CXLAs8C5xVsPGIhzu4haXpEwCQYDVR0T +BAIwADAiBgNVHREEGzAZgglsb2NhbGhvc3SCCTEyNy4wLjAuMYIBKjANBgkqhkiG +9w0BAQsFAAOCAQEAsgC/89C7+OAspaOgU5Tr9WFcZ1Nph21WTltBM0z9f4NyeR1Y +b/YoJrvocRWw9gpgCcj7AArSHNsha2+QMBEko3PIpkdMoSHylf2WqYNTCIb8cvJA +pHDYJJR99Cajo0meP5h1mtQdjOVv70Q3jtS6iSdD/KI5VwIRcfDutjHys78Bb2NQ +1KEZuHKwmhE3209OQ5ZbjDQ0gViJFPnfPfnbWuOllpIN27ZwGvlhhM9x7xRvwsWt +puh5wV2TBAYagOT+canBOxugv7L1eOpnNVE49YS0vr5y8JhLuKFoZ0hTi7PeqO4c +mE4zIVwKjIQ6w+N2Vj/ghNjkyJm0azpmnbPtFg== +-----END CERTIFICATE----- diff --git a/data/assets/certs/domain.csr b/data/assets/certs/domain.csr new file mode 100644 index 0000000..db2dcf3 --- /dev/null +++ b/data/assets/certs/domain.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICqDCCAZACAQAwYzELMAkGA1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UE +BwwETW9vbjEQMA4GA1UECgwHTWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQ +BgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AOWQx+pfhpDqd2wPkV5BL6Yf8UVTCsP13+1YlxZiD93VHhcK23T/YYqSxx6tDHAR +4sA/oKELT+dFuhMhC/QE5Sw6HD/FwCwdNJ7Ke3z+iUActtInDU5URC0XwdW7wTAt +1MLx4T9j7CkoVHsaiDlf6LTG165bIXD8JKzud26WXHmTCCBCgIU3zcq13jpFeb4P +o4rJtuDLwb3gloZzEzdS9S6OmjVNUSlZeb+ksep3TbJHIACy6WrPJZ+u2aScDOBO +t9Gv/UeOYHcvGIFHXddG+kHl/ay6b7JxNbBNWL57/PswmXcpB16gkBNWCfL1PDmD +FEkvd6uJTnPUnMge7CBNzX8CAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQB2gc2Z +7bzytAja4uDQQjQOxZMzwwgfODyQTWhvyEVJxq7iK8Saogn/dpjgeVhNaIgMAGRs +RNQ26cBQxvs9ZfNmNcNvc1eFw9NJicRpHOUjNf0mMHtqiFIpGc9Fnu34p1DLGKJ4 +qp5Kd9cl4Vx96xaPWqCyH+sXFxnIt8lK6K0yKHaDXLKzFmuJvEEc2Z/g0/RRfgq7 +cO9+otlsD3sF6TziNL/KFFYPqgn4Wkx8K8z9ovpMnyvYH1KnQsuhCNr9nUhmA8Wu +o9DMKQbqDYq9NLUmTJMgX75Vi71idbkgOZN7kvmUnEW+Ltf1FLl9AnF5kpkvMTvR +KIcPUOLLdpzwZ8jc +-----END CERTIFICATE REQUEST----- diff --git a/data/assets/certs/domain.ext b/data/assets/certs/domain.ext new file mode 100644 index 0000000..f8dc364 --- /dev/null +++ b/data/assets/certs/domain.ext @@ -0,0 +1,7 @@ +authorityKeyIdentifier=keyid,issuer +basicConstraints=CA:FALSE +subjectAltName = @alt_names +[alt_names] +DNS.1 = localhost +DNS.2 = 127.0.0.1 +DNS.3 = * diff --git a/data/assets/certs/domain.key b/data/assets/certs/domain.key new file mode 100644 index 0000000..cad8069 --- /dev/null +++ b/data/assets/certs/domain.key @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIDkuJpr20dpYCAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECAKW47FhDo5vBIIEyNJd7CLIboON +iXmQ5Vzj7nHna+HXfPdrNGUnAtRKQ7oZmAvPJQMqrEO88am5zl/puOThwdJ/b+tp +Ftt76zi8JffShf0fwNeL3zOfiVEUSmGeOfRzx4MV1flivbk70UjHx4ga9Nqdab6t +0dvV8copWkmj+B/sP2zk3+S9Urv6VPz97hq6PTqrmjWm+VwssDJyv9s7KGM/+9bC +/9DQR5AAQbd4e7sxW45cL9desyRfs0XNcYj6Go9sVHzFhKaSx75u6Shd5Rb2N5sX +2Dmm349cy3XimqNBCsrPIp76uLfCIhSp/pgC6phMeIu52SrFwM2OOwCuPkGZyVQv +I6n0vagltBHXYj5a371P9imV8LWTCy326yb6Ro1Mjy6XEMWVIBk/XI/U12APHytf +c1VvCk1pGemD3ArVYpuECdjtwZxxCOneOxeIYgSV/h3GHMHKmQiK36zQOslNNdfy +l7AO6kokITWoW/VPk2FG0tclWJe1aA8WOiqI3ZYRwBlovk9jUrjNqEA3BG/rzAWU +VbApXd4FvbsgLETHRZl1KWvwZFhO9vZ02+CznrnzzMWCb13UipCA7RuePuhdbViT +jOy1JJG408NcwRu0PNwr77oIZu7OrdEPu0u7YJ+SR/q3pxS6u86l6O3lvbUhtOyC +1grybOa+lJXrAL07yrbriCoy8igNIMKiA8blwpwCC/22CtGrY5UJqzpLIZuTLcnB +8pVoFioSGetvsjpzRsv6jCsacdAZwhuYEUCi82wFW1yd3UNCVMh6U8ypspQp3wz3 +tbdoGbzlwbwbgd2o9+MpxzW66s2emEsCBjG+SrNElZBkfAG8ZgSbF3yGlSe778BJ +7O71TEjxmYfUglvn90ZWpV7IH1TNbaKeIOJXkmuqQDaiG6U61kHcq//QvuZfU/tv +TEUlQGqbdYS1E7+byCxubUnD3rclSP1cMTGyUtacHGUzFhiCZfuuDc+1P1Q8wKTe +NkGfMpmXWLSncVUDEPgpsuz+hCtt65BAb0BfCWLZPyBXQ4Qbovk6Z/O5Ta5tyWEl +g2wRqFXUL8ZYk+TKbmSclU+1h3QfFwvyEmEGFi+igKRZR1ERB4cAEEDjOJP+uI7B +3K7lomdeh4kuPG6move8PCm9Dw1GhWPVFCKoan0MW2sNfnhmoOqXkoMT6P+M4U7+ +DjHY+G5Op2jkP+BrHQ99VRApXz40MtLaOdfu6S+IWURnqqwPuL99We8XFMgX3xX4 +++v7lSkcp54uSoN5e/fY/2fYG/RPxaI6+W6oxP4YmxUZjdvGdZvJiJJGqIBzCj1p +26WynwFu25wnsyXBzWo4wzH4Ga6ZtUvb59KFRTSJqQKieLVmX2zNjSps2B2/twax +EQt03AGIbtr677NeYKM3BUws+iw9TyBUjEMsqnpp6EuWhDcPga8WJn1ivw04BenP +uaOw2w1nLe8InaJxahmBKmRiSjX7XX4+PPgB/FwGN89nMBpy8+ujitteOYvlY6Hf +050aTysBmYWu4oCsx/kz8OHpwt7zPO8zkVdtHCGa8+5bm//pLUGHyoDVY2Xj68MD +OMfwbJl0Q4W+bOkCEK4fYhkB7HWPZqxZKujcR/goXBsUCvIk/WuDx8pNnjIas1Qm +MUDSs9XQFGWE8ydRYN4RRw== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/data/assets/certs/rootCA.crt b/data/assets/certs/rootCA.crt new file mode 100644 index 0000000..e7e9b8c --- /dev/null +++ b/data/assets/certs/rootCA.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDqTCCApGgAwIBAgIUbNUnFW+Ibevm3bOTzzznsNO4laIwDQYJKoZIhvcNAQEL +BQAwYzELMAkGA1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQ +MA4GA1UECgwHTWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxv +Y2FsaG9zdDAgFw0yMzAyMjUwNjU4MTJaGA8yMDUzMDIxNzA2NTgxMlowYzELMAkG +A1UEBhMCWloxDDAKBgNVBAgMA1N1bjENMAsGA1UEBwwETW9vbjEQMA4GA1UECgwH +TWVyY3VyeTERMA8GA1UECwwISG9tZWJyZXcxEjAQBgNVBAMMCWxvY2FsaG9zdDCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBF0q8GELLjXu6zTTNtCovU +QVsgg8kSN56p8Xxv5gZHEuhUXjan+UyiklW2aoxJZpyRbE8dpAR78ca6kLUG1LMf +2RX8FDjA6W5xXR2C2FmSYGnPyLigRFPbZv3sb7PyOYhqgPuu1xKMEmq5n1lE9pCV +nO7hAsfwqS3mZrPFL3MZIqrT6HqeSO1tVe8gUUWTm3dm9Yb0E/sVExdG6u0RfbVu +eqHykO4iCUonm3lOigskDbZ7WFKQyVRM3vZbALEpE7YlltcgT14GmG+L8aeFY6iT +FoPDV7bFAGtgg30os4kV135HUNJ80koIoUocwxThuyBpADltIZ5R2FSHBl1XzK8C +AwEAAaNTMFEwHQYDVR0OBBYEFHgmdAlywLPAucVbDxiIc7uIWl6RMB8GA1UdIwQY +MBaAFHgmdAlywLPAucVbDxiIc7uIWl6RMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI +hvcNAQELBQADggEBAGW6HVweWcsIxp2vVzspBaKSp2ECYRpx4xunge/eDWlokAj3 +OCW7kxgPfEbtClLOeQj3p9WolHzABgG+qqIB6kPbGtNXYaXrQbsD6j9f56GFklNK +tuYH3WtDpp5TLsYyj2cLeK2x02Z8k3+r11SqB1DeMPTBAkhXiTwrkUt3axnZuiZC +2Miwzi0b5muMbdecYukB+50xlV8TkiVmWUtQ5cVVE/U640sC6O1GMZG0zO9Ys0+U +xTeB/3Xq5Wg6OQx86GpbD7+8xRhSkdJxoVbuFgh0KNUlBREC/pYobehnwji7WWFH +F7nBdVyedi6qZTa7dVEk4eaXgalemTp9k4rzbZ8= +-----END CERTIFICATE----- diff --git a/data/assets/certs/rootCA.key b/data/assets/certs/rootCA.key new file mode 100644 index 0000000..d00a9ab --- /dev/null +++ b/data/assets/certs/rootCA.key @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIoyT8iwjhZBECAggA +MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECKy1pYbVGbtDBIIEyIIY1X/XVv5q +ihMCTQbnesuyEstQCw/9BFQ/ka4Ee2D6yJp59gSiEODwce+EgIn1jrgJImOZbnsz +xKtRJXNd+ENBwsZgh8am15o+bJ2WeOztuKcrhOvrRmj8wrDPAon4+sdcfphqRUbG +hilLbV7T8jpE1ScTD/zYU/KKWEIytYTxT+vfHvXYv8oQY9IscwNqx6cnXxNtoO7C +SO87/Apkul3irVHnad29gV/jyj4imlm6gVCmqByaD/JaV/d9Y0hWhZVeSzceP64Q +95kfhUM8AsTJi5A25vWAQAxa2Gi8ywiv+/NRVC4qhzMID4wbqI/2Oy8iEMJJfkaK +Ah/S5lY8sVRpenUmX4kSZs+oKbITc5LNccx5OUESvVZCj/mW9t91uZfTWTt23iac +snYzhH4PvYxCGU7LXzrgS5suv/N3R33E5kcND0dJbKkW4VVVxmv7HUDfs8YqduJn +teQFQNsoNuQO5Te9WsMpamickF/65nrg+OOhsbVkLsuCRPzyXIRgAPBBGFqlr3IG +XK41kQR5I4HTAeFXCClz00LfLrCl+T7IO3NbH+AD1EVGUHYPuwgJBRic/cMbXZwT +Kcxo98Apwsm+OHKRAq4c5wEmUb9ipVSwq6CRUojklrGMclJfXnd9r57FFl/9eYdY +ZEp+jnAqq3M8v2m29dPjja07CTIuimIRgIPaIjWZuZX8oW1GVpapV3JfIun5KXE4 +Sc+ScLA015Gzm/3hgKNke5HGYH49x9V/lYhr9j5AxgdWnoj4H3qbJSu2jJKooYmS +tsimgs3pqz/dygyx9Zmy2L5eb597MYEQwg4kZdFPyixAttmFXRdXVvRmQCB9H8VX +kx6z4Rus/Zh6NM6z0aHvWoaih9jJ444CdnOPLYSngLL5yzI3xunwT67Di9rrkNeL +nVBJP9Ljc9cE4LgK63xAy+25+bZWv/mZ07CBXatc91CCSa/O3KM4eLmOMNaZNU+T +P8EYHR3r24V6TCzud7dLp3k+Glkxj1feiXEktmFxnfUbGoS5Ihw4cVGqrst7hSSE +IaQFIx0X70sKyl/ixxVHWIMdV4Zqdxhf2boNZk7aHx8+yOhCnOEY4/8KUJM98W+W +a6VRhxYucKsz+B3i0BKEZg4sB1bT/6G17JAentfGmKp42IFJR3JeRydEF6ppCaWT +gdLnRlsYDHEpAMcTPsbDiQK3Crid3E0i/2QU5V5VEhR2ncq+oKZ0oy7nwoOV232W +TuodV43urEshbh8RDr321+2UxCgT6AGMAt6BPgx9D/mIZHMVgZalvHqtzPDyN5Av +5LiXct8nl4fO+c0iMdfAw2TfCvl6sIkaAW5ClqbHXxiSg9OUXSrfgBVMkcCmcnB0 +cNbx6Xc6jdLZEtnch+IcYZzj4wmLFx01zVAs9daPxbGw6mg1TloDQ0fYhgixkRSi +NDkztXZzLFx9MB4rYy/v8h08OWwNi/R6IOZDI4DNf7qXEtgqouqa85srsT9Pspc4 +SAN5YzHlo6AKujmUNRo+uYbJGqsssMXQPWNvozxnXIgQsiZ5/Y/x3KsUJu49RveL +baNm/ScI3ghTbt92bPE16ebtodULkxuPFAqXdjWXLjblSVihiKxvQ9wTULB97zHI +1oX6YdWladLddzK/De6JMA== +-----END ENCRYPTED PRIVATE KEY----- diff --git a/data/assets/certs/rootCA.srl b/data/assets/certs/rootCA.srl new file mode 100644 index 0000000..8ddf082 --- /dev/null +++ b/data/assets/certs/rootCA.srl @@ -0,0 +1 @@ +4A5531796DA232C2C3F0B937F9F7C651FC5E8FA5 diff --git a/data/assets/langs/English.ini b/data/assets/langs/English.ini index 2521fe5..05d5a05 100644 --- a/data/assets/langs/English.ini +++ b/data/assets/langs/English.ini @@ -120,3 +120,17 @@ 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_FAIL_GET_TOKEN_MSG=Failed to obtain an access token from +STR_GET_TOKEN_SUCCESS_MSG=Login Success. You may close the browser and return to the application +STR_PERM_DRIVE=See, edit, create, and delete all of your Google Drive files +STR_PERM_DRIVE_APPDATA=See, create, and delete its own configuration data in your Google Drive +STR_PERM_DRIVE_FILE=See, edit, create, and delete only the specific Google Drive files you use with this app +STR_PERM_DRIVE_METADATA=View and manage metadata of files in your Google Drive +STR_PERM_DRIVE_METADATA_RO=See information about your Google Drive files +STR_GOOGLE_LOGIN_FAIL_MSG=Google login failed +STR_GOOGLE_LOGIN_TIMEOUT_MSG=Google login timed out +STR_NEW_FILE=New File +STR_SETTINGS=Settings +STR_CLIENT_ID=Client ID +STR_CLIENT_SECRET=Client Secret +STR_GLOBAL=Global \ No newline at end of file diff --git a/source/actions.cpp b/source/actions.cpp index 5f2ea82..064c65f 100644 --- a/source/actions.cpp +++ b/source/actions.cpp @@ -4,7 +4,14 @@ #include #include #include -#include "crypt.h" +#include "clients/gdrive.h" +#include "clients/ftpclient.h" +#include "clients/smbclient.h" +#include "clients/webdavclient.h" +#include "clients/apache.h" +#include "clients/nginx.h" +#include "clients/npxserve.h" +#include "clients/iis.h" #include "common.h" #include "fs.h" #include "config.h" @@ -15,14 +22,7 @@ #include "installer.h" #include "web/request.hpp" #include "web/urn.hpp" -#include "sys_modules.h" -#include "ftpclient.h" -#include "smbclient.h" -#include "webdavclient.h" -#include "http/apache.h" -#include "http/nginx.h" -#include "http/npxserve.h" -#include "http/iis.h" +#include "system.h" #include "zip_util.h" namespace Actions @@ -1109,7 +1109,12 @@ namespace Actions { CONFIG::SaveConfig(); - if (strncmp(remote_settings->server, "https://", 8) == 0 || strncmp(remote_settings->server, "http://", 7) == 0) + if (strncmp(remote_settings->server, GOOGLE_DRIVE_BASE_URL, strlen(GOOGLE_DRIVE_BASE_URL)) == 0) + { + remoteclient = new GDriveClient(); + remoteclient->Connect("", "", ""); + } + else if (strncmp(remote_settings->server, "https://", 8) == 0 || strncmp(remote_settings->server, "http://", 7) == 0) { if (strcmp(remote_settings->http_server_type, HTTP_SERVER_APACHE) == 0) remoteclient = new ApacheClient(); @@ -1641,4 +1646,47 @@ namespace Actions return INSTALLER::InstallLocalPkg(local_file, header, true); } + + void CreateLocalFile(char *filename) + { + std::string new_file = FS::GetPath(local_directory, filename); + std::string temp_file = new_file; + int i = 1; + while (true) + { + if (!FS::FileExists(temp_file)) + break; + temp_file = new_file + "." + std::to_string(i); + i++; + } + FILE* f = FS::Create(temp_file); + FS::Close(f); + RefreshLocalFiles(false); + sprintf(local_file_to_select, "%s", temp_file.c_str()); + } + + void CreateRemoteFile(char *filename) + { + std::string new_file = FS::GetPath(remote_directory, filename); + std::string temp_file = new_file; + int i = 1; + while (true) + { + if (!remoteclient->FileExists(temp_file)) + break; + temp_file = new_file + "." + std::to_string(i); + i++; + } + + OrbisTick tick; + sceRtcGetCurrentTick(&tick); + std::string local_tmp = std::string(DATA_PATH) + "/" + std::to_string(tick.mytick); + FILE *f = FS::Create(local_tmp); + FS::Close(f); + remoteclient->Put(local_tmp, temp_file); + FS::Rm(local_tmp); + RefreshRemoteFiles(false); + sprintf(remote_file_to_select, "%s", temp_file.c_str()); + } + } diff --git a/source/actions.h b/source/actions.h index 7c2b7c6..a0bb7b1 100644 --- a/source/actions.h +++ b/source/actions.h @@ -48,7 +48,9 @@ enum ACTIONS ACTION_REMOTE_CUT, ACTION_REMOTE_COPY, ACTION_REMOTE_PASTE, - ACTION_REMOTE_EDIT + ACTION_REMOTE_EDIT, + ACTION_NEW_LOCAL_FILE, + ACTION_NEW_REMOTE_FILE }; enum OverWriteType @@ -106,6 +108,8 @@ namespace Actions void *CopyRemoteFilesThread(void *argp); void CopyRemoteFiles(); int DownloadAndInstallPkg(const std::string &filename, pkg_header *header); + void CreateLocalFile(char *filename); + void CreateRemoteFile(char *filename); } #endif \ No newline at end of file diff --git a/source/http/apache.cpp b/source/clients/apache.cpp similarity index 99% rename from source/http/apache.cpp rename to source/clients/apache.cpp index c298298..3873a70 100644 --- a/source/http/apache.cpp +++ b/source/clients/apache.cpp @@ -2,8 +2,8 @@ #include #include #include "common.h" -#include "remote_client.h" -#include "http/apache.h" +#include "clients/remote_client.h" +#include "clients/apache.h" #include "lang.h" #include "util.h" #include "windows.h" diff --git a/source/http/apache.h b/source/clients/apache.h similarity index 77% rename from source/http/apache.h rename to source/clients/apache.h index 2557f69..4885019 100644 --- a/source/http/apache.h +++ b/source/clients/apache.h @@ -4,9 +4,9 @@ #include #include #include "http/httplib.h" -#include "http/baseclient.h" +#include "clients/remote_client.h" +#include "clients/baseclient.h" #include "common.h" -#include "remote_client.h" class ApacheClient : public BaseClient { diff --git a/source/http/baseclient.cpp b/source/clients/baseclient.cpp similarity index 72% rename from source/http/baseclient.cpp rename to source/clients/baseclient.cpp index 83d4590..3959878 100644 --- a/source/http/baseclient.cpp +++ b/source/clients/baseclient.cpp @@ -1,9 +1,10 @@ #include #include #include +#include #include "common.h" -#include "remote_client.h" -#include "http/npxserve.h" +#include "clients/remote_client.h" +#include "clients/baseclient.h" #include "lang.h" #include "util.h" #include "windows.h" @@ -76,12 +77,12 @@ int BaseClient::Get(const std::string &outputfile, const std::string &path, uint std::ofstream file_stream(outputfile, std::ios::binary); bytes_transfered = 0; if (auto res = client->Get(GetFullPath(path), - [&](const char *data, size_t data_length) - { - file_stream.write(data, data_length); - bytes_transfered += data_length; - return true; - })) + [&](const char *data, size_t data_length) + { + file_stream.write(data, data_length); + bytes_transfered += data_length; + return true; + })) { file_stream.close(); return 1; @@ -126,21 +127,22 @@ int BaseClient::Move(const std::string &from, const std::string &to) int BaseClient::Head(const std::string &path, void *buffer, uint64_t len) { char range_header[64]; - sprintf(range_header, "bytes=%lu-%lu", 0L, len-1); + sprintf(range_header, "bytes=%lu-%lu", 0L, len - 1); Headers headers = {{"Range", range_header}}; size_t bytes_read = 0; std::vector body; if (auto res = client->Get(GetFullPath(path), headers, - [&](const char *data, size_t data_length) - { - body.insert(body.end(), data, data+data_length); - bytes_read += data_length; - if (bytes_read > len) - return false; - return true; - })) + [&](const char *data, size_t data_length) + { + body.insert(body.end(), data, data + data_length); + bytes_read += data_length; + if (bytes_read > len) + return false; + return true; + })) { - if (body.size() < len) return 0; + if (body.size() < len) + return 0; memcpy(buffer, body.data(), len); return 1; } @@ -161,21 +163,7 @@ std::vector BaseClient::ListDir(const std::string &path) { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path[path.length() - 1] == '/' && path.length() > 1) - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); return out; @@ -187,7 +175,7 @@ std::string BaseClient::GetPath(std::string ppath1, std::string ppath2) std::string path2 = ppath2; path1 = Util::Trim(Util::Trim(path1, " "), "/"); path2 = Util::Trim(Util::Trim(path2, " "), "/"); - path1 = this->base_path + "/" + path1 + "/" + path2; + path1 = this->base_path + ((this->base_path.length() > 0) ? "/" : "") + path1 + "/" + path2; return path1; } @@ -242,3 +230,38 @@ uint32_t BaseClient::SupportedActions() { return REMOTE_ACTION_DOWNLOAD | REMOTE_ACTION_INSTALL; } + +std::string BaseClient::EncodeUrl(const std::string &url) +{ + CURL *curl = curl_easy_init(); + if (curl) + { + char *output = curl_easy_escape(curl, url.c_str(), url.length()); + if (output) + { + std::string encoded_url = std::string(output); + curl_free(output); + return encoded_url; + } + curl_easy_cleanup(curl); + } + return ""; +} + +std::string BaseClient::DecodeUrl(const std::string &url) +{ + CURL *curl = curl_easy_init(); + if (curl) + { + int decode_len; + char *output = curl_easy_unescape(curl, url.c_str(), url.length(), &decode_len); + if (output) + { + std::string decoded_url = std::string(output, decode_len); + curl_free(output); + return decoded_url; + } + curl_easy_cleanup(curl); + } + return ""; +} diff --git a/source/http/baseclient.h b/source/clients/baseclient.h similarity index 90% rename from source/http/baseclient.h rename to source/clients/baseclient.h index 9007a7c..9ac5a65 100644 --- a/source/http/baseclient.h +++ b/source/clients/baseclient.h @@ -4,8 +4,8 @@ #include #include #include "http/httplib.h" +#include "clients/remote_client.h" #include "common.h" -#include "remote_client.h" class BaseClient : public RemoteClient { @@ -33,6 +33,8 @@ public: int Quit(); ClientType clientType(); uint32_t SupportedActions(); + static std::string EncodeUrl(const std::string &url); + static std::string DecodeUrl(const std::string &url); protected: httplib::Client *client; diff --git a/source/ftpclient.cpp b/source/clients/ftpclient.cpp similarity index 98% rename from source/ftpclient.cpp rename to source/clients/ftpclient.cpp index 129b571..c4bcda3 100644 --- a/source/ftpclient.cpp +++ b/source/clients/ftpclient.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -12,7 +12,7 @@ #include #include "lang.h" -#include "ftpclient.h" +#include "clients/ftpclient.h" #include "util.h" #include "windows.h" @@ -1578,21 +1578,7 @@ std::vector FtpClient::ListDir(const std::string &path) { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path[path.length() - 1] == '/' && path.length() > 1) - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); ftphandle *nData; diff --git a/source/ftpclient.h b/source/clients/ftpclient.h similarity index 99% rename from source/ftpclient.h rename to source/clients/ftpclient.h index 1f4b64d..0bfe11f 100644 --- a/source/ftpclient.h +++ b/source/clients/ftpclient.h @@ -6,7 +6,7 @@ #include #include #include -#include "remote_client.h" +#include "clients/remote_client.h" #define FTP_CLIENT_MAX_FILENAME_LEN 128 diff --git a/source/clients/gdrive.cpp b/source/clients/gdrive.cpp new file mode 100644 index 0000000..8b936fc --- /dev/null +++ b/source/clients/gdrive.cpp @@ -0,0 +1,741 @@ +#include +#include +#include +#include +#include "config.h" +#include "common.h" +#include "server/http_server.h" +#include "clients/remote_client.h" +#include "clients/gdrive.h" +#include "fs.h" +#include "lang.h" +#include "util.h" +#include "windows.h" +#include "system.h" + +#define GOOGLE_BUF_SIZE 262144 +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +static std::string shared_with_me("Shared with me"); + +using namespace httplib; + +std::string GetRedirectUrl() +{ + return std::string("https://localhost:" + std::to_string(http_server_port) + "/google_auth"); +} + +std::string GetScopes() +{ + std::vector permissions = Util::Split(gg_app.permissions, ","); + std::string scopes; + for (int i = 0; i < permissions.size(); i++) + { + scopes.append("https://www.googleapis.com/auth/"); + scopes.append(permissions[i]); + if (i < permissions.size() - 1) + { + scopes.append(" "); + } + } + return scopes; +} + +int RefreshAccessToken() +{ + Client client(GOOGLE_OAUTH_HOST); + client.enable_server_certificate_verification(false); + client.set_follow_location(true); + std::string url = std::string("/token"); + std::string post_data = std::string("grant_type=refresh_token") + + "&client_id=" + gg_app.client_id + + "&client_secret=" + gg_app.client_secret + + "&refresh_token=" + remote_settings->gg_account.refresh_token; + + if (auto res = client.Post(url, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded")) + { + if (HTTP_SUCCESS(res->status)) + { + json_object *jobj = json_tokener_parse(res->body.c_str()); + enum json_type type; + json_object_object_foreach(jobj, key, val) + { + if (strcmp(key, "access_token") == 0) + snprintf(remote_settings->gg_account.access_token, 255, "%s", json_object_get_string(val)); + else if (strcmp(key, "expires_in") == 0) + { + OrbisTick tick; + sceRtcGetCurrentTick(&tick); + remote_settings->gg_account.token_expiry = tick.mytick + (json_object_get_uint64(val) * 1000000); + } + } + if (remoteclient != nullptr && remoteclient->clientType() == CLIENT_TYPE_GOOGLE) + { + GDriveClient *client = (GDriveClient*)remoteclient; + client->SetAccessToken(remote_settings->gg_account.access_token); + } + CONFIG::SaveConfig(); + } + else + { + return 0; + } + } + else + { + return 0; + } + return 1; +} + +int login_state; + +std::string GetValue(const std::map &options, const std::string &name) +{ + auto it = options.find(name); + if (it == options.end()) + { + return std::string{""}; + } + else + { + return it->second; + } +} + +int GDriveClient::RequestAuthorization() +{ + SceShellUIUtilLaunchByUriParam param; + param.size = sizeof(SceShellUIUtilLaunchByUriParam); + sceUserServiceGetForegroundUser((int *)¶m.userId); + + std::string auth_url = std::string(GOOGLE_AUTH_URL "?client_id=") + gg_app.client_id + "&redirect_uri=" + GetRedirectUrl() + + "&response_type=code&access_type=offline&scope=" + GetScopes() + "&include_granted_scopes=true"; + auth_url = EncodeUrl(auth_url); + std::string launch_uri = std::string("pswebbrowser:search?url=") + auth_url; + int ret = sceShellUIUtilLaunchByUri(launch_uri.c_str(), ¶m); + + login_state = 0; + OrbisTick tick; + sceRtcGetCurrentTick(&tick); + while (login_state == 0) + { + OrbisTick cur_tick; + sceRtcGetCurrentTick(&cur_tick); + if (cur_tick.mytick - tick.mytick > 120000000) + { + login_state = -2; + break; + } + sceKernelUsleep(100000); + } + + if (login_state == -1) + { + sprintf(response, "%s", lang_strings[STR_GOOGLE_LOGIN_FAIL_MSG]); + return 0; + } + else if (login_state == -2) + { + sprintf(response, "%s", lang_strings[STR_GOOGLE_LOGIN_TIMEOUT_MSG]); + return 0; + } + + return 1; +} + +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)); +} + +int GDriveClient::Connect(const std::string &url, const std::string &user, const std::string &pass) +{ + if (strlen(remote_settings->gg_account.refresh_token) > 0) + { + int ret = RefreshAccessToken(); + if (ret == 0) + { + RequestAuthorization(); + } + } + else + { + RequestAuthorization(); + } + StartRefreshToken(); + + client = new Client(GOOGLE_API_URL); + client->set_bearer_token_auth(remote_settings->gg_account.access_token); + client->set_keep_alive(true); + client->set_follow_location(true); + client->set_connection_timeout(30); + client->set_read_timeout(30); + client->enable_server_certificate_verification(false); + this->connected = true; + + return 1; +} + +int GDriveClient::Rename(const std::string &src, const std::string &dst) +{ + if (src.find(shared_with_me) != std::string::npos || dst.find(shared_with_me) != std::string::npos) + return 0; + + std::string id = GetValue(path_id_map, src); + std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id); + std::string filename = dst.substr(dst.find_last_of("/") + 1); + std::string body = "{'name' : '" + filename + "'}"; + if (auto res = client->Patch(url, body.c_str(), body.length(), "application/json; charset=UTF-8")) + { + sprintf(response, "%d", res->status); + if (HTTP_SUCCESS(res->status)) + { + path_id_map.erase(src); + path_id_map.insert(std::make_pair(dst, id)); + } + else + return 0; + } + else + { + sprintf(response, "%s", to_string(res.error()).c_str()); + return 0; + } + return 1; +} + +bool GDriveClient::FileExists(const std::string &path) +{ + std::string id = GetValue(path_id_map, path); + if (id.empty()) // then find it parent folder to see if it exists + { + size_t name_separator = path.find_last_of("/"); + std::string parent = path.substr(0, name_separator); + if (parent.empty()) + parent = "/"; + + if (FileExists(parent)) + { + ListDir(parent); + id = GetValue(path_id_map, path); + if (!id.empty()) + return true; + } + } + else + return true; + return false; +} + +int GDriveClient::Head(const std::string &path, void *buffer, uint64_t len) +{ + size_t bytes_read = 0; + std::vector body; + std::string id = GetValue(path_id_map, path); + std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media"; + Headers headers; + headers.insert(std::make_pair("Range", "bytes=" + std::to_string(0) + "-" + std::to_string(len - 1))); + if (auto res = client->Get(url, headers, + [&](const char *data, size_t data_length) + { + body.insert(body.end(), data, data + data_length); + bytes_read += data_length; + if (bytes_read > len) + return false; + return true; + })) + { + if (body.size() < len) + return 0; + memcpy(buffer, body.data(), len); + return 1; + } + else + { + sprintf(this->response, "%s", httplib::to_string(res.error()).c_str()); + } + return 0; +} + +int GDriveClient::Get(const std::string &outputfile, const std::string &path, uint64_t offset) +{ + std::ofstream file_stream(outputfile, std::ios::binary); + bytes_transfered = 0; + + std::string id = GetValue(path_id_map, path); + std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?alt=media"; + if (auto res = client->Get(url, + [&](const char *data, size_t data_length) + { + file_stream.write(data, data_length); + bytes_transfered += data_length; + return true; + })) + { + file_stream.close(); + return 1; + } + else + { + sprintf(this->response, "%s", httplib::to_string(res.error()).c_str()); + } + return 0; +} + +int GDriveClient::Update(const std::string &inputfile, const std::string &path) +{ + bytes_to_download = FS::GetSize(inputfile); + bytes_transfered = 0; + + std::ifstream file_stream(inputfile, std::ios::binary); + bytes_transfered = 0; + + std::string id = GetValue(path_id_map, path); + + std::string url = "/upload/drive/v3/files/" + BaseClient::EncodeUrl(id) + "?uploadType=resumable"; + Headers headers; + headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream")); + headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download))); + char *buf = new char[GOOGLE_BUF_SIZE]; + if (auto res = client->Patch(url)) + { + if (HTTP_SUCCESS(res->status)) + { + std::string upload_uri = res->get_header_value("location"); + upload_uri = std::regex_replace(upload_uri, std::regex(GOOGLE_API_URL), ""); + Headers headers; + headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download))); + std::string range_value = "bytes 0-" + std::to_string(bytes_to_download - 1) + "/" + std::to_string(bytes_to_download); + headers.insert(std::make_pair("Content-Range", range_value)); + + if (auto res = client->Put( + upload_uri, bytes_to_download, + [&file_stream, &buf](size_t offset, size_t length, DataSink &sink) + { + uint32_t count = 0; + uint32_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count); + do + { + file_stream.read(buf, bytes_to_transfer); + sink.write(buf, bytes_to_transfer); + count += bytes_to_transfer; + bytes_transfered += bytes_to_transfer; + bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count); + } while (count < length); + return true; + }, + "application/octet-stream")) + { + // success + } + else + { + delete[] buf; + file_stream.close(); + return 0; + } + } + else + { + delete[] buf; + file_stream.close(); + return 0; + } + } + delete[] buf; + file_stream.close(); + return 1; +} + +int GDriveClient::Put(const std::string &inputfile, const std::string &path, uint64_t offset) +{ + if (path.find(shared_with_me) != std::string::npos) + return 0; + + if (FileExists(path)) + return Update(inputfile, path); + + bytes_to_download = FS::GetSize(inputfile); + bytes_transfered = 0; + + std::ifstream file_stream(inputfile, std::ios::binary); + bytes_transfered = 0; + + size_t path_pos = path.find_last_of("/"); + std::string parent_dir; + if (path_pos == 0) + parent_dir = "/"; + else + parent_dir = path.substr(0, path_pos); + + std::string filename = path.substr(path_pos + 1); + std::string parent_id = GetValue(path_id_map, parent_dir); + + std::string url = "/upload/drive/v3/files?uploadType=resumable"; + std::string post_data = std::string("{'name': '") + filename + "', 'parents': ['" + parent_id + "']}"; + Headers headers; + headers.insert(std::make_pair("X-Upload-Content-Type", "application/octet-stream")); + headers.insert(std::make_pair("X-Upload-Content-Length", std::to_string(bytes_to_download))); + char *buf = new char[GOOGLE_BUF_SIZE]; + if (auto res = client->Post(url, headers, post_data.c_str(), post_data.length(), "application/json")) + { + if (HTTP_SUCCESS(res->status)) + { + std::string upload_uri = res->get_header_value("location"); + upload_uri = std::regex_replace(upload_uri, std::regex(GOOGLE_API_URL), ""); + Headers headers; + headers.insert(std::make_pair("Content-Length", std::to_string(bytes_to_download))); + std::string range_value = "bytes 0-" + std::to_string(bytes_to_download - 1) + "/" + std::to_string(bytes_to_download); + headers.insert(std::make_pair("Content-Range", range_value)); + + if (auto res = client->Put( + upload_uri, bytes_to_download, + [&file_stream, &buf](size_t offset, size_t length, DataSink &sink) + { + uint32_t count = 0; + uint32_t bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count); + do + { + file_stream.read(buf, bytes_to_transfer); + sink.write(buf, bytes_to_transfer); + count += bytes_to_transfer; + bytes_transfered += bytes_to_transfer; + bytes_to_transfer = MIN(GOOGLE_BUF_SIZE, length - count); + } while (count < length); + return true; + }, + "application/octet-stream")) + { + // success + } + else + { + delete[] buf; + file_stream.close(); + return 0; + } + } + else + { + delete[] buf; + file_stream.close(); + return 0; + } + } + delete[] buf; + file_stream.close(); + return 1; +} + +int GDriveClient::Size(const std::string &path, int64_t *size) +{ + std::string id = GetValue(path_id_map, path); + std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id) + "?fields=size"; + if (auto res = client->Get(url)) + { + sprintf(response, "%d", res->status); + if (HTTP_SUCCESS(res->status)) + { + json_object *jobj = json_tokener_parse(res->body.c_str()); + *size = json_object_get_uint64(json_object_object_get(jobj, "size")); + } + else + return 0; + } + else + { + sprintf(response, "%s", to_string(res.error()).c_str()); + return 0; + } + return 1; +} + +int GDriveClient::Mkdir(const std::string &path) +{ + if (path.find(shared_with_me) != std::string::npos) + return 0; + + // if path already exists return; + if (FileExists(path)) + return 1; + + size_t path_pos = path.find_last_of("/"); + std::string parent_dir; + if (path_pos == 0) + parent_dir = "/"; + else + parent_dir = path.substr(0, path_pos); + + std::string folder_name = path.substr(path_pos + 1); + std::string parent_id = GetValue(path_id_map, parent_dir); + + // if parent dir does not exists, create it first + if (parent_id.length() == 0 || parent_id.empty()) + { + Mkdir(parent_dir); + parent_id = GetValue(path_id_map, parent_dir); + } + + std::string url = std::string("/drive/v3/files?fields=id"); + std::string folder_metadata = "{'name' : '" + folder_name + "'," + + "'parents' : ['" + parent_id + "']," + + "'mimeType' : 'application/vnd.google-apps.folder'}"; + + if (auto res = client->Post(url, folder_metadata.c_str(), folder_metadata.length(), "application/json; charset=UTF-8")) + { + sprintf(response, "%d", res->status); + if (HTTP_SUCCESS(res->status)) + { + json_object *jobj = json_tokener_parse(res->body.c_str()); + const char *id = json_object_get_string(json_object_object_get(jobj, "id")); + path_id_map.insert(std::make_pair(path, id)); + } + else + return 0; + } + else + { + sprintf(response, "%s", to_string(res.error()).c_str()); + return 0; + } + return 1; +} + +/* + * Rmdir in google drive deletes all files/folders in subdirectories also. + * Delete file/folder is the same api + */ +int GDriveClient::Rmdir(const std::string &path, bool recursive) +{ + if (path.find(shared_with_me) != std::string::npos) + return 0; + + int ret = Delete(path); + if (ret != 0) + { + std::string subfolders = path + "/"; + for (std::map::iterator it = path_id_map.begin(); it != path_id_map.end();) + { + if (strncmp(it->first.c_str(), subfolders.c_str(), path.length()) == 0) + { + it = path_id_map.erase(it); + } + else + ++it; + } + } + return ret; +} + +int GDriveClient::Delete(const std::string &path) +{ + std::string id = GetValue(path_id_map, path); + if (strcmp(id.c_str(), "root") == 0) + return 0; + + std::string url = std::string("/drive/v3/files/") + BaseClient::EncodeUrl(id); + if (auto res = client->Delete(url)) + { + if (HTTP_SUCCESS(res->status)) + { + path_id_map.erase(path); + sprintf(response, "%d", res->status); + } + else + return 0; + } + else + { + sprintf(response, "%s", to_string(res.error()).c_str()); + return 0; + } + return 1; +} + +void SetupSharedWithMeFolder(DirEntry *entry) +{ + memset(entry, 0, sizeof(DirEntry)); + sprintf(entry->directory, "%s", "/"); + sprintf(entry->name, "%s", shared_with_me.c_str()); + sprintf(entry->path, "/%s", shared_with_me.c_str()); + sprintf(entry->display_size, "%s", lang_strings[STR_FOLDER]); + entry->file_size = 0; + entry->isDir = true; + entry->selectable = false; +} + +std::vector GDriveClient::ListDir(const std::string &path) +{ + std::vector out; + DirEntry entry; + Util::SetupPreviousFolder(path, &entry); + out.push_back(entry); + + if (strcmp(path.c_str(), "/") == 0) + { + SetupSharedWithMeFolder(&entry); + out.push_back(entry); + } + + std::string id = GetValue(path_id_map, 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"); + bool find_no_parent = false; + if (id.compare(shared_with_me) == 0) + { + base_url = std::string("/drive/v3/files?q=sharedWithMe&pageSize=1000&fields=") + BaseClient::EncodeUrl("files(id,mimeType,name,modifiedTime,size),nextPageToken"); + } + + std::string next_page_url = base_url; + while (true) + { + if (auto res = client->Get(next_page_url)) + { + if (HTTP_SUCCESS(res->status)) + { + json_object *jobj = json_tokener_parse(res->body.c_str()); + json_object *next_page_token = json_object_object_get(jobj, "nextPageToken"); + json_object *files = json_object_object_get(jobj, "files"); + if (json_object_get_type(files) == json_type_array) + { + struct array_list *afiles = json_object_get_array(files); + for (size_t idx = 0; idx < afiles->length; ++idx) + { + json_object *file = (json_object *)array_list_get_idx(afiles, idx); + DirEntry entry; + memset(&entry, 0, sizeof(DirEntry)); + + sprintf(entry.directory, "%s", path.c_str()); + entry.selectable = true; + entry.file_size = 0; + + const char *id = json_object_get_string(json_object_object_get(file, "id")); + const char *name = json_object_get_string(json_object_object_get(file, "name")); + const char *mime_type = json_object_get_string(json_object_object_get(file, "mimeType")); + const char *modified_time = json_object_get_string(json_object_object_get(file, "modifiedTime")); + + snprintf(entry.name, 255, "%s", name); + if (path.length() > 0 && path[path.length() - 1] == '/') + { + snprintf(entry.path, 767, "%s%s", path.c_str(), entry.name); + } + else + { + sprintf(entry.path, "%s/%s", path.c_str(), entry.name); + } + path_id_map.insert(std::make_pair(entry.path, id)); + + if (strncmp(mime_type, "application/vnd.google-apps.folder", 35) != 0) + { + entry.file_size = json_object_get_uint64(json_object_object_get(file, "size")); + entry.isDir = false; + DirEntry::SetDisplaySize(&entry); + } + else + { + entry.isDir = true; + sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); + } + + std::vector date_time_arr = Util::Split(modified_time, "T"); + std::vector adate = Util::Split(date_time_arr[0], "-"); + std::vector atime = Util::Split(Util::Split(date_time_arr[1], ".")[0], ":"); + OrbisDateTime utc, local; + utc.year = std::atoi(adate[0].c_str()); + utc.month = std::atoi(adate[1].c_str()); + utc.day = std::atoi(adate[2].c_str()); + utc.hour = std::atoi(atime[0].c_str()); + utc.minute = std::atoi(atime[1].c_str()); + utc.second = std::atoi(atime[2].c_str()); + + convertUtcToLocalTime(&utc, &local); + + entry.modified.year = local.year; + entry.modified.month = local.month; + entry.modified.day = local.day; + entry.modified.hours = local.hour; + entry.modified.minutes = local.minute; + entry.modified.seconds = local.second; + + out.push_back(entry); + } + } + if (next_page_token != nullptr) + next_page_url = base_url + "&pageToken=" + BaseClient::EncodeUrl(json_object_get_string(next_page_token)); + else + break; + } + } + else + { + break; + } + }; + return out; +} + +ClientType GDriveClient::clientType() +{ + return CLIENT_TYPE_GOOGLE; +} + +uint32_t GDriveClient::SupportedActions() +{ + return REMOTE_ACTION_ALL ^ REMOTE_ACTION_CUT ^ REMOTE_ACTION_COPY ^ REMOTE_ACTION_PASTE; +} + +void *GDriveClient::RefreshTokenThread(void *argp) +{ + while (refresh_token_running) + { + OrbisTick tick; + memset(&tick, 0, sizeof(OrbisTick)); + sceRtcGetCurrentTick(&tick); + if (tick.mytick >= (remote_settings->gg_account.token_expiry - 300000000) && + remote_settings->type == CLIENT_TYPE_GOOGLE) // refresh token 5mins before expiry + { + RefreshAccessToken(); + } + sceKernelUsleep(500000); // check every 0.5s + } + return NULL; +} + +void GDriveClient::StartRefreshToken() +{ + if (refresh_token_running) + return; + + refresh_token_running = true; + int ret = pthread_create(&refresh_token_thid, NULL, RefreshTokenThread, NULL); + if (ret != 0) + { + refresh_token_running = false; + return; + } +} + +void GDriveClient::StopRefreshToken() +{ + refresh_token_running = false; +} + +int GDriveClient::Quit() +{ + StopRefreshToken(); + if (client != nullptr) + { + delete client; + client = nullptr; + } + return 1; +} + +void GDriveClient::SetAccessToken(const std::string &token) +{ + if (this->client != nullptr) + this->client->set_bearer_token_auth(token); +} \ No newline at end of file diff --git a/source/clients/gdrive.h b/source/clients/gdrive.h new file mode 100644 index 0000000..35b41d6 --- /dev/null +++ b/source/clients/gdrive.h @@ -0,0 +1,44 @@ +#ifndef GDRIVE_H +#define GDRIVE_H + +#include +#include +#include "http/httplib.h" +#include "clients/remote_client.h" +#include "clients/baseclient.h" +#include "common.h" + +static pthread_t refresh_token_thid; +static bool refresh_token_running = false; +extern int login_state; + +class GDriveClient : public BaseClient +{ +public: + GDriveClient(); + int Connect(const std::string &url, const std::string &user, const std::string &pass); + int Rename(const std::string &src, const std::string &dst); + int Get(const std::string &outputfile, const std::string &path, uint64_t offset=0); + int Put(const std::string &inputfile, const std::string &path, uint64_t offset=0); + int Head(const std::string &path, void *buffer, uint64_t len); + int Update(const std::string &inputfile, const std::string &path); + int Size(const std::string &path, int64_t *size); + int Mkdir(const std::string &path); + int Rmdir(const std::string &path, bool recursive); + int Delete(const std::string &path); + bool FileExists(const std::string &path); + void SetAccessToken(const std::string &token); + std::vector ListDir(const std::string &path); + static void *RefreshTokenThread(void *argp); + static void StartRefreshToken(); + static void StopRefreshToken(); + ClientType clientType(); + uint32_t SupportedActions(); + int Quit(); + +private: + int RequestAuthorization(); + std::map path_id_map; +}; + +#endif \ No newline at end of file diff --git a/source/http/iis.cpp b/source/clients/iis.cpp similarity index 91% rename from source/http/iis.cpp rename to source/clients/iis.cpp index 19dc797..ba1bba2 100644 --- a/source/http/iis.cpp +++ b/source/clients/iis.cpp @@ -2,8 +2,8 @@ #include #include #include "common.h" -#include "remote_client.h" -#include "http/iis.h" +#include "clients/remote_client.h" +#include "clients/iis.h" #include "lang.h" #include "util.h" #include "windows.h" @@ -16,21 +16,7 @@ std::vector IISClient::ListDir(const std::string &path) { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path[path.length() - 1] == '/' && path.length() > 1) - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); if (auto res = client->Get(GetFullPath(path))) diff --git a/source/http/iis.h b/source/clients/iis.h similarity index 77% rename from source/http/iis.h rename to source/clients/iis.h index a39ae12..1c4e340 100644 --- a/source/http/iis.h +++ b/source/clients/iis.h @@ -4,9 +4,9 @@ #include #include #include "http/httplib.h" -#include "http/baseclient.h" +#include "clients/remote_client.h" +#include "clients/baseclient.h" #include "common.h" -#include "remote_client.h" class IISClient : public BaseClient { diff --git a/source/http/nginx.cpp b/source/clients/nginx.cpp similarity index 91% rename from source/http/nginx.cpp rename to source/clients/nginx.cpp index 6ac8f24..517a22f 100644 --- a/source/http/nginx.cpp +++ b/source/clients/nginx.cpp @@ -4,8 +4,8 @@ #include #include #include "common.h" -#include "remote_client.h" -#include "http/nginx.h" +#include "clients/remote_client.h" +#include "clients/nginx.h" #include "lang.h" #include "util.h" #include "windows.h" @@ -23,21 +23,7 @@ std::vector NginxClient::ListDir(const std::string &path) { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path[path.length() - 1] == '/' && path.length() > 1) - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); if (auto res = client->Get(GetFullPath(path))) diff --git a/source/http/nginx.h b/source/clients/nginx.h similarity index 77% rename from source/http/nginx.h rename to source/clients/nginx.h index 3c04ba1..1043b03 100644 --- a/source/http/nginx.h +++ b/source/clients/nginx.h @@ -4,9 +4,9 @@ #include #include #include "http/httplib.h" -#include "http/baseclient.h" +#include "clients/baseclient.h" #include "common.h" -#include "remote_client.h" +#include "clients/remote_client.h" class NginxClient : public BaseClient { diff --git a/source/http/npxserve.cpp b/source/clients/npxserve.cpp similarity index 87% rename from source/http/npxserve.cpp rename to source/clients/npxserve.cpp index e495b60..110b7ca 100644 --- a/source/http/npxserve.cpp +++ b/source/clients/npxserve.cpp @@ -2,8 +2,8 @@ #include #include #include "common.h" -#include "remote_client.h" -#include "http/npxserve.h" +#include "clients/remote_client.h" +#include "clients/npxserve.h" #include "lang.h" #include "util.h" #include "windows.h" @@ -16,21 +16,7 @@ std::vector NpxServeClient::ListDir(const std::string &path) { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path[path.length() - 1] == '/' && path.length() > 1) - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); if (auto res = client->Get(GetFullPath(path))) diff --git a/source/http/npxserve.h b/source/clients/npxserve.h similarity index 78% rename from source/http/npxserve.h rename to source/clients/npxserve.h index c222763..9801506 100644 --- a/source/http/npxserve.h +++ b/source/clients/npxserve.h @@ -4,9 +4,9 @@ #include #include #include "http/httplib.h" -#include "http/baseclient.h" +#include "clients/baseclient.h" +#include "clients/remote_client.h" #include "common.h" -#include "remote_client.h" class NpxServeClient : public BaseClient { diff --git a/source/remote_client.h b/source/clients/remote_client.h similarity index 95% rename from source/remote_client.h rename to source/clients/remote_client.h index 22b0fa6..9eca76f 100644 --- a/source/remote_client.h +++ b/source/clients/remote_client.h @@ -18,7 +18,8 @@ enum RemoteActions REMOTE_ACTION_UPLOAD = 128, REMOTE_ACTION_INSTALL = 256, REMOTE_ACTION_EDIT = 512, - REMOTE_ACTION_ALL = 1023 + REMOTE_ACTION_NEW_FILE = 1024, + REMOTE_ACTION_ALL = 2047 }; enum ClientType @@ -27,6 +28,7 @@ enum ClientType CLIENT_TYPE_SMB, CLIENT_TYPE_WEBDAV, CLIENT_TYPE_HTTP_SERVER, + CLIENT_TYPE_GOOGLE, CLINET_TYPE_UNKNOWN }; diff --git a/source/smbclient.cpp b/source/clients/smbclient.cpp similarity index 95% rename from source/smbclient.cpp rename to source/clients/smbclient.cpp index f8ce036..7dcb079 100644 --- a/source/smbclient.cpp +++ b/source/clients/smbclient.cpp @@ -12,7 +12,7 @@ #include #include "fs.h" #include "lang.h" -#include "smbclient.h" +#include "clients/smbclient.h" #include "windows.h" #include "util.h" @@ -396,21 +396,7 @@ std::vector SmbClient::ListDir(const std::string &path) { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path.length() > 1 && path[path.length() - 1] == '/') - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); struct smb2dir *dir; diff --git a/source/smbclient.h b/source/clients/smbclient.h similarity index 97% rename from source/smbclient.h rename to source/clients/smbclient.h index a26ed7c..bdd1dab 100644 --- a/source/smbclient.h +++ b/source/clients/smbclient.h @@ -8,8 +8,8 @@ #include #include #include +#include "clients/remote_client.h" #include "common.h" -#include "remote_client.h" #define SMB_CLIENT_MAX_FILENAME_LEN 256 diff --git a/source/webdavclient.cpp b/source/clients/webdavclient.cpp similarity index 94% rename from source/webdavclient.cpp rename to source/clients/webdavclient.cpp index abd307a..b6e8c2c 100644 --- a/source/webdavclient.cpp +++ b/source/clients/webdavclient.cpp @@ -9,10 +9,10 @@ #include #include "lang.h" #include "webdav/client.hpp" -#include "webdavclient.h" +#include "clients/webdavclient.h" #include "windows.h" #include "util.h" -#include "sys_modules.h" +#include "system.h" #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) @@ -256,21 +256,7 @@ namespace WebDAV { std::vector out; DirEntry entry; - memset(&entry, 0, sizeof(DirEntry)); - if (path.length() > 1 && path[path.length() - 1] == '/') - { - strlcpy(entry.directory, path.c_str(), path.length() - 1); - } - else - { - sprintf(entry.directory, "%s", path.c_str()); - } - sprintf(entry.name, ".."); - sprintf(entry.path, "%s", entry.directory); - sprintf(entry.display_size, "%s", lang_strings[STR_FOLDER]); - entry.file_size = 0; - entry.isDir = true; - entry.selectable = false; + Util::SetupPreviousFolder(path, &entry); out.push_back(entry); WebDAV::dict_items_t files = client->list(path); diff --git a/source/webdavclient.h b/source/clients/webdavclient.h similarity index 98% rename from source/webdavclient.h rename to source/clients/webdavclient.h index 3464314..f481b22 100644 --- a/source/webdavclient.h +++ b/source/clients/webdavclient.h @@ -6,8 +6,8 @@ #include #include #include "webdav/client.hpp" +#include "clients/remote_client.h" #include "common.h" -#include "remote_client.h" namespace WebDAV { diff --git a/source/common.h b/source/common.h index fd1b8da..b6a3089 100644 --- a/source/common.h +++ b/source/common.h @@ -5,6 +5,8 @@ #include #include +#define HTTP_SUCCESS(x) (x >= 200 && x < 300) + typedef struct { uint16_t year; diff --git a/source/config.cpp b/source/config.cpp index f8d6db5..f98e12e 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -6,6 +6,7 @@ #include #include #include +#include "server/http_server.h" #include "config.h" #include "fs.h" #include "lang.h" @@ -32,6 +33,8 @@ PackageUrlInfo install_pkg_url; char favorite_urls[MAX_FAVORITE_URLS][512]; bool auto_delete_tmp_pkg; int max_edit_file_size; +GoogleAppInfo gg_app; + 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'}; @@ -84,6 +87,10 @@ namespace CONFIG { setting->type = CLIENT_TYPE_WEBDAV; } + else if (strncmp(setting->server, "https://drive.google.com", 24) == 0) + { + setting->type = CLIENT_TYPE_GOOGLE; + } else if (strncmp(setting->server, "http://", 7) == 0 || strncmp(setting->server, "https://", 8) == 0) { setting->type = CLIENT_TYPE_HTTP_SERVER; @@ -94,7 +101,7 @@ namespace CONFIG } } - void LoadEncryptKeys() + void LoadCipherKeys() { // Get the key and iv for encryption. Inject the account_id/MAC address as part of the key and iv. int user_id; @@ -123,7 +130,7 @@ namespace CONFIG void LoadConfig() { - LoadEncryptKeys(); + LoadCipherKeys(); if (!FS::FolderExists(DATA_PATH)) { @@ -161,6 +168,33 @@ namespace CONFIG 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); + // Load Google Account Info + sprintf(gg_app.client_id, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, "")); + WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id); + + // Client Secret + char tmp_gg_secret[512]; + sprintf(tmp_gg_secret, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, "")); + std::string encrypted_secret; + if (strlen(tmp_gg_secret) > 0) + { + std::string decrypted_secret; + int ret = Decrypt(tmp_gg_secret, decrypted_secret); + if (ret == 0) + sprintf(gg_app.client_secret, "%s", tmp_gg_secret); + else + sprintf(gg_app.client_secret, "%s", decrypted_secret.c_str()); + Encrypt(gg_app.client_secret, encrypted_secret); + } + WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str()); + + sprintf(gg_app.permissions, "%s", ReadString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, GOOGLE_DEFAULT_PERMISSIONS)); + WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions); + + // Http Server Info + http_server_port = ReadInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, 8080); + WriteInt(CONFIG_HTTP_SERVER, CONFIG_HTTP_SERVER_PORT, http_server_port); + for (int i = 0; i < sites.size(); i++) { RemoteSettings setting; @@ -204,6 +238,40 @@ 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); + // Token Expiry + setting.gg_account.token_expiry = ReadLong(sites[i].c_str(), CONFIG_GOOGLE_TOKEN_EXPIRY, 0); + WriteLong(sites[i].c_str(), CONFIG_GOOGLE_TOKEN_EXPIRY, setting.gg_account.token_expiry); + + // Access Token + sprintf(tmp_gg_secret, "%s", ReadString(sites[i].c_str(), CONFIG_GOOGLE_ACCESS_TOKEN, "")); + std::string encrypted_token; + if (strlen(tmp_gg_secret) > 0) + { + std::string decrypted_secret; + int ret = Decrypt(tmp_gg_secret, decrypted_secret); + if (ret == 0) + sprintf(setting.gg_account.access_token, "%s", tmp_gg_secret); + else + sprintf(setting.gg_account.access_token, "%s", decrypted_secret.c_str()); + Encrypt(setting.gg_account.access_token, encrypted_token); + } + WriteString(sites[i].c_str(), CONFIG_GOOGLE_ACCESS_TOKEN, encrypted_token.c_str()); + + // Refresh Token + sprintf(tmp_gg_secret, "%s", ReadString(sites[i].c_str(), CONFIG_GOOGLE_REFRESH_TOKEN, "")); + std::string encrypted_refresh_token; + if (strlen(tmp_gg_secret) > 0) + { + std::string decrypted_secret; + int ret = Decrypt(tmp_gg_secret, decrypted_secret); + if (ret == 0) + sprintf(setting.gg_account.refresh_token, "%s", tmp_gg_secret); + else + sprintf(setting.gg_account.refresh_token, "%s", decrypted_secret.c_str()); + Encrypt(setting.gg_account.refresh_token, encrypted_refresh_token); + } + WriteString(sites[i].c_str(), CONFIG_GOOGLE_REFRESH_TOKEN, encrypted_refresh_token.c_str()); + SetClientType(&setting); site_settings.insert(std::make_pair(sites[i], setting)); } @@ -212,14 +280,12 @@ namespace CONFIG WriteString(CONFIG_GLOBAL, CONFIG_LAST_SITE, last_site); remote_settings = &site_settings[std::string(last_site)]; - for (int i = 0; i < MAX_FAVORITE_URLS; i++) { const char *index = std::to_string(i).c_str(); sprintf(favorite_urls[i], "%s", ReadString(CONFIG_FAVORITE_URLS, index, "")); WriteString(CONFIG_FAVORITE_URLS, index, favorite_urls[i]); } - WriteIniFile(CONFIG_INI_FILE); CloseIniFile(); } @@ -241,6 +307,37 @@ namespace CONFIG WriteString(last_site, CONFIG_REMOTE_HTTP_SERVER_TYPE, remote_settings->http_server_type); 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); + else + encrypted_token = std::string(remote_settings->gg_account.access_token); + WriteString(last_site, CONFIG_GOOGLE_ACCESS_TOKEN, encrypted_token.c_str()); + + std::string encrypted_refresh_token; + if (strlen(remote_settings->gg_account.refresh_token) > 0) + Encrypt(remote_settings->gg_account.refresh_token, encrypted_refresh_token); + else + encrypted_refresh_token = std::string(remote_settings->gg_account.refresh_token); + WriteString(last_site, CONFIG_GOOGLE_REFRESH_TOKEN, encrypted_refresh_token.c_str()); + WriteLong(last_site, CONFIG_GOOGLE_TOKEN_EXPIRY, remote_settings->gg_account.token_expiry); + WriteIniFile(CONFIG_INI_FILE); + CloseIniFile(); + } + + void SaveGlobalConfig() + { + OpenIniFile(CONFIG_INI_FILE); + + std::string encrypted_secret; + if (strlen(gg_app.client_secret) > 0) + Encrypt(gg_app.client_secret, encrypted_secret); + else + encrypted_secret = std::string(gg_app.client_secret); + WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_SECRET, encrypted_secret.c_str()); + WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_CLIENT_ID, gg_app.client_id); + WriteString(CONFIG_GOOGLE, CONFIG_GOOGLE_PERMISSIONS, gg_app.permissions); + WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg); WriteIniFile(CONFIG_INI_FILE); CloseIniFile(); } @@ -253,52 +350,4 @@ namespace CONFIG WriteIniFile(CONFIG_INI_FILE); CloseIniFile(); } - - void ParseMultiValueString(const char *prefix_list, std::vector &prefixes, bool toLower) - { - std::string prefix = ""; - int length = strlen(prefix_list); - for (int i = 0; i < length; i++) - { - char c = prefix_list[i]; - if (c != ' ' && c != '\t' && c != ',') - { - if (toLower) - { - prefix += std::tolower(c); - } - else - { - prefix += c; - } - } - - if (c == ',' || i == length - 1) - { - prefixes.push_back(prefix); - prefix = ""; - } - } - } - - std::string GetMultiValueString(std::vector &multi_values) - { - std::string vts = std::string(""); - if (multi_values.size() > 0) - { - for (int i = 0; i < multi_values.size() - 1; i++) - { - vts.append(multi_values[i]).append(","); - } - vts.append(multi_values[multi_values.size() - 1]); - } - return vts; - } - - void RemoveFromMultiValues(std::vector &multi_values, std::string value) - { - auto itr = std::find(multi_values.begin(), multi_values.end(), value); - if (itr != multi_values.end()) - multi_values.erase(itr); - } } diff --git a/source/config.h b/source/config.h index 6039fcf..3c43e0b 100644 --- a/source/config.h +++ b/source/config.h @@ -3,10 +3,11 @@ #include #include +#include #include #include -#include "remote_client.h" +#include "clients/remote_client.h" #define APP_ID "ezremote-client" #define DATA_PATH "/data/" APP_ID @@ -16,6 +17,29 @@ #define CONFIG_GLOBAL "Global" +#define CONFIG_GOOGLE "Google" +#define CONFIG_GOOGLE_CLIENT_ID "google_client_id" +#define CONFIG_GOOGLE_CLIENT_SECRET "google_client_secret" +#define CONFIG_GOOGLE_PERMISSIONS "google_client_permissions" +#define CONFIG_GOOGLE_ACCESS_TOKEN "google_access_token" +#define CONFIG_GOOGLE_REFRESH_TOKEN "google_refresh_token" +#define CONFIG_GOOGLE_TOKEN_EXPIRY "google_token_expiry" + +#define GOOGLE_OAUTH_HOST "https://oauth2.googleapis.com" +#define GOOGLE_AUTH_URL "https://accounts.google.com/o/oauth2/v2/auth" +#define GOOGLE_API_URL "https://www.googleapis.com" +#define GOOGLE_DRIVE_API_PATH "/drive/v2/files" +#define GOOGLE_DRIVE_BASE_URL "https://drive.google.com" +#define GOOGLE_PERM_DRIVE "drive" +#define GOOGLE_PERM_DRIVE_APPDATA "drive.appdata" +#define GOOGLE_PERM_DRIVE_FILE "drive.file" +#define GOOGLE_PERM_DRIVE_METADATA "drive.metadata" +#define GOOGLE_PERM_DRIVE_METADATA_RO "drive.metadata.readonly" +#define GOOGLE_DEFAULT_PERMISSIONS GOOGLE_PERM_DRIVE + +#define CONFIG_HTTP_SERVER "HttpServer" +#define CONFIG_HTTP_SERVER_PORT "http_server_port" + #define CONFIG_REMOTE_SERVER_NAME "remote_server_name" #define CONFIG_REMOTE_SERVER_URL "remote_server_url" #define CONFIG_REMOTE_SERVER_USER "remote_server_user" @@ -46,6 +70,20 @@ #define MAX_EDIT_FILE_SIZE 32768 +struct GoogleAccountInfo +{ + char access_token[256]; + char refresh_token[256]; + uint64_t token_expiry; +}; + +struct GoogleAppInfo +{ + char client_id[140]; + char client_secret[64]; + char permissions[92]; +}; + struct RemoteSettings { char site_name[32]; @@ -57,6 +95,7 @@ struct RemoteSettings bool enable_rpi; uint32_t supported_actions; char http_server_type[24]; + GoogleAccountInfo gg_account; }; struct PackageUrlInfo @@ -83,15 +122,14 @@ extern bool auto_delete_tmp_pkg; extern int max_edit_file_size; extern unsigned char cipher_key[32]; extern unsigned char cipher_iv[16]; +extern GoogleAppInfo gg_app; namespace CONFIG { void LoadConfig(); void SaveConfig(); + void SaveGlobalConfig(); void SaveFavoriteUrl(int index, char *url); void SetClientType(RemoteSettings *settings); - void RemoveFromMultiValues(std::vector &multi_values, std::string value); - void ParseMultiValueString(const char *prefix_list, std::vector &prefixes, bool toLower); - std::string GetMultiValueString(std::vector &multi_values); } #endif diff --git a/source/fs.cpp b/source/fs.cpp index c6e0e49..fcfce83 100644 --- a/source/fs.cpp +++ b/source/fs.cpp @@ -11,7 +11,7 @@ #include "util.h" #include "lang.h" -#include "sys_modules.h" +#include "system.h" #include "windows.h" namespace FS @@ -187,9 +187,10 @@ namespace FS } while (bytes_read == 1024); if (line.size()>0) lines->push_back(std::string(line.data(), line.size())); - + fclose(fd); - + if (lines->size() == 0) + lines->push_back(""); return true; } diff --git a/source/http/httplib.cpp b/source/http/httplib.cpp index 118f178..5e9fb0e 100644 --- a/source/http/httplib.cpp +++ b/source/http/httplib.cpp @@ -932,6 +932,10 @@ socket_t create_client_socket( tv.tv_usec = static_cast(write_timeout_usec); setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); #endif + + int const size = 1048576; + setsockopt(sock2, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(sock2, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); } error = Error::Success; diff --git a/source/http/httplib.h b/source/http/httplib.h index f19d3e4..f75d315 100644 --- a/source/http/httplib.h +++ b/source/http/httplib.h @@ -1637,6 +1637,9 @@ inline void default_socket_options(socket_t sock) { sizeof(yes)); #endif #endif + int const size = 1048576; + setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); } template diff --git a/source/inifile.c b/source/inifile.c index 871f283..10908e7 100644 --- a/source/inifile.c +++ b/source/inifile.c @@ -52,7 +52,7 @@ ------------------------------------------------------------------------ Copyright (c) 2000 Carsten Breuer -/************************************************************************/ +************************************************************************/ /* defines for, or consts and inline functions for C++ */ @@ -68,7 +68,7 @@ struct ENTRY *Entry = NULL; struct ENTRY *CurEntry = NULL; -char Result[4096] = +char Result[520] = {""}; FILE *IniFile; @@ -84,7 +84,7 @@ struct ENTRY *MakeNewEntry(void); strupr -de- ------------------------------------------------------------------------- Job : String to Uppercase 22.03.2001 Dieter Engelbrecht dieter@wintop.net -/*========================================================================*/ +*========================================================================*/ #ifdef DONT_HAVE_STRUPR /* DONT_HAVE_STRUPR is set when INI_REMOVE_CR is defined */ void strupr(char *str) @@ -99,6 +99,7 @@ void strupr(char *str) str++; } } +#else #endif /*========================================================================= @@ -109,10 +110,10 @@ void strupr(char *str) Att : Be sure to call CloseIniFile to free all mem allocated during operation! -/*========================================================================*/ +*========================================================================*/ bool OpenIniFile(cchr *FileName) { - char Str[5120]; + char Str[512]; char *pStr; struct ENTRY *pEntry; @@ -127,7 +128,7 @@ bool OpenIniFile(cchr *FileName) return FALSE; } - while (fgets(Str, 5120, IniFile) != NULL) + while (fgets(Str, 512, IniFile) != NULL) { pStr = strchr(Str, '\n'); if (pStr != NULL) @@ -191,7 +192,7 @@ bool OpenIniFile(cchr *FileName) Job : Frees the memory and closes the ini file without any modifications. If you want to write the file use WriteIniFile instead. -/*========================================================================*/ +*========================================================================*/ void CloseIniFile(void) { FreeAllMem(); @@ -207,7 +208,7 @@ void CloseIniFile(void) ------------------------------------------------------------------------- Job : Writes the iniFile to the disk and close it. Frees all memory allocated by WriteIniFile; -/*========================================================================*/ +==========================================================================*/ bool WriteIniFile(const char *FileName) { struct ENTRY *pEntry = Entry; @@ -242,7 +243,7 @@ bool WriteIniFile(const char *FileName) void WriteString(cchr *Section, cchr *pKey, cchr *Value) { EFIND List; - char Str[5120]; + char Str[512]; if (ArePtrValid(Section, pKey, Value) == FALSE) { @@ -291,6 +292,16 @@ void WriteInt(cchr *Section, cchr *pKey, int Value) WriteString(Section, pKey, Val); } +/*========================================================================= + WriteLong : Writes an long to the ini file +*========================================================================*/ +void WriteLong(cchr *Section, cchr *pKey, long Value) +{ + char Val[22]; /* 64bit maximum + sign + \0 */ + sprintf(Val, "%ld", Value); + WriteString(Section, pKey, Val); +} + /*========================================================================= WriteDouble : Writes a double to the ini file *========================================================================*/ @@ -343,6 +354,16 @@ int ReadInt(cchr *Section, cchr *pKey, int Default) return (atoi(ReadString(Section, pKey, Val))); } +/*========================================================================= + ReadLong : Reads a long from the ini file +*========================================================================*/ +long ReadLong(cchr *Section, cchr *pKey, long Default) +{ + char Val[22]; + sprintf(Val, "%ld", Default); + return (atol(ReadString(Section, pKey, Val))); +} + /*========================================================================= ReadDouble : Reads a double from the ini file *========================================================================*/ @@ -463,7 +484,7 @@ bool FindpKey(cchr *Section, cchr *pKey, EFIND *List) { char Search[130]; char Found[130]; - char Text[5120]; + char Text[512]; char *pText; struct ENTRY *pEntry; List->pSec = NULL; @@ -595,7 +616,7 @@ bool AddItemAt(struct ENTRY *EntryAt, char Mode, cchr *Text) *========================================================================*/ bool AddSectionAndpKey(cchr *Section, cchr *pKey, cchr *Value) { - char Text[5120]; + char Text[512]; sprintf(Text, "[%s]", Section); if (AddItem(tpSECTION, Text) == FALSE) { @@ -610,7 +631,7 @@ bool AddSectionAndpKey(cchr *Section, cchr *pKey, cchr *Value) *========================================================================*/ void AddpKey(struct ENTRY *SecEntry, cchr *pKey, cchr *Value) { - char Text[5120]; + char Text[512]; sprintf(Text, "%s=%s", pKey, Value); AddItemAt(SecEntry, tpKEYVALUE, Text); } diff --git a/source/inifile.h b/source/inifile.h index ce9d02f..e6b3676 100644 --- a/source/inifile.h +++ b/source/inifile.h @@ -5,7 +5,7 @@ Author(s) : Carsten Breuer ------------------------------------------------------------------------ Copyright (c) 2000 by Carsten Breuer (C.Breuer@openwin.de) -/************************************************************************/ +************************************************************************/ #ifndef INIFILE_H #define INIFILE_H @@ -54,11 +54,13 @@ bool OpenIniFile(cchr *FileName); bool ReadBool(cchr *Section, cchr *Key, bool Default); int ReadInt(cchr *Section, cchr *Key, int Default); +long ReadLong(cchr *Section, cchr *Key, long Default); double ReadDouble(cchr *Section, cchr *Key, double Default); cchr *ReadString(cchr *Section, cchr *Key, cchr *Default); void WriteBool(cchr *Section, cchr *Key, bool Value); void WriteInt(cchr *Section, cchr *Key, int Value); +void WriteLong(cchr *Section, cchr *Key, long Value); void WriteDouble(cchr *Section, cchr *Key, double Value); void WriteString(cchr *Section, cchr *Key, cchr *Value); diff --git a/source/installer.cpp b/source/installer.cpp index 2f155c0..25b1323 100644 --- a/source/installer.cpp +++ b/source/installer.cpp @@ -17,9 +17,9 @@ #include "config.h" #include "windows.h" #include "lang.h" -#include "sys_modules.h" +#include "system.h" #include "fs.h" -#include "webdavclient.h" +#include "clients/webdavclient.h" #define BGFT_HEAP_SIZE (1 * 1024 * 1024) @@ -333,6 +333,11 @@ namespace INSTALLER goto err; goto retry; } + else + { + if (auto_delete_tmp_pkg) + FS::Rm(filename); + } } else if (ret > 0) goto err; diff --git a/source/lang.cpp b/source/lang.cpp index 3b73b6b..23b0925 100644 --- a/source/lang.cpp +++ b/source/lang.cpp @@ -127,14 +127,29 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = { "This option enables Remote Package Installation. " "This requires a HTTP Server setup on the same host sharing the same folder with anonymous access.", // STR_ENABLE_RPI_FTP_SMB_MSG "This option enables Remote Package Installation. " - "This requires the Server with anonymous access that does not need username/password.", // STR_ENABLE_RPI_WEBDAV_MSG - "Files", // STR_FILES - "Editor", // STR_EDITOR - "Save", // STR_SAVE - "Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG - "Delete Selected Line", // STR_DELETE_LINE - "Insert Below Selected Line", // STR_INSERT_LINE - "Modified", // STR_MODIFIED + "This requires the Server with anonymous access that does not need username/password.", // STR_ENABLE_RPI_WEBDAV_MSG + "Files", // STR_FILES + "Editor", // STR_EDITOR + "Save", // STR_SAVE + "Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG + "Delete Selected Line", // STR_DELETE_LINE + "Insert Below Selected Line", // STR_INSERT_LINE + "Modified", // STR_MODIFIED + "Failed to obtain an access token from", // STR_FAIL_GET_TOKEN_MSG + "Login Success. You may close the browser and return to the application", // STR_GET_TOKEN_SUCCESS_MSG + "See, edit, create, and delete all of your Google Drive files", // STR_PERM_DRIVE + "See, create, and delete its own configuration data in your Google Drive", // STR_PERM_DRIVE_APPDATA + "See, edit, create, and delete only the specific Google Drive files you use with this app", // STR_PERM_DRIVE_FILE + "View and manage metadata of files in your Google Drive", // STR_PERM_DRIVE_METADATA + "See information about your Google Drive files", // STR_PERM_DRIVE_METADATA_RO + "Google login failed", // STR_GOOGLE_LOGIN_FAIL_MSG + "Google login timed out", // STR_GOOGLE_LOGIN_TIMEOUT_MSG + "New File", // STR_NEW_FILE + "Settings", // STR_SETTINGS + "Client ID", // STR_CLIENT_ID + "Client Secret", // STR_CLIENT_SECRET + "Global", // STR_GLOBAL + "Google", // STR_GOOGLE }; bool needs_extended_font = false; diff --git a/source/lang.h b/source/lang.h index dc8e5bc..bf0a2aa 100644 --- a/source/lang.h +++ b/source/lang.h @@ -126,7 +126,22 @@ FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \ FUNC(STR_DELETE_LINE) \ FUNC(STR_INSERT_LINE) \ - FUNC(STR_MODIFIED) + FUNC(STR_MODIFIED) \ + FUNC(STR_FAIL_GET_TOKEN_MSG) \ + FUNC(STR_GET_TOKEN_SUCCESS_MSG) \ + FUNC(STR_PERM_DRIVE) \ + FUNC(STR_PERM_DRIVE_APPDATA) \ + FUNC(STR_PERM_DRIVE_FILE) \ + FUNC(STR_PERM_DRIVE_METADATA) \ + FUNC(STR_PERM_DRIVE_METADATA_RO) \ + FUNC(STR_GOOGLE_LOGIN_FAIL_MSG) \ + FUNC(STR_GOOGLE_LOGIN_TIMEOUT_MSG) \ + FUNC(STR_NEW_FILE) \ + FUNC(STR_SETTINGS) \ + FUNC(STR_CLIENT_ID) \ + FUNC(STR_CLIENT_SECRET) \ + FUNC(STR_GLOBAL) \ + FUNC(STR_GOOGLE) #define GET_VALUE(x) x, #define GET_STRING(x) #x, @@ -136,7 +151,7 @@ enum FOREACH_STR(GET_VALUE) }; -#define LANG_STRINGS_NUM 123 +#define LANG_STRINGS_NUM 138 #define LANG_ID_SIZE 64 #define LANG_STR_SIZE 384 extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE]; diff --git a/source/main.cpp b/source/main.cpp index 2605445..14c380a 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -11,18 +11,20 @@ #include #include #include -#include +// #include #include "imgui.h" #include "SDL2/SDL.h" #include "imgui_impl_sdl.h" #include "imgui_impl_sdlrenderer.h" +#include "server/http_server.h" +#include "clients/gdrive.h" #include "config.h" #include "lang.h" #include "gui.h" #include "util.h" #include "installer.h" -#include "sys_modules.h" +#include "system.h" extern "C" { @@ -111,7 +113,7 @@ void InitImgui() 0xE0AC, 0xE0AC, // rename 0xE5A1, 0xE5A1, // delete 0xF002, 0xF002, // search - 0x2699, 0x2699, // settings + 0xF013, 0xF013, // settings 0xF0ED, 0xF0ED, // download 0xF0EE, 0xF0EE, // upload 0xF56E, 0xF56E, // extract @@ -261,8 +263,8 @@ static void terminate() int main() { - dbglogger_init(); - dbglogger_log("If you see this you've set up dbglogger correctly."); + // dbglogger_init(); + // dbglogger_log("If you see this you've set up dbglogger correctly."); int rc; // No buffering setvbuf(stdout, NULL, _IONBF, 0); @@ -288,6 +290,7 @@ int main() return 0; CONFIG::LoadConfig(); + HttpServer::Start(); // Create a window context window = SDL_CreateWindow("main", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, FRAME_WIDTH, FRAME_HEIGHT, 0); @@ -317,7 +320,6 @@ int main() atexit(terminate); GUI::RenderLoop(renderer); - SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); diff --git a/source/server/http_server.cpp b/source/server/http_server.cpp new file mode 100644 index 0000000..5f5b4f9 --- /dev/null +++ b/source/server/http_server.cpp @@ -0,0 +1,171 @@ +#include +#include +#include "http/httplib.h" +#include "server/http_server.h" +#include "clients/gdrive.h" +#include "config.h" +#include "windows.h" +#include "lang.h" +#include "system.h" + +#define SERVER_CERT_FILE "/app0/assets/certs/domain.crt" +#define SERVER_PRIVATE_KEY_FILE "/app0/assets/certs/domain.key" +#define SERVER_PRIVATE_KEY_PASSWORD "12345678" + +using namespace httplib; +SSLServer *svr; +int http_server_port = 8080; + +namespace HttpServer +{ + std::string dump_headers(const Headers &headers) + { + std::string s; + char buf[BUFSIZ]; + + for (auto it = headers.begin(); it != headers.end(); ++it) + { + const auto &x = *it; + snprintf(buf, sizeof(buf), "%s: %s\n", x.first.c_str(), x.second.c_str()); + s += buf; + } + + return s; + } + + std::string log(const Request &req, const Response &res) + { + std::string s; + char buf[BUFSIZ]; + + s += "================================\n"; + + snprintf(buf, sizeof(buf), "%s %s %s", req.method.c_str(), + req.version.c_str(), req.path.c_str()); + s += buf; + + std::string query; + for (auto it = req.params.begin(); it != req.params.end(); ++it) + { + const auto &x = *it; + snprintf(buf, sizeof(buf), "%c%s=%s", + (it == req.params.begin()) ? '?' : '&', x.first.c_str(), + x.second.c_str()); + query += buf; + } + snprintf(buf, sizeof(buf), "%s\n", query.c_str()); + s += buf; + + s += dump_headers(req.headers); + + s += "--------------------------------\n"; + + snprintf(buf, sizeof(buf), "%d %s\n", res.status, res.version.c_str()); + s += buf; + s += dump_headers(res.headers); + s += "\n"; + + if (!res.body.empty()) + { + s += res.body; + } + + s += "\n"; + + return s; + } + + void *ServerThread(void *argp) + { + svr->Get("/google_auth", [](const Request &req, Response &res) + { + std::string auth_code = req.get_param_value("code"); + Client client(GOOGLE_OAUTH_HOST); + client.set_follow_location(true); + client.enable_server_certificate_verification(false); + + std::string url = std::string("/token"); + std::string post_data = std::string("code=") + auth_code + + "&client_id=" + gg_app.client_id + + "&client_secret=" + gg_app.client_secret + + "&redirect_uri=https%3A//localhost%3A" + std::to_string(http_server_port) + "/google_auth" + "&grant_type=authorization_code"; + + if (auto result = client.Post(url, post_data.c_str(), post_data.length(), "application/x-www-form-urlencoded")) + { + if (HTTP_SUCCESS(result->status)) + { + json_object *jobj = json_tokener_parse(result.value().body.c_str()); + enum json_type type; + json_object_object_foreach(jobj, key, val) + { + if (strcmp(key, "access_token")==0) + snprintf(remote_settings->gg_account.access_token, 255, "%s", json_object_get_string(val)); + else if (strcmp(key, "refresh_token")==0) + snprintf(remote_settings->gg_account.refresh_token, 255, "%s", json_object_get_string(val)); + else if (strcmp(key, "expires_in")==0) + { + OrbisTick tick; + sceRtcGetCurrentTick(&tick); + remote_settings->gg_account.token_expiry = tick.mytick + (json_object_get_uint64(val)*1000000); + } + } + CONFIG::SaveConfig(); + login_state = 1; + res.set_content(lang_strings[STR_GET_TOKEN_SUCCESS_MSG], "text/plain"); + return; + } + else + { + login_state = -1; + std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google"; + res.set_content(str.c_str(), "text/plain"); + } + } + login_state = -1; + std::string str = std::string(lang_strings[STR_FAIL_GET_TOKEN_MSG]) + " Google"; + res.set_content(str.c_str(), "text/plain"); + }); + + svr->Get("/stop", [&](const Request & /*req*/, Response & /*res*/) + { + svr->stop(); + }); + + svr->set_error_handler([](const Request & /*req*/, Response &res) + { + const char *fmt = "

Error Status: %d

"; + char buf[BUFSIZ]; + snprintf(buf, sizeof(buf), fmt, res.status); + res.set_content(buf, "text/html"); + }); + + /* + svr->set_logger([](const Request &req, const Response &res) + { + dbglogger_log("%s", log(req, res).c_str()); + }); + */ + + svr->listen("127.0.0.1", http_server_port); + + return NULL; + } + + void Start() + { + if (svr == nullptr) + svr = new SSLServer(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE, nullptr, nullptr, SERVER_PRIVATE_KEY_PASSWORD); + if (!svr->is_valid()) + { + return; + } + int ret = pthread_create(&http_server_thid, NULL, ServerThread, NULL); + } + + void Stop() + { + if (svr != nullptr) + svr->stop(); + } +} \ No newline at end of file diff --git a/source/server/http_server.h b/source/server/http_server.h new file mode 100644 index 0000000..faf77e8 --- /dev/null +++ b/source/server/http_server.h @@ -0,0 +1,19 @@ +#ifndef HTTP_SERVER_H +#define HTTP_SERVER_H + +#include "http/httplib.h" + +using namespace httplib; +extern SSLServer *svr; + +static pthread_t http_server_thid; +extern int http_server_port; + +namespace HttpServer +{ + void *ServerThread(void *argp); + void Start(); + void Stop(); +} + +#endif \ No newline at end of file diff --git a/source/sys_modules.cpp b/source/system.cpp similarity index 84% rename from source/sys_modules.cpp rename to source/system.cpp index 573a044..f6b56f2 100644 --- a/source/sys_modules.cpp +++ b/source/system.cpp @@ -2,13 +2,15 @@ #include #include -#include "sys_modules.h" +#include "system.h" int (*sceRtcGetTick)(const OrbisDateTime *inOrbisDateTime, OrbisTick *outTick); int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *inputTick); int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc); int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time); int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time); +int (*sceRtcGetCurrentTick)(OrbisTick *outTick); +unsigned int (*sceRtcGetTickResolution)(); int (*sceShellUIUtilLaunchByUri)(const char *uri, SceShellUIUtilLaunchByUriParam *param); int (*sceShellUIUtilInitialize)(); @@ -68,6 +70,18 @@ int load_sys_modules() return -1; } + sceKernelDlsym(handle, "sceRtcGetCurrentTick", (void **)&sceRtcGetCurrentTick); + if (sceRtcGetCurrentTick == NULL) + { + return -1; + } + + sceKernelDlsym(handle, "sceRtcGetTickResolution", (void **)&sceRtcGetTickResolution); + if (sceRtcGetTickResolution == NULL) + { + return -1; + } + handle = sceKernelLoadStartModule("/system/common/lib/libSceShellUIUtil.sprx", 0, NULL, 0, 0, 0); if (handle == 0) { @@ -86,6 +100,7 @@ int load_sys_modules() return -1; } + if (sceShellUIUtilInitialize() < 0) return -1; return 0; } \ No newline at end of file diff --git a/source/sys_modules.h b/source/system.h similarity index 92% rename from source/sys_modules.h rename to source/system.h index 24d69eb..591a9e0 100644 --- a/source/sys_modules.h +++ b/source/system.h @@ -29,6 +29,8 @@ extern int (*sceRtcSetTick)(OrbisDateTime *outOrbisDateTime, const OrbisTick *in extern int (*sceRtcConvertLocalTimeToUtc)(const OrbisTick *local_time, OrbisTick *utc); extern int (*sceRtcConvertUtcToLocalTime)(const OrbisTick *utc, OrbisTick *local_time); extern int (*sceRtcGetCurrentClockLocalTime)(OrbisDateTime *time); +extern int (*sceRtcGetCurrentTick)(OrbisTick *outTick); +extern unsigned int (*sceRtcGetTickResolution)(); extern int (*sceShellUIUtilLaunchByUri)(const char *uri, SceShellUIUtilLaunchByUriParam *param); extern int (*sceShellUIUtilInitialize)(); diff --git a/source/util.h b/source/util.h index 48160b4..1b49b20 100644 --- a/source/util.h +++ b/source/util.h @@ -6,6 +6,7 @@ #include #include #include +#include "lang.h" namespace Util { @@ -81,5 +82,23 @@ namespace Util sceKernelSendNotificationRequest(0, &request, sizeof(request), 0); } + static inline void SetupPreviousFolder(const std::string &path, DirEntry *entry) + { + memset(entry, 0, sizeof(DirEntry)); + if (path[path.length() - 1] == '/' && path.length() > 1) + { + strlcpy(entry->directory, path.c_str(), path.length() - 1); + } + else + { + sprintf(entry->directory, "%s", path.c_str()); + } + sprintf(entry->name, "%s", ".."); + sprintf(entry->path, "%s", entry->directory); + sprintf(entry->display_size, "%s", lang_strings[STR_FOLDER]); + entry->file_size = 0; + entry->isDir = true; + entry->selectable = false; + } } #endif diff --git a/source/windows.cpp b/source/windows.cpp index 2457236..dddd698 100644 --- a/source/windows.cpp +++ b/source/windows.cpp @@ -13,6 +13,8 @@ #include "lang.h" #include "ime_dialog.h" #include "IconsFontAwesome6.h" +#include "server/http_server.h" +#include "clients/gdrive.h" extern "C" { @@ -51,7 +53,7 @@ char local_file_to_select[256]; char remote_file_to_select[256]; char local_filter[32]; char remote_filter[32]; -char editor_text[1024]; +char dialog_editor_text[1024]; char activity_message[1024]; int selected_browser = 0; int saved_selected_browser; @@ -64,6 +66,7 @@ bool select_url_inprogress = false; int favorite_url_idx = 0; char extract_zip_folder[256]; char zip_file_path[384]; +bool show_settings = false; // Editor variables std::vector edit_buffer; @@ -322,6 +325,8 @@ namespace Windows int width = 550; if (remote_settings->type == CLIENT_TYPE_HTTP_SERVER) width = 500; + else if (remote_settings->type == CLIENT_TYPE_GOOGLE) + width = 600; pos = ImGui::GetCursorPos(); if (ImGui::Button(id, ImVec2(width, 0))) { @@ -360,9 +365,12 @@ namespace Windows ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_USERNAME]); ImGui::SameLine(); + width = 180; + if (remote_settings->type == CLIENT_TYPE_GOOGLE) + width = 480; sprintf(id, "%s##username", remote_settings->username); pos = ImGui::GetCursorPos(); - if (ImGui::Button(id, ImVec2(180, 0))) + if (ImGui::Button(id, ImVec2(width, 0))) { ime_single_field = remote_settings->username; ResetImeCallbacks(); @@ -373,63 +381,79 @@ namespace Windows } ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_PASSWORD]); - ImGui::SameLine(); - - sprintf(id, "%s##password", hidden_password.c_str()); - pos = ImGui::GetCursorPos(); - if (ImGui::Button(id, ImVec2(100, 0))) + if (remote_settings->type != CLIENT_TYPE_GOOGLE) { - ime_single_field = remote_settings->password; - ResetImeCallbacks(); - ime_field_size = 24; - ime_callback = SingleValueImeCallback; - Dialog::initImeDialog(lang_strings[STR_PASSWORD], remote_settings->password, 24, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y); - gui_mode = GUI_MODE_IME; - } - - ImGui::SameLine(); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_ENABLE_RPI]); - ImGui::SameLine(); - - if (ImGui::Checkbox("###enable_rpi", &remote_settings->enable_rpi)) - { - CONFIG::SaveConfig(); - } - if (ImGui::IsItemHovered()) - { - ImGui::SetNextWindowSize(ImVec2(450, 135)); - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 440); - ImGui::Text("%s", (remote_settings->type == CLIENT_TYPE_SMB || remote_settings->type == CLIENT_TYPE_FTP) ? lang_strings[STR_ENABLE_RPI_FTP_SMB_MSG] : lang_strings[STR_ENABLE_RPI_WEBDAV_MSG]); - ImGui::PopTextWrapPos(); - ImGui::EndTooltip(); - } - - if ((remote_settings->type == CLIENT_TYPE_SMB || remote_settings->type == CLIENT_TYPE_FTP) && remote_settings->enable_rpi) - { - ImGui::SameLine(); ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); - ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_HTTP_PORT]); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_PASSWORD]); ImGui::SameLine(); - sprintf(id, "%s##http_port", txt_http_port); + sprintf(id, "%s##password", hidden_password.c_str()); pos = ImGui::GetCursorPos(); - if (ImGui::Button(id, ImVec2(65, 0))) + if (ImGui::Button(id, ImVec2(100, 0))) { - ime_single_field = txt_http_port; + ime_single_field = remote_settings->password; ResetImeCallbacks(); ime_field_size = 24; ime_callback = SingleValueImeCallback; - ime_after_update = AfterHttpPortChangeCallback; - Dialog::initImeDialog(lang_strings[STR_PASSWORD], txt_http_port, 24, ORBIS_TYPE_NUMBER, pos.x, pos.y); + Dialog::initImeDialog(lang_strings[STR_PASSWORD], remote_settings->password, 24, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y); gui_mode = GUI_MODE_IME; } + + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_ENABLE_RPI]); + ImGui::SameLine(); + + if (ImGui::Checkbox("###enable_rpi", &remote_settings->enable_rpi)) + { + CONFIG::SaveConfig(); + } + if (ImGui::IsItemHovered()) + { + ImGui::SetNextWindowSize(ImVec2(450, 135)); + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + 440); + ImGui::Text("%s", (remote_settings->type == CLIENT_TYPE_SMB || remote_settings->type == CLIENT_TYPE_FTP) ? lang_strings[STR_ENABLE_RPI_FTP_SMB_MSG] : lang_strings[STR_ENABLE_RPI_WEBDAV_MSG]); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + + if ((remote_settings->type == CLIENT_TYPE_SMB || remote_settings->type == CLIENT_TYPE_FTP) && remote_settings->enable_rpi) + { + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s:", lang_strings[STR_HTTP_PORT]); + ImGui::SameLine(); + + sprintf(id, "%s##http_port", txt_http_port); + pos = ImGui::GetCursorPos(); + if (ImGui::Button(id, ImVec2(65, 0))) + { + ime_single_field = txt_http_port; + ResetImeCallbacks(); + ime_field_size = 24; + ime_callback = SingleValueImeCallback; + ime_after_update = AfterHttpPortChangeCallback; + Dialog::initImeDialog(lang_strings[STR_PASSWORD], txt_http_port, 24, ORBIS_TYPE_NUMBER, pos.x, pos.y); + gui_mode = GUI_MODE_IME; + } + } + } + ImGui::PopStyleVar(); + + ImGui::SameLine(); + ImGui::SetCursorPosX(1870); + if (ImGui::Button(ICON_FA_GEAR, ImVec2(35, 0))) + { + show_settings = true; + } + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::Text("%s", lang_strings[STR_SETTINGS]); + ImGui::EndTooltip(); } - ImGui::PopStyleVar(); ImGui::Dummy(ImVec2(0, 10)); EndGroupPanel(); } @@ -528,60 +552,64 @@ namespace Windows set_focus_to_local = false; ImGui::SetWindowFocus(); } - for (int j = 0; j < local_files.size(); j++) - { - DirEntry item = local_files[j]; - ImGui::SetColumnWidth(-1, 740); - ImGui::PushID(i); - auto search_item = multi_selected_local_files.find(item); - if (search_item != multi_selected_local_files.end()) + ImGuiListClipper local_clipper; + local_clipper.Begin(local_files.size()); + while (local_clipper.Step()) + for (int j = local_clipper.DisplayStart; j < local_clipper.DisplayEnd; j++) { - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255)); - } - if (ImGui::Selectable(item.name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(919, 0))) - { - if (item.isDir) + DirEntry item = local_files[j]; + ImGui::SetColumnWidth(-1, 740); + ImGui::PushID(i); + auto search_item = multi_selected_local_files.find(item); + if (search_item != multi_selected_local_files.end()) + { + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255)); + } + if (ImGui::Selectable(item.name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(919, 0))) + { + if (item.isDir) + { + selected_local_file = item; + selected_action = ACTION_CHANGE_LOCAL_DIRECTORY; + } + } + ImGui::PopID(); + if (ImGui::IsItemFocused()) { selected_local_file = item; - selected_action = ACTION_CHANGE_LOCAL_DIRECTORY; } - } - ImGui::PopID(); - if (ImGui::IsItemFocused()) - { - selected_local_file = item; - } - if (ImGui::IsItemHovered()) - { - if (ImGui::CalcTextSize(item.name).x > 740) + if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text("%s", item.name); - ImGui::EndTooltip(); + if (ImGui::CalcTextSize(item.name).x > 740) + { + ImGui::BeginTooltip(); + ImGui::Text("%s", item.name); + ImGui::EndTooltip(); + } } - } - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) - { - if (strcmp(local_file_to_select, item.name) == 0) + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) { - SetNavFocusHere(); - ImGui::SetScrollHereY(0.5f); - sprintf(local_file_to_select, ""); + if (strcmp(local_file_to_select, item.name) == 0) + { + SetNavFocusHere(); + ImGui::SetScrollHereY(0.5f); + sprintf(local_file_to_select, ""); + } + selected_browser |= LOCAL_BROWSER; } - selected_browser |= LOCAL_BROWSER; + ImGui::NextColumn(); + ImGui::SetColumnWidth(-1, 150); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(item.display_size).x - ImGui::GetScrollX() - ImGui::GetStyle().ItemSpacing.x); + ImGui::Text("%s", item.display_size); + if (search_item != multi_selected_local_files.end()) + { + ImGui::PopStyleColor(); + } + ImGui::NextColumn(); + ImGui::Separator(); + i++; } - ImGui::NextColumn(); - ImGui::SetColumnWidth(-1, 150); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(item.display_size).x - ImGui::GetScrollX() - ImGui::GetStyle().ItemSpacing.x); - ImGui::Text("%s", item.display_size); - if (search_item != multi_selected_local_files.end()) - { - ImGui::PopStyleColor(); - } - ImGui::NextColumn(); - ImGui::Separator(); - i++; - } + local_clipper.End(); ImGui::Columns(1); ImGui::EndChild(); EndGroupPanel(); @@ -672,61 +700,65 @@ namespace Windows ImGui::Separator(); ImGui::Columns(2, "Remote##Columns", true); i = 99999; - for (int j = 0; j < remote_files.size(); j++) - { - DirEntry item = remote_files[j]; + ImGuiListClipper remote_clipper; + remote_clipper.Begin(remote_files.size()); + while (remote_clipper.Step()) + for (int j = remote_clipper.DisplayStart; j < remote_clipper.DisplayEnd; j++) + { + DirEntry item = remote_files[j]; - ImGui::SetColumnWidth(-1, 740); - auto search_item = multi_selected_remote_files.find(item); - if (search_item != multi_selected_remote_files.end()) - { - ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255)); - } - ImGui::PushID(i); - if (ImGui::Selectable(item.name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(919, 0))) - { - if (item.isDir) + ImGui::SetColumnWidth(-1, 740); + auto search_item = multi_selected_remote_files.find(item); + if (search_item != multi_selected_remote_files.end()) + { + ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255)); + } + ImGui::PushID(i); + if (ImGui::Selectable(item.name, false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(919, 0))) + { + if (item.isDir) + { + selected_remote_file = item; + selected_action = ACTION_CHANGE_REMOTE_DIRECTORY; + } + } + if (ImGui::IsItemFocused()) { selected_remote_file = item; - selected_action = ACTION_CHANGE_REMOTE_DIRECTORY; } - } - if (ImGui::IsItemFocused()) - { - selected_remote_file = item; - } - if (ImGui::IsItemHovered()) - { - if (ImGui::CalcTextSize(item.name).x > 740) + if (ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text("%s", item.name); - ImGui::EndTooltip(); + if (ImGui::CalcTextSize(item.name).x > 740) + { + ImGui::BeginTooltip(); + ImGui::Text("%s", item.name); + ImGui::EndTooltip(); + } } - } - ImGui::PopID(); - if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) - { - if (strcmp(remote_file_to_select, item.name) == 0) + ImGui::PopID(); + if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) { - SetNavFocusHere(); - ImGui::SetScrollHereY(0.5f); - sprintf(remote_file_to_select, ""); + if (strcmp(remote_file_to_select, item.name) == 0) + { + SetNavFocusHere(); + ImGui::SetScrollHereY(0.5f); + sprintf(remote_file_to_select, ""); + } + selected_browser |= REMOTE_BROWSER; } - selected_browser |= REMOTE_BROWSER; + ImGui::NextColumn(); + ImGui::SetColumnWidth(-1, 150); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(item.display_size).x - ImGui::GetScrollX() - ImGui::GetStyle().ItemSpacing.x); + ImGui::Text("%s", item.display_size); + if (search_item != multi_selected_remote_files.end()) + { + ImGui::PopStyleColor(); + } + ImGui::NextColumn(); + ImGui::Separator(); + i++; } - ImGui::NextColumn(); - ImGui::SetColumnWidth(-1, 150); - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetColumnWidth() - ImGui::CalcTextSize(item.display_size).x - ImGui::GetScrollX() - ImGui::GetStyle().ItemSpacing.x); - ImGui::Text("%s", item.display_size); - if (search_item != multi_selected_remote_files.end()) - { - ImGui::PopStyleColor(); - } - ImGui::NextColumn(); - ImGui::Separator(); - i++; - } + remote_clipper.End(); ImGui::Columns(1); ImGui::EndChild(); EndGroupPanel(); @@ -793,13 +825,13 @@ namespace Windows bool remote_browser_selected = saved_selected_browser & REMOTE_BROWSER; if (local_browser_selected) { - ImGui::SetNextWindowPos(ImVec2(410, 300)); + ImGui::SetNextWindowPos(ImVec2(410, 280)); } else if (remote_browser_selected) { - ImGui::SetNextWindowPos(ImVec2(1330, 300)); + ImGui::SetNextWindowPos(ImVec2(1330, 280)); } - ImGui::SetNextWindowSizeConstraints(ImVec2(230, 150), ImVec2(230, 600), NULL, NULL); + ImGui::SetNextWindowSizeConstraints(ImVec2(230, 150), ImVec2(230, 625), NULL, NULL); if (ImGui::BeginPopupModal(lang_strings[STR_ACTIONS], NULL, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::PushID("Select All##settings"); @@ -932,9 +964,28 @@ namespace Windows ImGui::PopID(); ImGui::Separator(); + ImGui::PushID("New File##settings"); + flags = ImGuiSelectableFlags_None; + if (remote_browser_selected && remoteclient != nullptr && !(remoteclient->SupportedActions() & REMOTE_ACTION_NEW_FILE)) + { + flags = ImGuiSelectableFlags_Disabled; + } + if (ImGui::Selectable(lang_strings[STR_NEW_FILE], false, flags | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0))) + { + if (local_browser_selected) + selected_action = ACTION_NEW_LOCAL_FILE; + else if (remote_browser_selected) + selected_action = ACTION_NEW_REMOTE_FILE; + SetModalMode(false); + ImGui::CloseCurrentPopup(); + } + ImGui::PopID(); + ImGui::Separator(); + ImGui::PushID("Edit##settings"); flags = ImGuiSelectableFlags_None; - if (remote_browser_selected && remoteclient != nullptr && !(remoteclient->SupportedActions() & REMOTE_ACTION_EDIT)) + if ((remote_browser_selected && remoteclient != nullptr && (!(remoteclient->SupportedActions() & REMOTE_ACTION_EDIT) || selected_remote_file.isDir)) || + (local_browser_selected && selected_local_file.isDir)) { flags = ImGuiSelectableFlags_Disabled; } @@ -1321,13 +1372,6 @@ namespace Windows ImGui::CloseCurrentPopup(); } - if (ImGui::Checkbox("##auto_delete_tmp_pkg", &auto_delete_tmp_pkg)) - { - CONFIG::SaveConfig(); - } - ImGui::SameLine(); - ImGui::Text("%s", lang_strings[STR_AUTO_DELETE_TMP_PKG]); - ImGui::Separator(); for (int j = 0; j < MAX_FAVORITE_URLS; j++) { @@ -1496,7 +1540,7 @@ namespace Windows insert_item = -1; ImGui::EndChild(); - ImGui::Text("%s%s", (editor_modified? "**" : ""), edit_file); + 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::EndPopup(); @@ -1504,6 +1548,85 @@ namespace Windows } } + void ShowSettingsDialog() + { + if (show_settings) + { + ImGuiIO &io = ImGui::GetIO(); + (void)io; + ImGuiStyle *style = &ImGui::GetStyle(); + ImVec4 *colors = style->Colors; + + SetModalMode(true); + ImGui::OpenPopup(lang_strings[STR_SETTINGS]); + + ImGui::SetNextWindowPos(ImVec2(1150, 80)); + ImGui::SetNextWindowSizeConstraints(ImVec2(750, 80), ImVec2(750, 400), NULL, NULL); + if (ImGui::BeginPopupModal(lang_strings[STR_SETTINGS], NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GLOBAL]); + ImGui::Separator(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15); + ImGui::Text("%s", lang_strings[STR_AUTO_DELETE_TMP_PKG]); + ImGui::SameLine(); + ImGui::SetCursorPosX(705); + ImGui::Checkbox("##auto_delete_tmp_pkg", &auto_delete_tmp_pkg); + ImGui::Separator(); + ImGui::TextColored(colors[ImGuiCol_ButtonHovered], "%s", lang_strings[STR_GOOGLE]); + ImGui::Separator(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 15); + ImGui::Text("%s", lang_strings[STR_CLIENT_ID]); + ImGui::SameLine(); + ImGui::SetCursorPosX(163); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f)); + if (ImGui::Button(gg_app.client_id, ImVec2(580, 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); + 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); + 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))) + { + 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); + gui_mode = GUI_MODE_IME; + } + ImGui::PopStyleVar(); + ImGui::Separator(); + sprintf(id, "%s##settings", lang_strings[STR_CLOSE]); + if (ImGui::Button(id, ImVec2(735, 0))) + { + show_settings = false; + CONFIG::SaveGlobalConfig(); + SetModalMode(false); + ImGui::CloseCurrentPopup(); + } + if (ImGui::IsWindowAppearing()) + { + ImGui::SetItemDefaultFocus(); + } + ImGui::SameLine(); + ImGui::EndPopup(); + } + } + } + void MainWindow() { Windows::SetupWindow(); @@ -1522,6 +1645,7 @@ namespace Windows ShowActionsDialog(); ShowFavoriteUrlsDialog(); ShowEditorDialog(); + ShowSettingsDialog(); } ImGui::End(); } @@ -1552,17 +1676,19 @@ namespace Windows break; case ACTION_NEW_LOCAL_FOLDER: case ACTION_NEW_REMOTE_FOLDER: + case ACTION_NEW_LOCAL_FILE: + case ACTION_NEW_REMOTE_FILE: if (gui_mode != GUI_MODE_IME) { - sprintf(editor_text, ""); - ime_single_field = editor_text; + sprintf(dialog_editor_text, ""); + ime_single_field = dialog_editor_text; ResetImeCallbacks(); ime_field_size = 128; 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], editor_text, 128, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y); + Dialog::initImeDialog(lang_strings[STR_NEW_FOLDER], dialog_editor_text, 128, ORBIS_TYPE_BASIC_LATIN, pos.x, pos.y); gui_mode = GUI_MODE_IME; } break; @@ -1622,16 +1748,16 @@ namespace Windows if (gui_mode != GUI_MODE_IME) { if (multi_selected_local_files.size() > 0) - sprintf(editor_text, "%s", multi_selected_local_files.begin()->name); + sprintf(dialog_editor_text, "%s", multi_selected_local_files.begin()->name); else - sprintf(editor_text, "%s", selected_local_file.name); - ime_single_field = editor_text; + sprintf(dialog_editor_text, "%s", selected_local_file.name); + ime_single_field = dialog_editor_text; ResetImeCallbacks(); ime_field_size = 128; ime_after_update = AfterFolderNameCallback; ime_cancelled = CancelActionCallBack; ime_callback = SingleValueImeCallback; - Dialog::initImeDialog(lang_strings[STR_RENAME], editor_text, 128, ORBIS_TYPE_BASIC_LATIN, 410, 350); + Dialog::initImeDialog(lang_strings[STR_RENAME], dialog_editor_text, 128, ORBIS_TYPE_BASIC_LATIN, 410, 350); gui_mode = GUI_MODE_IME; } break; @@ -1639,16 +1765,16 @@ namespace Windows if (gui_mode != GUI_MODE_IME) { if (multi_selected_remote_files.size() > 0) - sprintf(editor_text, "%s", multi_selected_remote_files.begin()->name); + sprintf(dialog_editor_text, "%s", multi_selected_remote_files.begin()->name); else - sprintf(editor_text, "%s", selected_remote_file.name); - ime_single_field = editor_text; + sprintf(dialog_editor_text, "%s", selected_remote_file.name); + ime_single_field = dialog_editor_text; ResetImeCallbacks(); ime_field_size = 128; ime_after_update = AfterFolderNameCallback; ime_cancelled = CancelActionCallBack; ime_callback = SingleValueImeCallback; - Dialog::initImeDialog(lang_strings[STR_RENAME], editor_text, 128, ORBIS_TYPE_BASIC_LATIN, 1330, 350); + Dialog::initImeDialog(lang_strings[STR_RENAME], dialog_editor_text, 128, ORBIS_TYPE_BASIC_LATIN, 1330, 350); gui_mode = GUI_MODE_IME; } break; @@ -1684,6 +1810,8 @@ namespace Windows break; case ACTION_DISCONNECT_AND_EXIT: Actions::Disconnect(); + HttpServer::Stop(); + GDriveClient::StopRefreshToken(); done = true; break; case ACTION_INSTALL_REMOTE_PKG: @@ -1874,27 +2002,34 @@ namespace Windows void AfterFolderNameCallback(int ime_result) { - if (selected_action == ACTION_NEW_LOCAL_FOLDER) - { - Actions::CreateNewLocalFolder(editor_text); - } - else if (selected_action == ACTION_NEW_REMOTE_FOLDER) - { - Actions::CreateNewRemoteFolder(editor_text); - } - else if (selected_action == ACTION_RENAME_LOCAL) + switch (selected_action) { + case ACTION_NEW_LOCAL_FOLDER: + Actions::CreateNewLocalFolder(dialog_editor_text); + break; + case ACTION_NEW_REMOTE_FOLDER: + Actions::CreateNewRemoteFolder(dialog_editor_text); + break; + case ACTION_RENAME_LOCAL: if (multi_selected_local_files.size() > 0) - Actions::RenameLocalFolder(multi_selected_local_files.begin()->path, editor_text); + Actions::RenameLocalFolder(multi_selected_local_files.begin()->path, dialog_editor_text); else - Actions::RenameLocalFolder(selected_local_file.path, editor_text); - } - else if (selected_action == ACTION_RENAME_REMOTE) - { + Actions::RenameLocalFolder(selected_local_file.path, dialog_editor_text); + break; + case ACTION_RENAME_REMOTE: if (multi_selected_remote_files.size() > 0) - Actions::RenameRemoteFolder(multi_selected_remote_files.begin()->path, editor_text); + Actions::RenameRemoteFolder(multi_selected_remote_files.begin()->path, dialog_editor_text); else - Actions::RenameRemoteFolder(selected_remote_file.path, editor_text); + Actions::RenameRemoteFolder(selected_remote_file.path, dialog_editor_text); + break; + case ACTION_NEW_LOCAL_FILE: + Actions::CreateLocalFile(dialog_editor_text); + break; + case ACTION_NEW_REMOTE_FILE: + Actions::CreateRemoteFile(dialog_editor_text); + break; + default: + break; } selected_action = ACTION_NONE; } diff --git a/source/zip_util.cpp b/source/zip_util.cpp index 5cd26a5..205b4a2 100644 --- a/source/zip_util.cpp +++ b/source/zip_util.cpp @@ -12,7 +12,7 @@ #include "common.h" #include "fs.h" #include "lang.h" -#include "sys_modules.h" +#include "system.h" #include "windows.h" #include "zip_util.h"