752 lines
24 KiB
C++
752 lines
24 KiB
C++
/*
|
|
Copyright (c) 2013-2015 pCloud Ltd. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met: Redistributions of source code must retain the above
|
|
copyright notice, this list of conditions and the following
|
|
disclaimer. Redistributions in binary form must reproduce the above
|
|
copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with
|
|
the distribution. Neither the name of pCloud Ltd nor the names of
|
|
its contributors may be used to endorse or promote products derived
|
|
from this software without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL pCloud
|
|
Ltd BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE.
|
|
*/
|
|
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <string>
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <termios.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "pclsync/pcryptofolder.h"
|
|
#include "pclsync/pfoldersync.h"
|
|
#include "pclsync/pmem.h"
|
|
#include "pclsync/prpc.h"
|
|
#include "pclsync/psynclib.h"
|
|
#include "pclsync/pshm.h"
|
|
#include "pclsync/pdevice.h"
|
|
#include "pclsync/pcommands.h"
|
|
#include "pclsync/putil.h"
|
|
#include "pclsync/pdbg.h"
|
|
#include "pclsync/psock.h"
|
|
#include "pclsync/plibs.h"
|
|
#include "pclsync/psignal.h"
|
|
|
|
#include "pclsync_lib.h"
|
|
|
|
namespace cc = console_client;
|
|
namespace clib = cc::clibrary;
|
|
|
|
static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
|
|
static pthread_mutex_t tfa_mtx = PTHREAD_MUTEX_INITIALIZER;
|
|
static pthread_cond_t tfa_cond = PTHREAD_COND_INITIALIZER;
|
|
static pthread_mutex_t auth_mtx = PTHREAD_MUTEX_INITIALIZER;
|
|
static pthread_cond_t auth_cond = PTHREAD_COND_INITIALIZER;
|
|
|
|
static const std::string client_name = "pCloud CC v3.0.0";
|
|
|
|
static const char *psync_error_to_string(uint32_t error_code) {
|
|
switch (error_code) {
|
|
case PERROR_LOCAL_FOLDER_NOT_FOUND:
|
|
return "local folder not found";
|
|
case PERROR_REMOTE_FOLDER_NOT_FOUND:
|
|
return "remote folder not found";
|
|
case PERROR_DATABASE_OPEN:
|
|
return "failed to open database";
|
|
case PERROR_NO_HOMEDIR:
|
|
return "cannot determine home directory or create .pcloud directory";
|
|
case PERROR_SSL_INIT_FAILED:
|
|
return "SSL initialization failed";
|
|
case PERROR_DATABASE_ERROR:
|
|
return "database error";
|
|
case PERROR_LOCAL_FOLDER_ACC_DENIED:
|
|
return "local folder access denied";
|
|
case PERROR_REMOTE_FOLDER_ACC_DENIED:
|
|
return "remote folder access denied";
|
|
case PERROR_FOLDER_ALREADY_SYNCING:
|
|
return "folder already syncing";
|
|
case PERROR_INVALID_SYNCTYPE:
|
|
return "invalid sync type";
|
|
case PERROR_OFFLINE:
|
|
return "offline";
|
|
case PERROR_INVALID_SYNCID:
|
|
return "invalid sync ID";
|
|
case PERROR_PARENT_OR_SUBFOLDER_ALREADY_SYNCING:
|
|
return "parent or subfolder already syncing";
|
|
case PERROR_LOCAL_IS_ON_PDRIVE:
|
|
return "local path is on pCloud Drive";
|
|
case PERROR_NO_MEMORY:
|
|
return "out of memory";
|
|
case PERROR_NET_ERROR:
|
|
return "network error";
|
|
case PERROR_PARENT_IS_IGNORED:
|
|
return "parent folder is ignored";
|
|
default:
|
|
return "unknown error";
|
|
}
|
|
}
|
|
|
|
clib::pclsync_lib::pclsync_lib()
|
|
: setup_crypto_(false), status_(new pstatus_struct_()), was_init_(false) {}
|
|
|
|
clib::pclsync_lib::~pclsync_lib() {}
|
|
|
|
const bool clib::pclsync_lib::get_trusted_device() { return trusted_device_; };
|
|
|
|
const std::string &clib::pclsync_lib::get_tfa_code() { return tfa_code_; }
|
|
|
|
const std::string &clib::pclsync_lib::get_username() { return username_; }
|
|
|
|
const std::string &clib::pclsync_lib::get_password() { return password_; }
|
|
|
|
const std::string &clib::pclsync_lib::get_crypto_pass() {
|
|
return crypto_pass_;
|
|
};
|
|
|
|
void clib::pclsync_lib::wipe_crypto_pass() {
|
|
this->wipe(crypto_pass_);
|
|
}
|
|
|
|
void clib::pclsync_lib::wipe_password() {
|
|
this->wipe(password_);
|
|
}
|
|
|
|
void clib::pclsync_lib::wipe_tfa_code() {
|
|
this->wipe(tfa_code_);
|
|
}
|
|
|
|
const std::string &clib::pclsync_lib::get_mount() { return mount_; }
|
|
|
|
void clib::pclsync_lib::set_trusted_device(bool arg) {
|
|
trusted_device_ = arg;
|
|
}
|
|
void clib::pclsync_lib::set_tfa_code(const std::string &arg) {
|
|
tfa_code_ = arg;
|
|
}
|
|
void clib::pclsync_lib::set_username(const std::string &arg) {
|
|
username_ = arg;
|
|
}
|
|
void clib::pclsync_lib::set_password(const std::string &arg) {
|
|
password_ = arg;
|
|
}
|
|
void clib::pclsync_lib::set_crypto_pass(const std::string &arg) {
|
|
crypto_pass_ = arg;
|
|
};
|
|
void clib::pclsync_lib::set_mount(const std::string &arg) { mount_ = arg; }
|
|
void clib::pclsync_lib::set_savepass(bool s) { save_pass_ = s; }
|
|
void clib::pclsync_lib::setupsetup_crypto(bool p) { setup_crypto_ = p; }
|
|
void clib::pclsync_lib::set_newuser(bool p) { newuser_ = p; }
|
|
void clib::pclsync_lib::set_daemon(bool p) { daemon_ = p; }
|
|
void clib::pclsync_lib::set_status_callback(status_callback_t p) {
|
|
status_callback_ = p;
|
|
}
|
|
|
|
clib::pclsync_lib &clib::pclsync_lib::get_lib() {
|
|
static clib::pclsync_lib g_lib;
|
|
return g_lib;
|
|
}
|
|
|
|
void clib::pclsync_lib::read_password() {
|
|
if (daemon_) {
|
|
syslog(LOG_NOTICE,
|
|
"pcloudcc: password required. "
|
|
"Provide with: echo 'auth PASSWORD' | pcloudcc -k");
|
|
pthread_mutex_lock(&auth_mtx);
|
|
while (password_.empty()) {
|
|
pthread_cond_wait(&auth_cond, &auth_mtx);
|
|
}
|
|
pthread_mutex_unlock(&auth_mtx);
|
|
return;
|
|
}
|
|
read_from_stdin(password_);
|
|
}
|
|
|
|
int clib::pclsync_lib::receive_auth(const char *pass) {
|
|
pthread_mutex_lock(&auth_mtx);
|
|
get_lib().password_ = std::string(pass);
|
|
pthread_cond_signal(&auth_cond);
|
|
pthread_mutex_unlock(&auth_mtx);
|
|
std::cout << "Auth received." << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
void clib::pclsync_lib::read_tfa_code(bool auto_sms)
|
|
{
|
|
if (daemon_) {
|
|
if (auto_sms) {
|
|
char *country_code = nullptr;
|
|
char *phone_number = nullptr;
|
|
int result = psync_tfa_send_sms(&country_code, &phone_number);
|
|
if (result == 0) {
|
|
if (country_code && phone_number) {
|
|
syslog(LOG_NOTICE,
|
|
"pcloudcc: 2FA required. SMS sent to +%s %s. "
|
|
"Provide code with: echo 'tfa CODE' | pcloudcc -k",
|
|
country_code, phone_number);
|
|
pmem_free(PMEM_SUBSYS_OTHER, country_code);
|
|
pmem_free(PMEM_SUBSYS_OTHER, phone_number);
|
|
} else {
|
|
syslog(LOG_NOTICE,
|
|
"pcloudcc: 2FA required. SMS sent. "
|
|
"Provide code with: echo 'tfa CODE' | pcloudcc -k");
|
|
}
|
|
} else {
|
|
syslog(LOG_WARNING,
|
|
"pcloudcc: 2FA required but SMS failed (error %d). "
|
|
"Provide code with: echo 'tfa CODE' | pcloudcc -k", result);
|
|
}
|
|
} else {
|
|
syslog(LOG_WARNING,
|
|
"pcloudcc: 2FA code was rejected. "
|
|
"Provide correct code with: echo 'tfa CODE' | pcloudcc -k");
|
|
}
|
|
|
|
// Block until code arrives via RPC (pcloudcc -k)
|
|
pthread_mutex_lock(&tfa_mtx);
|
|
while (tfa_code_.empty()) {
|
|
pthread_cond_wait(&tfa_cond, &tfa_mtx);
|
|
}
|
|
pthread_mutex_unlock(&tfa_mtx);
|
|
return;
|
|
}
|
|
|
|
// Interactive mode
|
|
std::cout << "2FA required. Enter code from authenticator app, or type 'sms' to receive code via SMS: ";
|
|
std::string input;
|
|
std::getline(std::cin, input);
|
|
|
|
if (input == "sms" || input == "SMS") {
|
|
char *country_code = nullptr;
|
|
char *phone_number = nullptr;
|
|
int result = psync_tfa_send_sms(&country_code, &phone_number);
|
|
|
|
if (result == 0) {
|
|
if (country_code && phone_number) {
|
|
std::cout << "SMS sent to +" << country_code << " " << phone_number << std::endl;
|
|
pmem_free(PMEM_SUBSYS_OTHER, country_code);
|
|
pmem_free(PMEM_SUBSYS_OTHER, phone_number);
|
|
} else {
|
|
std::cout << "SMS sent successfully" << std::endl;
|
|
}
|
|
std::cout << "Enter code from SMS: ";
|
|
std::getline(std::cin, tfa_code_);
|
|
} else {
|
|
std::cerr << "Failed to send SMS (error " << result << "). Enter code from authenticator app: ";
|
|
std::getline(std::cin, tfa_code_);
|
|
}
|
|
} else {
|
|
tfa_code_ = input;
|
|
}
|
|
}
|
|
|
|
int clib::pclsync_lib::receive_tfa_code(const char *code) {
|
|
pthread_mutex_lock(&tfa_mtx);
|
|
get_lib().tfa_code_ = std::string(code);
|
|
pthread_cond_signal(&tfa_cond);
|
|
pthread_mutex_unlock(&tfa_mtx);
|
|
std::cout << "2FA code received." << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
void clib::pclsync_lib::read_cryptopass() {
|
|
read_from_stdin(crypto_pass_);
|
|
}
|
|
|
|
void clib::pclsync_lib::read_from_stdin(std::string &s) {
|
|
if (daemon_) {
|
|
std::cout << "Not able to read password when started as daemon." << std::endl;
|
|
exit(1);
|
|
}
|
|
termios oldt;
|
|
tcgetattr(STDIN_FILENO, &oldt);
|
|
termios newt = oldt;
|
|
newt.c_lflag &= ~ECHO;
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
|
std::cout << "Please, enter password" << std::endl;
|
|
getline(std::cin, s);
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
|
}
|
|
|
|
void event_handler(psync_eventtype_t event, psync_eventdata_t eventdata) {
|
|
if (event < PEVENT_FIRST_USER_EVENT) {
|
|
if (event & PEVENT_TYPE_FOLDER) {
|
|
if (eventdata.folder) {
|
|
std::cout << "folder event=" << event
|
|
<< ", syncid=" << eventdata.folder->syncid
|
|
<< ", folderid=" << eventdata.folder->folderid << ", name="
|
|
<< (eventdata.folder->name ? eventdata.folder->name : "")
|
|
<< ", local="
|
|
<< (eventdata.folder->localpath ? eventdata.folder->localpath
|
|
: "")
|
|
<< ", remote="
|
|
<< (eventdata.folder->remotepath
|
|
? eventdata.folder->remotepath
|
|
: "")
|
|
<< std::endl;
|
|
} else {
|
|
std::cout << "folder event=" << event << " (no folder data)"
|
|
<< std::endl;
|
|
}
|
|
} else {
|
|
if (eventdata.file) {
|
|
std::cout
|
|
<< "file event=" << event << ", syncid=" << eventdata.file->syncid
|
|
<< ", file=" << eventdata.file->fileid
|
|
<< ", name=" << (eventdata.file->name ? eventdata.file->name : "")
|
|
<< ", local="
|
|
<< (eventdata.file->localpath ? eventdata.file->localpath : "")
|
|
<< ", remote="
|
|
<< (eventdata.file->remotepath ? eventdata.file->remotepath : "")
|
|
<< std::endl;
|
|
} else {
|
|
std::cout << "file event=" << event << " (no file data)" << std::endl;
|
|
}
|
|
}
|
|
} else if (event >= PEVENT_FIRST_SHARE_EVENT) {
|
|
if (eventdata.share) {
|
|
std::cout << "share event=" << event
|
|
<< ", folderid=" << eventdata.share->folderid << ", sharename="
|
|
<< (eventdata.share->sharename ? eventdata.share->sharename
|
|
: "")
|
|
<< ", email="
|
|
<< (eventdata.share->toemail ? eventdata.share->toemail : "")
|
|
<< ", message="
|
|
<< (eventdata.share->message ? eventdata.share->message : "")
|
|
<< ", userid=" << eventdata.share->userid
|
|
<< ", shareid=" << eventdata.share->shareid
|
|
<< ", sharerequestid=" << eventdata.share->sharerequestid
|
|
<< ", created=" << eventdata.share->created
|
|
<< ", canread=" << eventdata.share->canread
|
|
<< ", cancreate=" << eventdata.share->cancreate
|
|
<< ", canmodify=" << eventdata.share->canmodify
|
|
<< ", candelete=" << eventdata.share->candelete << std::endl;
|
|
} else {
|
|
std::cout << "share event=" << event << " (no share data)" << std::endl;
|
|
}
|
|
} else {
|
|
std::cout << "event " << event << std::endl;
|
|
}
|
|
}
|
|
|
|
static int lib_setup_cripto() {
|
|
if(pstatus_get(PSTATUS_TYPE_ONLINE) == PSTATUS_ONLINE_OFFLINE) {
|
|
std::cout << "Cannot unlock crypto folder, pcloudcc is offline" << std::endl;
|
|
return PSYNC_CRYPTO_CANT_CONNECT;
|
|
}
|
|
|
|
const char *pwd = clib::pclsync_lib::get_lib().get_crypto_pass().c_str();
|
|
if(!pcryptofolder_issetup()) {
|
|
std::cout << "crypto is not setup, setting it up now..." << std::endl;
|
|
if(int ret = pcryptofolder_setup(pwd, "no hint") != PSYNC_CRYPTO_SETUP_SUCCESS) {
|
|
std::cout << "crypto setup failed, error code was " << ret << std::endl;
|
|
clib::pclsync_lib::get_lib().wipe_crypto_pass();
|
|
return ret;
|
|
}
|
|
if(int ret = pcryptofolder_mkdir(0, "Crypto", NULL, NULL) != PSYNC_CRYPTO_SUCCESS) {
|
|
std::cout << "failed to create crypto directory, error code was" << ret << std::endl;
|
|
clib::pclsync_lib::get_lib().wipe_crypto_pass();
|
|
return ret;
|
|
}
|
|
std::cout << "crypto folder was setup using the provided password, "
|
|
<< "you may want to change your password hint on the "
|
|
<< "pcloud website." << std::endl;
|
|
}
|
|
|
|
if(int ret = pcryptofolder_unlock(pwd) != PSYNC_CRYPTO_START_SUCCESS) {
|
|
std::cout << "Failed to unlock crypto folder: error code was " << ret << std::endl;
|
|
clib::pclsync_lib::get_lib().wipe_crypto_pass();
|
|
return ret;
|
|
}
|
|
|
|
clib::pclsync_lib::get_lib().wipe_crypto_pass();
|
|
clib::pclsync_lib::get_lib().crypto_on_ = true;
|
|
return 0;
|
|
}
|
|
|
|
static const char *status2string(uint32_t status) {
|
|
switch (status) {
|
|
case PSTATUS_READY:
|
|
return "READY";
|
|
case PSTATUS_DOWNLOADING:
|
|
return "DOWNLOADING";
|
|
case PSTATUS_UPLOADING:
|
|
return "UPLOADING";
|
|
case PSTATUS_DOWNLOADINGANDUPLOADING:
|
|
return "DOWNLOADINGANDUPLOADING";
|
|
case PSTATUS_LOGIN_REQUIRED:
|
|
return "LOGIN_REQUIRED";
|
|
case PSTATUS_BAD_LOGIN_DATA:
|
|
return "BAD_LOGIN_DATA";
|
|
case PSTATUS_BAD_LOGIN_TOKEN:
|
|
return "BAD_LOGIN_TOKEN";
|
|
case PSTATUS_ACCOUNT_FULL:
|
|
return "ACCOUNT_FULL";
|
|
case PSTATUS_DISK_FULL:
|
|
return "DISK_FULL";
|
|
case PSTATUS_PAUSED:
|
|
return "PAUSED";
|
|
case PSTATUS_STOPPED:
|
|
return "STOPPED";
|
|
case PSTATUS_OFFLINE:
|
|
return "OFFLINE";
|
|
case PSTATUS_CONNECTING:
|
|
return "CONNECTING";
|
|
case PSTATUS_SCANNING:
|
|
return "SCANNING";
|
|
case PSTATUS_USER_MISMATCH:
|
|
return "USER_MISMATCH";
|
|
case PSTATUS_ACCOUT_EXPIRED:
|
|
return "ACCOUT_EXPIRED";
|
|
case PSTATUS_TFA_REQUIRED:
|
|
return "TFA_REQUIRED";
|
|
case PSTATUS_BAD_TFA_CODE:
|
|
return "BAD_TFA_CODE";
|
|
default:
|
|
return "Unrecognized status";
|
|
}
|
|
}
|
|
|
|
static void status_change(pstatus_t *status) {
|
|
static int cryptocheck = 0;
|
|
|
|
char *err;
|
|
err = (char *)pmem_malloc(PMEM_SUBSYS_OTHER, 1024);
|
|
|
|
uint32_t cur_status = __atomic_load_n(&status->status, __ATOMIC_RELAXED);
|
|
std::cout << "Down: " << status->downloadstr << "| Up: " << status->uploadstr
|
|
<< ", status is " << status2string(cur_status) << std::endl;
|
|
*clib::pclsync_lib::get_lib().status_ = *status;
|
|
clib::pclsync_lib::get_lib().status_->status = cur_status;
|
|
if (cur_status == PSTATUS_LOGIN_REQUIRED) {
|
|
if (clib::pclsync_lib::get_lib().get_password().empty()) {
|
|
clib::pclsync_lib::get_lib().read_password();
|
|
}
|
|
|
|
psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(),
|
|
clib::pclsync_lib::get_lib().get_password().c_str(),
|
|
(int)clib::pclsync_lib::get_lib().save_pass_);
|
|
clib::pclsync_lib::get_lib().wipe_password();
|
|
std::cout << "logging in" << std::endl;
|
|
} else if (cur_status == PSTATUS_TFA_REQUIRED) {
|
|
if (clib::pclsync_lib::get_lib().get_tfa_code().empty()) {
|
|
clib::pclsync_lib::get_lib().read_tfa_code();
|
|
}
|
|
psync_tfa_set_code(clib::pclsync_lib::get_lib().get_tfa_code().c_str(),
|
|
1 /* trusted */, 0);
|
|
clib::pclsync_lib::get_lib().wipe_tfa_code();
|
|
} else if (cur_status == PSTATUS_BAD_TFA_CODE) {
|
|
clib::pclsync_lib::get_lib().wipe_tfa_code();
|
|
clib::pclsync_lib::get_lib().read_tfa_code(false /* auto_sms */);
|
|
psync_tfa_set_code(clib::pclsync_lib::get_lib().get_tfa_code().c_str(),
|
|
1 /* trusted */, 0);
|
|
clib::pclsync_lib::get_lib().wipe_tfa_code();
|
|
} else if (cur_status == PSTATUS_BAD_LOGIN_DATA) {
|
|
if (!clib::pclsync_lib::get_lib().newuser_) {
|
|
clib::pclsync_lib::get_lib().read_password();
|
|
psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(),
|
|
clib::pclsync_lib::get_lib().get_password().c_str(),
|
|
(int)clib::pclsync_lib::get_lib().save_pass_);
|
|
} else {
|
|
std::cout << "registering" << std::endl;
|
|
if (psync_register(clib::pclsync_lib::get_lib().get_username().c_str(),
|
|
clib::pclsync_lib::get_lib().get_password().c_str(), 1,
|
|
"bineapi.pcloud.com", 2, &err)) {
|
|
std::cout << "both login and registration failed" << std::endl;
|
|
exit(1);
|
|
} else {
|
|
std::cout << "registered, logging in" << std::endl;
|
|
psync_set_user_pass(clib::pclsync_lib::get_lib().get_username().c_str(),
|
|
clib::pclsync_lib::get_lib().get_password().c_str(),
|
|
(int)clib::pclsync_lib::get_lib().save_pass_);
|
|
}
|
|
}
|
|
}
|
|
if (cur_status == PSTATUS_READY || cur_status == PSTATUS_UPLOADING ||
|
|
cur_status == PSTATUS_DOWNLOADING ||
|
|
cur_status == PSTATUS_DOWNLOADINGANDUPLOADING) {
|
|
if (!cryptocheck) {
|
|
cryptocheck = 1;
|
|
if (clib::pclsync_lib::get_lib().setup_crypto_) {
|
|
lib_setup_cripto();
|
|
}
|
|
}
|
|
pfs_start();
|
|
}
|
|
if (clib::pclsync_lib::get_lib().status_callback_) {
|
|
clib::pclsync_lib::get_lib().status_callback_(
|
|
(int)cur_status, status2string(cur_status));
|
|
}
|
|
|
|
if (err) {
|
|
pmem_free(PMEM_SUBSYS_OTHER, err);
|
|
}
|
|
}
|
|
|
|
int clib::pclsync_lib::start_crypto(const char *pwd) {
|
|
get_lib().crypto_pass_ = pwd;
|
|
return lib_setup_cripto();
|
|
}
|
|
|
|
int clib::pclsync_lib::stop_crypto(const char *unused) {
|
|
(void)unused;
|
|
|
|
pcryptofolder_lock();
|
|
get_lib().crypto_on_ = false;
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::check_pending(const char *unused) {
|
|
(void)unused;
|
|
|
|
pstatus_t status;
|
|
psync_get_status(&status);
|
|
|
|
uint32_t pending = status.filestoupload + status.filestodownload;
|
|
|
|
// Write result to shared memory for client
|
|
pshm_write(&pending, sizeof(uint32_t));
|
|
|
|
if (pending > 0) {
|
|
std::cout << "Warning: " << pending << " pending transfer(s) detected";
|
|
if (status.filestoupload > 0 && status.filestodownload > 0) {
|
|
std::cout << " (" << status.filestoupload << " upload(s), "
|
|
<< status.filestodownload << " download(s))";
|
|
} else if (status.filestoupload > 0) {
|
|
std::cout << " (" << status.filestoupload << " upload(s))";
|
|
} else {
|
|
std::cout << " (" << status.filestodownload << " download(s))";
|
|
}
|
|
std::cout << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
std::cout << "No pending transfers detected" << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::get_status(const char *unused) {
|
|
(void)unused;
|
|
|
|
pstatus_t st;
|
|
psync_get_status(&st);
|
|
|
|
char buf[512];
|
|
snprintf(buf, sizeof(buf),
|
|
"Status: %s\n"
|
|
"Download: %s\n"
|
|
"Upload: %s",
|
|
status2string(st.status),
|
|
st.downloadstr ? st.downloadstr : "",
|
|
st.uploadstr ? st.uploadstr : "");
|
|
|
|
pshm_write(buf, strlen(buf) + 1);
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::finalize(const char *unused) {
|
|
(void)unused;
|
|
psync_destroy();
|
|
exit(0);
|
|
}
|
|
|
|
int clib::pclsync_lib::pause_sync(const char *unused) {
|
|
(void)unused;
|
|
psync_pause();
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::resume_sync(const char *unused) {
|
|
(void)unused;
|
|
psync_resume();
|
|
return 0;
|
|
}
|
|
|
|
// path is the local and remote path delimited by '|'
|
|
int clib::pclsync_lib::add_sync_folder(const char *combined_path) {
|
|
if (combined_path == nullptr) {
|
|
std::cerr << "Error: path is nullptr" << std::endl;
|
|
return -255;
|
|
}
|
|
const char delimiter = '|';
|
|
std::string combined(combined_path);
|
|
size_t delimiter_pos = combined.find(delimiter);
|
|
if (delimiter_pos == std::string::npos) {
|
|
std::cerr << "Error: Invalid path format. Expected 'localpath|remotepath'"
|
|
<< std::endl;
|
|
return -255;
|
|
}
|
|
|
|
std::string localpath = combined.substr(0, delimiter_pos);
|
|
std::string remotepath = combined.substr(delimiter_pos + 1);
|
|
psync_syncid_t syncid = pfolder_add_sync_path(localpath.c_str(), remotepath.c_str(), PSYNC_FULL);
|
|
|
|
pthread_mutex_lock(&mtx);
|
|
if (syncid == PSYNC_INVALID_SYNCID) {
|
|
std::cerr << "psync_add_sync_by_path returned PSYNC_INVALID_SYNCID" << std::endl;
|
|
uint64_t error_value = (static_cast<uint64_t>(1) << 32) | PSYNC_INVALID_SYNCID;
|
|
pshm_write(&error_value, sizeof(uint64_t));
|
|
pthread_mutex_unlock(&mtx);
|
|
return -1;
|
|
}
|
|
pshm_write(&syncid, sizeof(psync_syncid_t));
|
|
pthread_mutex_unlock(&mtx);
|
|
return 0;
|
|
}
|
|
|
|
// path is the folderid to remove
|
|
int clib::pclsync_lib::remove_sync_folder(const char *fid) {
|
|
psync_folderid_t folderid;
|
|
try {
|
|
folderid = static_cast<psync_folderid_t>(std::stoull(fid, nullptr, 10));
|
|
} catch (const std::invalid_argument &e) {
|
|
std::cerr << "Invalid folder ID: " << fid << std::endl;
|
|
return -1;
|
|
} catch (const std::out_of_range &e) {
|
|
std::cerr << "Folder ID out of range: " << fid << std::endl;
|
|
return -1;
|
|
}
|
|
return pfolder_delete_sync_by_id(folderid);
|
|
}
|
|
|
|
// path is not used
|
|
int clib::pclsync_lib::list_sync_folders(const char *unused) {
|
|
(void)unused;
|
|
|
|
psync_folder_list_t *folders;
|
|
size_t folderssz;
|
|
|
|
folders = pfolder_sync_folders((char *)PSYNC_STR_ALLSYNCS);
|
|
if (!folders) {
|
|
return -1;
|
|
}
|
|
folderssz =
|
|
sizeof(psync_folder_list_t) + (folders->foldercnt * sizeof(psync_folder_t));
|
|
|
|
pthread_mutex_lock(&mtx);
|
|
pshm_write(folders, folderssz);
|
|
pthread_mutex_unlock(&mtx);
|
|
|
|
pmem_free(PMEM_SUBSYS_OTHER, folders);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::init() {
|
|
std::string software_string;
|
|
char *username_old;
|
|
|
|
pdevice_set_software(client_name.c_str());
|
|
|
|
if (setup_crypto_ && crypto_pass_.empty()) {
|
|
return 3;
|
|
}
|
|
|
|
if (psync_init()) {
|
|
std::cerr << "Initialization failed: " << psync_error_to_string(psync_error)
|
|
<< " (error code: " << psync_error << ")" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
was_init_ = true;
|
|
|
|
psignal_register(SIGINT);
|
|
psignal_register(SIGTERM);
|
|
psignal_register(SIGHUP);
|
|
|
|
if (!get_mount().empty()) {
|
|
psync_set_string_setting("fsroot", get_mount().c_str());
|
|
}
|
|
|
|
const char *cache_size_env = getenv("PCLOUD_CACHE_SIZE");
|
|
if (cache_size_env && cache_size_env[0] != '\0') {
|
|
try {
|
|
uint64_t cache_size = std::stoull(cache_size_env);
|
|
psync_set_uint_setting("fscachesize", cache_size);
|
|
} catch (const std::exception &e) {
|
|
pdbg_logf(D_ERROR, "Invalid PCLOUD_CACHE_SIZE: %s", cache_size_env);
|
|
}
|
|
}
|
|
|
|
psync_start_sync(status_change, event_handler);
|
|
|
|
username_old = psync_get_username();
|
|
if (username_old) {
|
|
if (username_.compare(username_old) != 0) {
|
|
std::cout << "logged in with user " << username_old << ", not "
|
|
<< username_ << ", unlinking" << std::endl;
|
|
psync_unlink();
|
|
pmem_free(PMEM_SUBSYS_OTHER, username_old);
|
|
return 2;
|
|
}
|
|
pmem_free(PMEM_SUBSYS_OTHER, username_old);
|
|
}
|
|
|
|
prpc_register(STARTCRYPTO, &start_crypto);
|
|
prpc_register(STOPCRYPTO, &stop_crypto);
|
|
prpc_register(FINALIZE, &finalize);
|
|
prpc_register(CHECKPENDING, &check_pending);
|
|
prpc_register(LISTSYNC, &list_sync_folders);
|
|
prpc_register(ADDSYNC, &add_sync_folder);
|
|
prpc_register(STOPSYNC, &remove_sync_folder);
|
|
prpc_register(SYNCPAUSE, &pause_sync);
|
|
prpc_register(SYNCRESUME, &resume_sync);
|
|
prpc_register(SENDTFA, &receive_tfa_code);
|
|
prpc_register(SENDAUTH, &receive_auth);
|
|
prpc_register(GETSTATUS, &get_status);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::login(const char *user, const char *pass, int save) {
|
|
username_ = user;
|
|
password_ = pass;
|
|
save_pass_ = save;
|
|
psync_set_user_pass(user, pass, save);
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::logout() {
|
|
wipe_password();
|
|
psync_logout(PSTATUS_AUTH_REQUIRED, 1);
|
|
return 0;
|
|
}
|
|
|
|
int clib::pclsync_lib::unlink() {
|
|
set_username("");
|
|
wipe_password();
|
|
psync_unlink();
|
|
return 0;
|
|
}
|
|
|
|
void clib::pclsync_lib::wipe(std::string& s) {
|
|
if (s.empty()) {
|
|
return;
|
|
}
|
|
|
|
void* mem = &s[0];
|
|
size_t sz = s.size();
|
|
putil_wipe(mem, sz);
|
|
s.clear();
|
|
}
|