pcloudcc-lneely/pclsync/pdiff.c

3239 lines
113 KiB
C

/*
Copyright (c) 2013-2014 Anton Titov.
Copyright (c) 2013-2014 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 MERCHANTsABILITY 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 <errno.h>
#include <ctype.h>
#include <pthread.h>
#include <stddef.h>
#include <unistd.h>
#include "paccountevents.h"
#include "papi.h"
#include "pbusinessaccount.h"
#include "pcache.h"
#include "pcryptofolder.h"
#include "pqevent.h"
#include "pcontacts.h"
#include "pdevice.h"
#include "pdiff.h"
#include "pdiff_helpers.h"
#include "pdownload.h"
#include "pfileops.h"
#include "pfoldersync.h"
#include "pfs.h"
#include "pfsxattr.h"
#include "plibs.h"
#include "pmem.h"
#include "pnetlibs.h"
#include "pnotify.h"
#include "ppathstatus.h"
#include "prun.h"
#include "psettings.h"
#include "pstatus.h"
#include "psynclib.h"
#include "pfoldersync.h"
#include "psys.h"
#include "ptask.h"
#include "ptimer.h"
#include "ptools.h"
#include "publiclinks.h"
#include "putil.h"
#include "psql.h"
int psync_recache_contacts = 1;
#define PSYNC_SQL_DOWNLOAD "synctype&" NTO_STR(PSYNC_DOWNLOAD_ONLY) "=" NTO_STR(PSYNC_DOWNLOAD_ONLY)
#define create_entry() \
binresult entry; \
hashpair pair; \
entry.type = PARAM_HASH; \
entry.length = 1; \
entry.hash = &pair; \
pair.key = "metadata"; \
pair.value = (binresult *)meta;
#define bind_num(s) psql_bind_uint(res, off++, papi_find_result2(meta, s, PARAM_NUM)->num)
#define bind_bool(s) psql_bind_uint(res, off++, papi_find_result2(meta, s, PARAM_BOOL)->num)
#define bind_str(s) \
do { \
br = papi_find_result2(meta, s, PARAM_STR); \
psql_bind_lstr(res, off++, br->str, br->length); \
} while (0)
#define bind_opt_str(s) \
do { \
br = papi_check_result2(meta, s, PARAM_STR); \
if (br) \
psql_bind_lstr(res, off++, br->str, br->length); \
else \
psql_bind_null(res, off++); \
} while (0)
#define bind_opt_num(s) \
do { \
br = papi_check_result2(meta, s, PARAM_NUM); \
if (br) \
psql_bind_uint(res, off++, br->num); \
else \
psql_bind_null(res, off++); \
} while (0)
#define bind_opt_double(s) \
do { \
br = papi_check_result2(meta, s, PARAM_STR); \
if (br) \
psql_bind_double(res, off++, atof(br->str)); \
else \
psql_bind_null(res, off++); \
} while (0)
#define fill_str(f, s, sl) \
do { \
if (s && sl) { \
memcpy(str, s, sl); \
f = str; \
str += sl; \
} else \
f = ""; \
} while (0);
#define FN(n) {process_##n, #n, sizeof(#n) - 1, 0}
#define event_list_size ARRAY_SIZE(event_list)
typedef struct {
psync_eventtype_t eventid;
psync_share_event_t *event_data;
uint64_t touserid;
uint64_t fromuserid;
uint64_t teamid;
char *str;
} notify_paramst;
typedef struct {
uint64_t diffid;
uint32_t notificationid;
uint64_t publinkid;
uint64_t uploadlinkid;
} subscribed_ids;
typedef struct {
psync_folderid_t *refresh_folders;
uint32_t refresh_last;
} refresh_folders_ptr_t;
static uint64_t used_quota = 0, current_quota = 0, free_quota = 0;
static time_t last_event = 0;
static unsigned long needdownload = 0;
static int exceptionsockwrite = INVALID_SOCKET;
static pthread_mutex_t diff_mutex = PTHREAD_MUTEX_INITIALIZER;
static int initialdownload = 0;
static paccount_cache_callback_t psync_cache_callback = NULL;
static uint32_t psync_is_business = 0;
static unsigned char adapter_hash[PSYNC_FAST_HASH256_LEN];
static psync_folderid_t *refresh_folders = NULL;
static uint32_t refresh_allocated = 0;
static uint32_t refresh_last = 0;
int unlinked = 0;
int tfa = 0;
static void psync_diff_refresh_fs_add_folder(psync_folderid_t folderid);
static void do_send_eventdata(void *param);
static void psync_notify_cache_change(psync_changetype_t event) {
paccount_cache_callback_t callback;
psync_changetype_t *chtype = pmem_malloc(PMEM_SUBSYS_SYNC, sizeof(psync_changetype_t));
*chtype = event;
callback = psync_cache_callback;
if (callback)
prun_thread1("cache start callback", callback, chtype);
else
pmem_free(PMEM_SUBSYS_SYNC, chtype);
}
static binresult *get_userinfo_user_digest(psock_t *sock, const char *username,
size_t userlen, const char *pwddig, const char *digest,
uint32_t diglen, const char *osversion,
const char *appversion, const char *deviceid,
const char *devicestring) {
binparam params[] = {
PAPI_STR("timeformat", "timestamp"),
PAPI_LSTR("username", username, userlen),
PAPI_LSTR("digest", digest, diglen),
PAPI_LSTR("passworddigest", pwddig, PSYNC_SHA1_DIGEST_HEXLEN),
PAPI_STR("osversion", osversion),
PAPI_STR("appversion", appversion),
PAPI_STR("deviceid", deviceid),
PAPI_STR("device", devicestring),
PAPI_BOOL("getauth", 1),
PAPI_BOOL("getapiserver", 1),
PAPI_BOOL("cryptokeyssign", 1),
PAPI_BOOL("getlastsubscription", 1),
PAPI_NUM("os", P_OS_ID)};
return papi_send2(sock, "login", params);
}
static binresult *get_userinfo_user_pass(psock_t *sock, const char *username,
const char *password, const char *osversion,
const char *appversion, const char *deviceid,
const char *devicestring) {
binparam empty_params[] = {PAPI_STR("MS", "sucks")};
psync_sha1_ctx ctx;
binresult *res, *ret;
const binresult *dig;
unsigned char *uc;
size_t ul, i;
unsigned char sha1bin[PSYNC_SHA1_DIGEST_LEN];
char sha1hex[PSYNC_SHA1_DIGEST_HEXLEN];
res = papi_send2(sock, "getdigest", empty_params);
if (!res)
return res;
if (papi_find_result2(res, "result", PARAM_NUM)->num != 0) {
pmem_free(PMEM_SUBSYS_SYNC, res);
return NULL;
}
dig = papi_find_result2(res, "digest", PARAM_STR);
pdbg_logf(D_NOTICE, "got digest %s", dig->str);
ul = strlen(username);
uc = pmem_malloc_array(PMEM_SUBSYS_SYNC, ul, sizeof(unsigned char));
for (i = 0; i < ul; i++)
uc[i] = tolower(username[i]);
psync_sha1(uc, ul, sha1bin);
pmem_free(PMEM_SUBSYS_SYNC, uc);
psync_binhex(sha1hex, sha1bin, PSYNC_SHA1_DIGEST_LEN);
psync_sha1_init(&ctx);
psync_sha1_update(&ctx, password, strlen(password));
psync_sha1_update(&ctx, sha1hex, PSYNC_SHA1_DIGEST_HEXLEN);
psync_sha1_update(&ctx, dig->str, dig->length);
psync_sha1_final(sha1bin, &ctx);
psync_binhex(sha1hex, sha1bin, PSYNC_SHA1_DIGEST_LEN);
ret = get_userinfo_user_digest(sock, username, ul, sha1hex, dig->str,
dig->length, osversion, appversion, deviceid,
devicestring);
pmem_free(PMEM_SUBSYS_SYNC, res);
return ret;
}
static int check_active_subscribtion(const binresult *res) {
return pdiff_check_active_subscribtion(res);
}
static int check_user_relocated(uint64_t luserid, psock_t *sock) {
binresult *res;
const binresult *userids;
uint64_t result, userid;
int cnt, i, lid, clid;
binresult *id;
binparam params[] = {PAPI_STR("timeformat", "timestamp"),
PAPI_STR("auth", psync_my_auth)};
res = papi_send2(sock, "getolduserids", params);
if (pdbg_unlikely(!res))
return 0;
result = papi_find_result2(res, "result", PARAM_NUM)->num;
if (result) {
pdbg_logf(D_NOTICE, "getolduserids returned error %lu %s",
(unsigned long)result,
papi_find_result2(res, "error", PARAM_STR)->str);
pmem_free(PMEM_SUBSYS_SYNC, res);
return 0;
}
userids = papi_find_result2(res, "userids", PARAM_ARRAY);
cnt = userids->length;
if (!cnt) {
pmem_free(PMEM_SUBSYS_SYNC, res);
return 0;
}
clid = psql_cellint(
"SELECT value FROM setting WHERE id='last_logged_location_id'", 1);
for (i = 0; i < cnt; ++i) {
id = userids->array[i];
userid = papi_find_result2(id, "userid", PARAM_NUM)->num;
lid = papi_find_result2(id, "locationid", PARAM_NUM)->num;
if (luserid == userid && lid == clid) {
return 1;
}
}
return 0;
}
static psock_t *get_connected_socket() {
char *auth, *user, *pass, *deviceid, *osversion, *devicestring, *binapi,
*chrUserid;
const char *appversion;
psock_t *sock;
binresult *res;
const binresult *cres;
psync_sql_res *q;
uint64_t result, userid, luserid, locationid;
int saveauth, isbusiness, cryptosetup, digest, lid, isFirstLogin;
digest = 1;
pmem_free(PMEM_SUBSYS_SYNC, psync_my_2fa_token);
auth = user = pass = psync_my_2fa_token = NULL;
psync_is_business = 0;
deviceid = psql_cellstr("SELECT value FROM setting WHERE id='deviceid'");
// generate deviceid if needed
if (!deviceid) {
psync_sql_res *q;
unsigned char deviceidbin[16];
char deviceidhex[32 + 2];
pssl_rand_strong(deviceidbin, sizeof(deviceidbin));
psync_binhex(deviceidhex, deviceidbin, sizeof(deviceidbin));
deviceidhex[sizeof(deviceidbin) * 2] = 0;
q = psql_prepare(
"REPLACE INTO setting (id, value) VALUES ('deviceid', ?)");
psql_bind_str(q, 1, deviceidhex);
psql_run_free(q);
deviceid = putil_strdup(deviceidhex);
}
pdbg_logf(D_NOTICE, "using deviceid %s", deviceid);
appversion = pdevice_get_software();
devicestring = pdevice_name();
while (1) {
pmem_free(PMEM_SUBSYS_SYNC, auth);
pmem_free(PMEM_SUBSYS_SYNC, user);
pmem_free(PMEM_SUBSYS_SYNC, pass);
pstatus_wait(PSTATUS_TYPE_RUN, PSTATUS_RUN_RUN | PSTATUS_RUN_PAUSE);
auth = psql_cellstr("SELECT value FROM setting WHERE id='auth'");
user = psql_cellstr("SELECT value FROM setting WHERE id='user'");
pass = psql_cellstr("SELECT value FROM setting WHERE id='pass'");
if (user && !user[0])
user = NULL;
if (pass && !pass[0])
pass = NULL;
if (auth && !auth[0])
auth = NULL;
chrUserid =
psql_cellstr("SELECT value FROM setting WHERE id='userid'");
// If there is no userid row, we assume it's first login, after instalation.
// Rise a flag so we can send a first login event later.
if (chrUserid == NULL) {
isFirstLogin = 1;
} else {
isFirstLogin = 0;
}
if (!auth && psync_my_auth[0])
auth = putil_strdup(psync_my_auth);
if (!user && psync_my_user)
user = putil_strdup(psync_my_user);
if (!pass && psync_my_pass)
pass = putil_strdup(psync_my_pass);
if (!auth && (!pass || !user)) {
if (tfa) {
tfa = 0;
psys_sleep_milliseconds(1000);
pdbg_logf(D_WARNING, "tfa sleep");
continue;
}
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_REQUIRED);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
continue;
}
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
saveauth = psync_setting_get_bool(_PS(saveauth));
sock = papi_connect(apiserver, psync_setting_get_bool(_PS(usessl)));
if (pdbg_unlikely(!sock)) {
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_OFFLINE);
psys_sleep_milliseconds(PSYNC_SLEEP_BEFORE_RECONNECT);
continue;
}
osversion = pdevice_get_os();
if (psync_my_2fa_token && psync_my_2fa_code_type && psync_my_2fa_code[0]) {
const char *method = psync_my_2fa_code_type == 1
? "tfa_login"
: "tfa_loginwithrecoverycode";
binparam params[] = {PAPI_STR("timeformat", "timestamp"),
PAPI_STR("token", psync_my_2fa_token),
PAPI_STR("code", psync_my_2fa_code),
PAPI_BOOL("trustdevice", psync_my_2fa_trust),
PAPI_STR("osversion", osversion),
PAPI_STR("appversion", appversion),
PAPI_STR("deviceid", deviceid),
PAPI_STR("device", devicestring),
PAPI_BOOL("getauth", 1),
PAPI_BOOL("cryptokeyssign", 1),
PAPI_BOOL("getapiserver", 1),
PAPI_BOOL("getlastsubscription", 1),
PAPI_NUM("os", P_OS_ID)};
res = papi_send2(sock, method, params);
} else if (user && pass && pass[0]) {
if (digest) {
res = get_userinfo_user_pass(sock, user, pass, osversion, appversion,
deviceid, devicestring);
} else {
binparam params[] = {
PAPI_STR("timeformat", "timestamp"), PAPI_STR("username", user),
PAPI_STR("password", pass), PAPI_STR("osversion", osversion),
PAPI_STR("appversion", appversion), PAPI_STR("deviceid", deviceid),
PAPI_STR("device", devicestring), PAPI_BOOL("getauth", 1),
PAPI_BOOL("cryptokeyssign", 1), PAPI_BOOL("getapiserver", 1),
PAPI_BOOL("getlastsubscription", 1), PAPI_NUM("os", P_OS_ID)};
res = papi_send2(sock, "login", params);
}
} else {
binparam params[] = {PAPI_STR("timeformat", "timestamp"),
PAPI_STR("auth", auth),
PAPI_STR("osversion", osversion),
PAPI_STR("appversion", appversion),
PAPI_STR("deviceid", deviceid),
PAPI_STR("device", devicestring),
PAPI_BOOL("getauth", 1),
PAPI_BOOL("cryptokeyssign", 1),
PAPI_BOOL("getapiserver", 1),
PAPI_BOOL("getlastsubscription", 1),
PAPI_NUM("os", P_OS_ID)};
res = papi_send2(sock, "userinfo", params);
}
pmem_free(PMEM_SUBSYS_SYNC, osversion);
if (pdbg_unlikely(!res)) {
psock_close(sock);
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_OFFLINE);
psys_sleep_milliseconds(PSYNC_SLEEP_BEFORE_RECONNECT);
papi_conn_fail_inc();
continue;
}
papi_conn_fail_reset();
result = papi_find_result2(res, "result", PARAM_NUM)->num;
if (unlikely(result)) {
pdbg_logf(D_NOTICE, "userinfo returned error %lu %s", (unsigned long)result,
papi_find_result2(res, "error", PARAM_STR)->str);
// here we only handle statuses that need to access the result
if (result == 2297) {
pmem_free(PMEM_SUBSYS_SYNC, psync_my_2fa_token);
psync_my_2fa_token =
putil_strdup(papi_find_result2(res, "token", PARAM_STR)->str);
psync_my_2fa_has_devices =
papi_find_result2(res, "hasdevices", PARAM_BOOL)->num;
psync_my_2fa_type = papi_find_result2(res, "tfatype", PARAM_NUM)->num;
psync_my_2fa_code_type = 0;
psync_my_2fa_code[0] = 0;
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_TFAREQ);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
continue;
}
if (result == 2306) {
pmem_free(PMEM_SUBSYS_SYNC, psync_my_verify_token);
psync_my_verify_token =
putil_strdup(papi_find_result2(res, "verifytoken", PARAM_STR)->str);
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_VERIFYREQ);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
continue;
}
if (result == 2321) {
cres = papi_check_result2(res, "location", PARAM_HASH);
if (cres) {
binapi =
putil_strdup(papi_find_result2(cres, "binapi", PARAM_STR)->str);
locationid = papi_find_result2(cres, "id", PARAM_NUM)->num;
psync_set_apiserver(binapi, locationid);
}
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
continue;
}
if (result == 2330) {
psync_set_apiserver(PSYNC_API_HOST, PSYNC_LOCATIONID_DEFAULT);
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_RELOCATING);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
continue;
}
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
if (result == 2000 || result == 2012 || result == 2064 ||
result == 2074 || result == 2092) {
psync_my_2fa_code_type = 0;
psync_my_2fa_code[0] = 0;
if (result == 2012 || result == 2064 || result == 2074 ||
result == 2092)
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADCODE);
else if (user && pass) {
// Ugly fix, sorry :(
if (!strcmp(user, "pass") && !strcmp(pass, "dummy")) {
pdbg_logf(D_NOTICE,
"got %lu, for user=%s, not rising PSTATUS_AUTH_BADLOGIN",
(unsigned long)result, user);
psys_sleep_milliseconds(1000);
continue;
} else {
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADLOGIN);
pmem_free(PMEM_SUBSYS_SYNC, psync_my_pass);
psync_my_pass = NULL;
}
} else {
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_BADTOKEN);
psync_set_apiserver(PSYNC_API_HOST, PSYNC_LOCATIONID_DEFAULT);
}
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
} else if (result == 4000)
psys_sleep_milliseconds(5 * 60 * 1000);
else if (result == 2205 || result == 2229) {
psync_set_apiserver(PSYNC_API_HOST, PSYNC_LOCATIONID_DEFAULT);
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_EXPIRED);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
} else if (result == 2237) {
digest = 0;
continue;
} else
psys_sleep_milliseconds(PSYNC_SLEEP_BEFORE_RECONNECT);
continue;
}
psync_my_userid = userid = papi_find_result2(res, "userid", PARAM_NUM)->num;
current_quota = papi_find_result2(res, "quota", PARAM_NUM)->num;
cres = papi_check_result2(res, "freequota", PARAM_NUM);
if (cres) {
free_quota = cres->num;
}
luserid =
psql_cellint("SELECT value FROM setting WHERE id='userid'", 0);
psync_is_business = papi_find_result2(res, "business", PARAM_BOOL)->num;
lid = psync_setting_get_uint(_PS(location_id));
psql_start();
putil_strlcpy(psync_my_auth, papi_find_result2(res, "auth", PARAM_STR)->str,
sizeof(psync_my_auth));
if (luserid) {
if (pdbg_unlikely(luserid != userid)) {
if (check_user_relocated(luserid, sock)) {
pdbg_logf(D_NOTICE, "setting PSTATUS_AUTH_RELOCATED");
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_RELOCATED);
} else {
pdbg_logf(D_NOTICE, "user mistmatch, db userid=%lu, connected userid=%lu",
(unsigned long)luserid, (unsigned long)userid);
pstatus_set(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_MISMATCH);
}
psql_rollback();
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
continue;
}
if (saveauth) {
q = psql_prepare(
"REPLACE INTO setting (id, value) VALUES ('auth', ?)");
psql_bind_str(q, 1, psync_my_auth);
psql_run_free(q);
}
} else {
used_quota = 0;
q = psql_prepare(
"REPLACE INTO setting (id, value) VALUES (?, ?)");
psql_bind_str(q, 1, "userid");
psql_bind_uint(q, 2, userid);
psql_run(q);
psql_bind_str(q, 1, "last_logged_location_id");
psql_bind_uint(q, 2, lid);
psql_run(q);
psql_bind_str(q, 1, "quota");
psql_bind_uint(q, 2, current_quota);
psql_run(q);
psql_bind_str(q, 1, "freequota");
psql_bind_uint(q, 2, free_quota);
psql_run(q);
psql_bind_str(q, 1, "usedquota");
psql_bind_uint(q, 2, 0);
psql_run(q);
result = papi_find_result2(res, "premium", PARAM_BOOL)->num;
psql_bind_str(q, 1, "premium");
psql_bind_uint(q, 2, result);
psql_run(q);
if (result)
result = papi_find_result2(res, "premiumexpires", PARAM_NUM)->num;
else
result = 0;
psql_bind_str(q, 1, "premiumexpires");
psql_bind_uint(q, 2, result);
psql_run(q);
psql_bind_str(q, 1, "emailverified");
psql_bind_uint(
q, 2, papi_find_result2(res, "emailverified", PARAM_BOOL)->num);
psql_run(q);
psql_bind_str(q, 1, "registered");
psql_bind_uint(q, 2,
papi_find_result2(res, "registered", PARAM_NUM)->num);
psql_run(q);
psql_bind_str(q, 1, "username");
psql_bind_str(q, 2,
papi_find_result2(res, "email", PARAM_STR)->str);
psql_run(q);
psql_bind_str(q, 1, "language");
psql_bind_str(q, 2,
papi_find_result2(res, "language", PARAM_STR)->str);
psql_run(q);
psql_bind_str(q, 1, "plan");
psql_bind_uint(q, 2, papi_find_result2(res, "plan", PARAM_NUM)->num);
psql_run(q);
psql_bind_str(q, 1, "business");
psql_bind_uint(q, 2,
papi_find_result2(res, "business", PARAM_BOOL)->num);
psql_run(q);
psql_bind_str(q, 1, "premiumlifetime");
psql_bind_uint(
q, 2, papi_find_result2(res, "premiumlifetime", PARAM_BOOL)->num);
psql_run(q);
cres = papi_check_result2(res, "vivapcloud", PARAM_BOOL);
if (cres) {
psql_bind_str(q, 1, "vivapcloud");
psql_bind_uint(q, 2, cres->num);
psql_run(q);
}
cres = papi_check_result2(res, "family", PARAM_HASH);
if (cres) {
psql_bind_str(q, 1, "owner");
psql_bind_uint(q, 2,
papi_find_result2(cres, "owner", PARAM_BOOL)->num);
psql_run(q);
}
if (saveauth) {
psql_bind_str(q, 1, "auth");
psql_bind_str(q, 2, psync_my_auth);
psql_run(q);
}
psql_free(q);
}
if (pstatus_get(PSTATUS_TYPE_AUTH) != PSTATUS_AUTH_PROVIDED) {
psql_rollback();
psock_close(sock);
pmem_free(PMEM_SUBSYS_SYNC, res);
pstatus_wait(PSTATUS_TYPE_AUTH, PSTATUS_AUTH_PROVIDED);
continue;
}
pdbg_logf(D_NOTICE, "userid %lu", (unsigned long)userid);
cres = papi_check_result2(res, "account", PARAM_HASH);
q = psql_prepare(
"REPLACE INTO setting (id, value) VALUES (?, ?)");
if (cres) {
psql_bind_str(q, 1, "business");
psql_bind_uint(q, 2, 1);
psql_run(q);
psql_bind_str(q, 1, "firstname");
psql_bind_str(
q, 2, papi_find_result2(cres, "firstname", PARAM_STR)->str);
psql_run(q);
psql_bind_str(q, 1, "lastname");
psql_bind_str(
q, 2, papi_find_result2(cres, "lastname", PARAM_STR)->str);
psql_run(q);
isbusiness = 1;
} else {
psql_bind_str(q, 1, "business");
psql_bind_uint(q, 2, 0);
psql_run(q);
isbusiness = 0;
}
cres = papi_check_result2(res, "cryptov2isactive", PARAM_BOOL);
if (cres)
psync_set_bool_setting("cryptov2isactive", cres->num);
else
psync_set_bool_setting("cryptov2isactive", 0);
cryptosetup = papi_find_result2(res, "cryptosetup", PARAM_BOOL)->num;
psql_bind_str(q, 1, "cryptosetup");
psql_bind_uint(q, 2, cryptosetup);
psql_run(q);
if (cryptosetup) {
char *publicsha1 = psql_cellstr(
"SELECT value FROM setting WHERE id='crypto_public_sha1'");
char *privatesha1 = psql_cellstr(
"SELECT value FROM setting WHERE id='crypto_private_sha1'");
if (!publicsha1 || !privatesha1 ||
strcmp(publicsha1,
papi_find_result2(res, "publicsha1", PARAM_STR)->str) ||
strcmp(privatesha1,
papi_find_result2(res, "privatesha1", PARAM_STR)->str))
psync_delete_cached_crypto_keys();
pmem_free(PMEM_SUBSYS_SYNC, privatesha1);
pmem_free(PMEM_SUBSYS_SYNC, publicsha1);
} else
psync_delete_cached_crypto_keys();
psql_bind_str(q, 1, "cryptosubscription");
psql_bind_uint(
q, 2, papi_find_result2(res, "cryptosubscription", PARAM_BOOL)->num);
psql_run(q);
cres = papi_check_result2(res, "cryptoexpires", PARAM_NUM);
psql_bind_str(q, 1, "cryptoexpires");
psql_bind_uint(q, 2, cres ? cres->num : 0);
psql_run(q);
int sub = check_active_subscribtion(res);
psql_bind_str(q, 1, "hasactivesubscription");
psql_bind_uint(q, 2, sub);
psql_run(q);
psql_free(q);
psql_commit();
pthread_mutex_lock(&psync_my_auth_mutex);
if (psync_my_pass) {
memset(psync_my_pass, 'X', strlen(psync_my_pass));
q = psql_prepare(
"UPDATE setting SET value=? WHERE id='pass'");
psql_bind_str(q, 1, psync_my_pass);
psql_run_free(q);
pmem_free(PMEM_SUBSYS_SYNC, psync_my_pass);
psync_my_pass = NULL;
}
pthread_mutex_unlock(&psync_my_auth_mutex);
if (saveauth)
psql_statement("DELETE FROM setting WHERE id='pass'");
else
psql_statement("DELETE FROM setting WHERE id IN ('pass', 'auth')");
cres = papi_find_result2(papi_find_result2(res, "apiserver", PARAM_HASH),
"binapi", PARAM_ARRAY);
if (cres->length)
psync_apipool_set_server(cres->array[0]->str);
pmem_free(PMEM_SUBSYS_SYNC, res);
// If the flag is up, send a first login event to track the number of
// sucessful installs.
if (isFirstLogin) {
pdbg_logf(D_NOTICE,
"This is a first login. Send the FIRST_LOGIN event. Token:[%s], "
"User id: [%lu]",
psync_my_auth, (unsigned long)userid);
time_t rawtime;
time(&rawtime);
char *macAddr;
macAddr = ptools_get_mac_addr();
eventParams params = {1, // Number of parameters we are passing below.
{PAPI_STR(EPARAM_MAC, macAddr)}};
ptools_create_backend_event(apiserver, INST_EVENT_CATEG, INST_EVENT_FLOGIN,
INST_EVENT_CATEG, psync_my_auth, P_OS_ID, rawtime,
&params, (char **)res);
} else {
pdbg_logf(D_NOTICE, "Not a first login. Run sync event.");
ptools_send_psyncs_event(apiserver, psync_my_auth);
}
if (isbusiness) {
binparam params[] = {PAPI_STR("timeformat", "timestamp"),
PAPI_STR("auth", psync_my_auth)};
res = papi_send2(sock, "account_info", params);
if (pdbg_unlikely(!res)) {
psock_close(sock);
continue;
}
result = papi_find_result2(res, "result", PARAM_NUM)->num;
if (likely(result == 0)) {
cres = papi_check_result2(res, "account", PARAM_HASH);
q = psql_prepare(
"REPLACE INTO setting (id, value) VALUES (?, ?)");
psql_bind_str(q, 1, "company");
psql_bind_str(
q, 2, papi_find_result2(cres, "company", PARAM_STR)->str);
psql_run_free(q);
cres = papi_check_result2(cres, "owner", PARAM_HASH);
psync_set_bool_setting(
"owner_cryptosetup",
papi_find_result2(cres, "cryptosetup", PARAM_BOOL)->num);
} else
pdbg_logf(D_WARNING,
"account_info returned %lu, continuing without business info",
(unsigned long)result);
pmem_free(PMEM_SUBSYS_SYNC, res);
psql_sync();
}
pmem_free(PMEM_SUBSYS_SYNC, chrUserid);
pmem_free(PMEM_SUBSYS_SYNC, auth);
pmem_free(PMEM_SUBSYS_SYNC, user);
pmem_free(PMEM_SUBSYS_SYNC, pass);
pmem_free(PMEM_SUBSYS_SYNC, psync_my_2fa_token);
psync_my_2fa_token = NULL;
psync_my_2fa_code_type = 0;
psync_my_2fa_code[0] = 0;
pmem_free(PMEM_SUBSYS_SYNC, deviceid);
pmem_free(PMEM_SUBSYS_SYNC, devicestring);
psql_sync();
return sock;
}
}
static uint64_t extract_meta_folder_flags(const binresult *meta) {
return pdiff_extract_meta_folder_flags(meta);
}
static void process_createfolder(const binresult *entry) {
static psync_sql_res *st = NULL, *st2 = NULL;
psync_sql_res *res, *stmt, *stmt2;
const binresult *meta, *name;
uint64_t userid, perms, mtime, flags;
psync_uint_row row;
psync_folderid_t parentfolderid, folderid, localfolderid;
// char *localname;
psync_syncid_t syncid;
if (!entry) {
if (st) {
psql_free(st);
st = NULL;
}
if (st2) {
psql_free(st2);
st2 = NULL;
}
return;
}
if (!st) {
st = psql_prepare(
"INSERT OR IGNORE INTO folder (id, parentfolderid, userid, "
"permissions, name, ctime, mtime, flags, subdircnt) VALUES (?, ?, ?, "
"?, ?, ?, ?, ?, 0)");
if (!st)
return;
st2 = psql_prepare(
"UPDATE folder SET subdircnt=subdircnt+1, mtime=? WHERE id=?");
if (!st2)
return;
}
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
flags = extract_meta_folder_flags(meta);
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num) {
userid = psync_my_userid;
perms = PSYNC_PERM_ALL;
} else {
userid = papi_find_result2(meta, "userid", PARAM_NUM)->num;
perms = pfileops_get_perms(meta);
}
name = papi_find_result2(meta, "name", PARAM_STR);
folderid = papi_find_result2(meta, "folderid", PARAM_NUM)->num;
parentfolderid = papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num;
mtime = papi_find_result2(meta, "modified", PARAM_NUM)->num;
psql_bind_uint(st, 1, folderid);
psql_bind_uint(st, 2, parentfolderid);
psql_bind_uint(st, 3, userid);
psql_bind_uint(st, 4, perms);
psql_bind_lstr(st, 5, name->str, name->length);
psql_bind_uint(st, 6,
papi_find_result2(meta, "created", PARAM_NUM)->num);
psql_bind_uint(st, 7, mtime);
psql_bind_uint(st, 8, flags);
psql_run(st);
if (!psql_affected()) {
res = psql_prepare(
"UPDATE folder SET parentfolderid=?, userid=?, permissions=?, name=?, "
"ctime=?, mtime=?, flags=? WHERE id=?");
psql_bind_uint(res, 1, parentfolderid);
psql_bind_uint(res, 2, userid);
psql_bind_uint(res, 3, perms);
psql_bind_lstr(res, 4, name->str, name->length);
psql_bind_uint(res, 5,
papi_find_result2(meta, "created", PARAM_NUM)->num);
psql_bind_uint(res, 6, mtime);
psql_bind_uint(res, 7, flags);
psql_bind_uint(res, 8, folderid);
psql_run_free(res);
}
psql_bind_uint(st2, 1, mtime);
psql_bind_uint(st2, 2, parentfolderid);
psql_run(st2);
// Log remote folder creation (both synced and FUSE-only)
{
char *folderpath = pfs_get_path_by_folderid(folderid);
if (likely(folderpath)) {
pdbg_write_fs_event("folder created %s", folderpath);
pmem_free(PMEM_SUBSYS_SYNC, folderpath);
}
folderpath = pfolder_path(folderid, NULL);
if (likely(folderpath)) {
pdbg_logf(D_NOTICE, "remote folder created %s", folderpath);
pmem_free(PMEM_SUBSYS_SYNC, folderpath);
}
}
if (psyncer_dl_has_folder(parentfolderid) &&
!psync_is_name_to_ignore(name->str)) {
psyncer_dl_queue_add(folderid);
res = psql_query(
"SELECT syncid, localfolderid, synctype FROM syncedfolder WHERE "
"folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, parentfolderid);
stmt = psql_prepare(
"INSERT OR IGNORE INTO syncedfolder (syncid, folderid, localfolderid, "
"synctype) VALUES (?, ?, ?, ?)");
while ((row = psql_fetch_int(res))) {
syncid = row[0];
pdbg_logf(D_NOTICE,
"creating local folder %lu/%s for folderid %lu, parentfolderid %lu",
(unsigned long)row[1], name->str, (unsigned long)folderid,
(unsigned long)parentfolderid);
localfolderid =
psyncer_db_folder_create(syncid, folderid, row[1], name->str);
psql_bind_uint(stmt, 1, syncid);
psql_bind_uint(stmt, 2, folderid);
psql_bind_uint(stmt, 3, localfolderid);
psql_bind_uint(stmt, 4, row[2]);
psql_run(stmt);
if (psql_affected() == 1) {
ptask_ldir_mk(syncid, folderid, localfolderid);
needdownload = 1;
} else {
stmt2 = psql_prepare("UPDATE syncedfolder SET folderid=? "
"WHERE syncid=? AND localfolderid=?");
psql_bind_uint(stmt2, 1, folderid);
psql_bind_uint(stmt2, 2, syncid);
psql_bind_uint(stmt2, 3, localfolderid);
psql_run_free(stmt2);
}
}
psql_free(stmt);
psql_free(res);
}
}
static void group_results_by_col(psync_full_result_int *restrict r1,
psync_full_result_int *restrict r2,
uint32_t col) {
pdiff_group_results_by_col(r1, r2, col);
}
static void del_synced_folder_rec(psync_folderid_t folderid,
psync_syncid_t syncid) {
psync_sql_res *res;
psync_uint_row row;
res = psql_prepare(
"DELETE FROM syncedfolder WHERE folderid=? AND syncid=?");
psql_bind_uint(res, 1, folderid);
psql_bind_uint(res, 2, syncid);
psql_run_free(res);
res = psql_query("SELECT id FROM folder WHERE parentfolderid=?");
psql_bind_uint(res, 1, folderid);
while ((row = psql_fetch_int(res)))
del_synced_folder_rec(row[0], syncid);
psql_free(res);
}
static void process_modifyfolder(const binresult *entry) {
static psync_sql_res *st = NULL;
psync_sql_res *res;
psync_full_result_int *fres1, *fres2;
const binresult *meta, *name;
uint64_t userid, perms, mtime, flags, oldflags;
psync_variant_row vrow;
psync_uint_row row;
psync_folderid_t parentfolderid, folderid, oldparentfolderid, localfolderid;
char *oldname;
psync_syncid_t syncid;
uint32_t i, cnt;
int oldsync, newsync;
if (!entry) {
process_createfolder(NULL);
if (st) {
psql_free(st);
st = NULL;
}
return;
}
if (!st) {
st = psql_prepare(
"UPDATE folder SET parentfolderid=?, userid=?, permissions=?, name=?, "
"ctime=?, mtime=?, flags=? WHERE id=?");
if (!st)
return;
}
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
flags = extract_meta_folder_flags(meta);
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num) {
userid = psync_my_userid;
perms = PSYNC_PERM_ALL;
} else {
userid = papi_find_result2(meta, "userid", PARAM_NUM)->num;
perms = pfileops_get_perms(meta);
}
name = papi_find_result2(meta, "name", PARAM_STR);
folderid = papi_find_result2(meta, "folderid", PARAM_NUM)->num;
parentfolderid = papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num;
res = psql_query(
"SELECT parentfolderid, name, flags FROM folder WHERE id=?");
psql_bind_uint(res, 1, folderid);
vrow = psql_fetch(res);
if (likely(vrow)) {
oldparentfolderid = psync_get_number(vrow[0]);
oldname = psync_dup_string(vrow[1]);
oldflags = psync_get_number(vrow[2]);
} else {
pdbg_logf(D_ERROR,
"got modify for non-existing folder %lu (%s), processing as create",
(unsigned long)folderid, name->str);
psql_free(res);
process_createfolder(entry);
return;
}
psql_free(res);
if ((oldflags & PSYNC_FOLDER_FLAG_BACKUP_ROOT) != 0 &&
(flags & PSYNC_FOLDER_FLAG_BACKUP_ROOT) == 0) {
pdbg_logf(D_NOTICE, "Stop backup root");
pfolder_delete_sync_by_id(folderid);
// prun_thread1("psync_async_backup_delete",
// pfolder_delete_sync_by_id, folderid);
}
if ((oldflags & PSYNC_FOLDER_FLAG_BACKUP_DEVICE) != 0 &&
(flags & PSYNC_FOLDER_FLAG_BACKUP_DEVICE) == 0) {
pdbg_logf(D_NOTICE, "Stop backup device");
psync_delete_backup_device(folderid);
}
// Get old folder path before database update (for move detection)
char *oldfolderpath = pfs_get_path_by_folderid(folderid);
char *oldfolderpath_rel = pfolder_path(folderid, NULL);
mtime = papi_find_result2(meta, "modified", PARAM_NUM)->num;
psql_bind_uint(st, 1, parentfolderid);
psql_bind_uint(st, 2, userid);
psql_bind_uint(st, 3, perms);
psql_bind_lstr(st, 4, name->str, name->length);
psql_bind_uint(st, 5,
papi_find_result2(meta, "created", PARAM_NUM)->num);
psql_bind_uint(st, 6, mtime);
psql_bind_uint(st, 7, flags);
psql_bind_uint(st, 8, folderid);
psql_run(st);
// Log folder move/rename if location or name changed
{
int is_move = (oldparentfolderid != parentfolderid ||
strcmp(name->str, oldname) != 0);
if (is_move) {
char *newfolderpath = pfs_get_path_by_folderid(folderid);
if (likely(oldfolderpath && newfolderpath)) {
pdbg_write_fs_event("folder moved %s -> %s", oldfolderpath, newfolderpath);
}
pmem_free(PMEM_SUBSYS_SYNC, newfolderpath);
char *newfolderpath_rel = pfolder_path(folderid, NULL);
if (likely(oldfolderpath_rel && newfolderpath_rel)) {
pdbg_logf(D_NOTICE, "remote folder moved %s -> %s", oldfolderpath_rel, newfolderpath_rel);
}
pmem_free(PMEM_SUBSYS_SYNC, newfolderpath_rel);
}
pmem_free(PMEM_SUBSYS_SYNC, oldfolderpath);
pmem_free(PMEM_SUBSYS_SYNC, oldfolderpath_rel);
}
if (oldparentfolderid != parentfolderid) {
res = psql_prepare(
"UPDATE folder SET subdircnt=subdircnt-1, mtime=? WHERE id=?");
psql_bind_uint(res, 1, mtime);
psql_bind_uint(res, 2, oldparentfolderid);
psql_run_free(res);
res = psql_prepare(
"UPDATE folder SET subdircnt=subdircnt+1, mtime=? WHERE id=?");
psql_bind_uint(res, 1, mtime);
psql_bind_uint(res, 2, parentfolderid);
psql_run_free(res);
ppathstatus_fldr_moved(folderid, oldparentfolderid, parentfolderid);
}
/* We should check if oldparentfolderid is in downloadlist, not folderid. If
* parentfolderid is not in and folderid is in, it means that folder that is a
* "root" of a syncid is modified, we do not care about that.
*/
oldsync = psyncer_dl_has_folder(oldparentfolderid);
if (oldparentfolderid == parentfolderid)
newsync = oldsync;
else {
newsync = psyncer_dl_has_folder(parentfolderid);
psync_diff_refresh_fs_add_folder(oldparentfolderid);
}
if ((oldsync || newsync) &&
(oldparentfolderid != parentfolderid || strcmp(name->str, oldname))) {
if (!oldsync)
psyncer_dl_queue_add(folderid);
else if (!newsync) {
res = psql_query(
"SELECT id FROM syncfolder WHERE folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, folderid);
if (!psql_fetch_int(res))
psyncer_dl_queue_del(folderid);
psql_free(res);
}
res = psql_query(
"SELECT syncid, localfolderid, synctype FROM syncedfolder WHERE "
"folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, oldparentfolderid);
fres1 = psql_fetchall_int(res);
res = psql_query(
"SELECT syncid, localfolderid, synctype FROM syncedfolder WHERE "
"folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, parentfolderid);
fres2 = psql_fetchall_int(res);
if (psync_is_name_to_ignore(name->str))
fres2->rows = 0;
group_results_by_col(fres1, fres2, 0);
cnt = fres2->rows > fres1->rows ? fres1->rows : fres2->rows;
for (i = 0; i < cnt; i++) {
res = psql_query("SELECT localfolderid FROM syncedfolder WHERE "
"folderid=? AND syncid=?");
psql_bind_uint(res, 1, folderid);
psql_bind_uint(res, 2, psync_get_result_cell(fres1, i, 0));
row = psql_fetch_int(res);
if (unlikely(!row)) {
pdbg_logf(D_ERROR, "could not find local folder of folderid %lu",
(unsigned long)folderid);
psql_free(res);
continue;
}
localfolderid = row[0];
psql_free(res);
ptask_ldir_rename(
psync_get_result_cell(fres2, i, 0), folderid, localfolderid,
psync_get_result_cell(fres2, i, 1), name->str);
needdownload = 1;
if (psync_get_result_cell(fres2, i, 0) !=
psync_get_result_cell(fres1, i, 0)) {
res = psql_prepare(
"UPDATE syncedfolder SET syncid=?, synctype=? WHERE syncid=? AND "
"folderid=?");
psql_bind_uint(res, 1, psync_get_result_cell(fres2, i, 0));
psql_bind_uint(res, 2, psync_get_result_cell(fres2, i, 2));
psql_bind_uint(res, 3, psync_get_result_cell(fres1, i, 0));
psql_bind_uint(res, 4, folderid);
psql_run_free(res);
}
}
for (/*i is already=cnt*/; i < fres1->rows; i++) {
syncid = psync_get_result_cell(fres1, i, 0);
res = psql_query("SELECT localfolderid FROM syncedfolder WHERE "
"folderid=? AND syncid=?");
psql_bind_uint(res, 1, folderid);
psql_bind_uint(res, 2, syncid);
row = psql_fetch_int(res);
if (unlikely(!row)) {
pdbg_logf(D_ERROR, "could not find local folder of folderid %lu",
(unsigned long)folderid);
psql_free(res);
continue;
}
localfolderid = row[0];
psql_free(res);
del_synced_folder_rec(folderid, syncid);
ptask_ldir_rm_r(syncid, folderid, localfolderid);
needdownload = 1;
}
for (/*i is already=cnt*/; i < fres2->rows; i++) {
syncid = psync_get_result_cell(fres2, i, 0);
pdbg_logf(D_NOTICE,
"creating local folder %lu/%s for folderid %lu, parentfolderid %lu",
(unsigned long)psync_get_result_cell(fres2, i, 1), name->str,
(unsigned long)folderid, (unsigned long)parentfolderid);
localfolderid = psyncer_db_folder_create(
syncid, folderid, psync_get_result_cell(fres2, i, 1), name->str);
ptask_ldir_mk(syncid, folderid, localfolderid);
psyncer_dl_folder_add(
syncid, psync_get_result_cell(fres2, i, 2), folderid, localfolderid);
needdownload = 1;
}
pmem_free(PMEM_SUBSYS_SYNC, fres1);
pmem_free(PMEM_SUBSYS_SYNC, fres2);
}
pmem_free(PMEM_SUBSYS_SYNC, oldname);
}
static void process_deletefolder(const binresult *entry) {
static psync_sql_res *st = NULL, *st2 = NULL;
const binresult *meta;
psync_sql_res *res, *stmt;
char *path;
psync_folderid_t folderid;
psync_uint_row row;
if (!entry) {
if (st) {
psql_free(st);
st = NULL;
}
if (st2) {
psql_free(st2);
st2 = NULL;
}
return;
}
if (!st) {
st = psql_prepare("DELETE FROM folder WHERE id=?");
if (!st)
return;
st2 = psql_prepare(
"UPDATE folder SET subdircnt=subdircnt-1, mtime=? WHERE id=?");
if (!st2)
return;
}
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
folderid = papi_find_result2(meta, "folderid", PARAM_NUM)->num;
ppathstatus_fldr_deleted(folderid);
// Get folder path BEFORE deletion from database
path = pfolder_path(folderid, NULL);
char *fullpath = pfs_get_path_by_folderid(folderid);
if (psyncer_dl_has_folder(folderid)) {
psyncer_dl_queue_del(folderid);
res = psql_query(
"SELECT syncid, localfolderid FROM syncedfolder WHERE folderid=?");
psql_bind_uint(res, 1, folderid);
while ((row = psql_fetch_int(res))) {
stmt = psql_prepare(
"DELETE FROM syncedfolder WHERE syncid=? AND folderid=?");
psql_bind_uint(stmt, 1, row[0]);
psql_bind_uint(stmt, 2, folderid);
psql_run_free(stmt);
if (psql_affected() == 1) {
char *syncpath = pfolder_path(folderid, NULL);
ptask_ldir_rm(row[0], folderid, row[1], syncpath);
pmem_free(PMEM_SUBSYS_SYNC, syncpath);
needdownload = 1;
}
}
psql_free(res);
}
psql_bind_uint(st, 1, folderid);
psql_run(st);
if (psql_affected()) {
// Log remote folder deletion (both synced and FUSE-only)
if (likely(fullpath)) {
pdbg_write_fs_event("folder deleted %s", fullpath);
}
if (likely(path)) {
pdbg_logf(D_NOTICE, "remote folder deleted %s", path);
}
psql_bind_uint(st2, 1,
papi_find_result2(meta, "modified", PARAM_NUM)->num);
psql_bind_uint(
st2, 2, papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num);
psql_run(st2);
pfs_xatr_folder_deleted(folderid);
}
if (path)
pmem_free(PMEM_SUBSYS_SYNC, path);
if (fullpath)
pmem_free(PMEM_SUBSYS_SYNC, fullpath);
}
static void check_for_deletedfileid(const binresult *meta) {
const binresult *delfileid;
delfileid = papi_check_result2(meta, "deletedfileid", PARAM_NUM);
if (likely(!delfileid))
return;
else {
psync_sql_res *res;
res = psql_prepare("DELETE FROM file WHERE id=?");
psql_bind_uint(res, 1, delfileid->num);
psql_run_free(res);
pfs_xatr_file_deleted(delfileid->num);
}
}
static int bind_meta(psync_sql_res *res, const binresult *meta, int off) {
return pdiff_bind_meta(res, meta, off);
}
static void insert_revision(psync_fileid_t fileid, uint64_t hash,
uint64_t ctime, uint64_t size) {
static psync_sql_res *st = NULL;
if (!fileid) {
if (st) {
psql_free(st);
st = NULL;
}
return;
}
if (!st)
st = psql_prepare("REPLACE INTO filerevision (fileid, hash, "
"ctime, size) VALUES (?, ?, ?, ?)");
psql_bind_uint(st, 1, fileid);
psql_bind_uint(st, 2, hash);
psql_bind_uint(st, 3, ctime);
psql_bind_uint(st, 4, size);
psql_run(st);
}
static void process_createfile(const binresult *entry) {
static psync_sql_res *st = NULL;
const binresult *meta, *name;
psync_sql_res *res, *res2;
psync_folderid_t parentfolderid;
psync_fileid_t fileid;
uint64_t size, userid, hash;
psync_uint_row row;
psync_str_row row2;
int hasit;
if (!entry) {
if (st) {
psql_free(st);
st = NULL;
}
insert_revision(0, 0, 0, 0);
return;
}
if (!st)
st = psql_prepare(
"INSERT OR IGNORE INTO file (id, parentfolderid, userid, size, hash, "
"name, ctime, mtime, category, thumb, icon, "
"artist, album, title, genre, trackno, width, height, duration, fps, "
"videocodec, audiocodec, videobitrate, "
"audiobitrate, audiosamplerate, rotate) VALUES (?, ?, ?, ?, ?, ?, ?, "
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
size = papi_find_result2(meta, "size", PARAM_NUM)->num;
fileid = papi_find_result2(meta, "fileid", PARAM_NUM)->num;
parentfolderid = papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num;
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num) {
userid = psync_my_userid;
used_quota += size;
} else
userid = papi_find_result2(meta, "userid", PARAM_NUM)->num;
hash = papi_find_result2(meta, "hash", PARAM_NUM)->num;
name = papi_find_result2(meta, "name", PARAM_STR);
check_for_deletedfileid(meta);
psql_bind_uint(st, 1, fileid);
psql_bind_uint(st, 2, parentfolderid);
psql_bind_uint(st, 3, userid);
psql_bind_uint(st, 4, size);
psql_bind_uint(st, 5, hash);
psql_bind_lstr(st, 6, name->str, name->length);
bind_meta(st, meta, 7);
psql_run(st);
if (!psql_affected()) {
int off;
res = psql_prepare(
"UPDATE file SET id=?, parentfolderid=?, userid=?, size=?, hash=?, "
"name=?, ctime=?, mtime=?, category=?, thumb=?, icon=?, "
"artist=?, album=?, title=?, genre=?, trackno=?, width=?, height=?, "
"duration=?, fps=?, videocodec=?, audiocodec=?, videobitrate=?, "
"audiobitrate=?, audiosamplerate=?, rotate=? WHERE id=?");
psql_bind_uint(res, 1, fileid);
psql_bind_uint(res, 2, parentfolderid);
psql_bind_uint(res, 3, userid);
psql_bind_uint(res, 4, size);
psql_bind_uint(res, 5, hash);
psql_bind_lstr(res, 6, name->str, name->length);
off = bind_meta(res, meta, 7);
psql_bind_uint(res, off, fileid);
psql_run_free(res);
}
insert_revision(fileid, hash,
papi_find_result2(meta, "modified", PARAM_NUM)->num, size);
// Log all remote file creations (both synced and FUSE-only)
{
char *filepath = pfs_get_path_by_fileid(fileid);
if (likely(filepath)) {
pdbg_write_fs_event("file created %s", filepath);
pmem_free(PMEM_SUBSYS_SYNC, filepath);
}
filepath = pfolder_file_path(fileid, NULL);
if (likely(filepath)) {
pdbg_logf(D_NOTICE, "remote file created %s", filepath);
pmem_free(PMEM_SUBSYS_SYNC, filepath);
}
}
if (psyncer_dl_has_folder(parentfolderid) &&
!psync_is_name_to_ignore(name->str)) {
res = psql_query("SELECT syncid, localfolderid FROM syncedfolder "
"WHERE folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, parentfolderid);
while ((row = psql_fetch_int(res))) {
res2 = psql_query("SELECT name FROM localfile WHERE syncid=? AND "
"localparentfolderid=? AND hash=? AND fileid=?");
psql_bind_uint(res2, 1, row[0]);
psql_bind_uint(res2, 2, row[1]);
psql_bind_uint(res2, 3, hash);
psql_bind_uint(res2, 4, fileid);
row2 = psql_fetch_str(res2);
hasit = row2 != NULL;
psql_free(res2);
if (!hasit) {
pdbg_logf(D_NOTICE, "downloading file %s with hash %ld to local folder %lu",
name->str, (long)hash, (unsigned long)row[1]);
ptask_download_q(row[0], fileid, row[1], name->str);
needdownload = 1;
} else
pdbg_logf(D_NOTICE,
"file %s with hash %ld already exists in local folder %lu",
name->str, (long)hash, (unsigned long)row[1]);
}
psql_free(res);
}
}
static void process_modifyfile(const binresult *entry) {
static psync_sql_res *sq = NULL, *st = NULL;
psync_sql_res *res;
psync_full_result_int *fres1, *fres2;
const binresult *meta, *name, *enc;
const char *oldname;
size_t oldnamelen;
psync_variant_row row;
psync_fileid_t fileid;
psync_folderid_t parentfolderid, oldparentfolderid;
uint64_t size, userid, hash, oldsize;
int oldsync, newsync, lneeddownload, needrename;
uint32_t cnt, i;
if (!entry) {
if (sq) {
psql_free(sq);
sq = NULL;
}
if (st) {
psql_free(st);
st = NULL;
}
process_createfile(NULL);
return;
}
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
fileid = papi_find_result2(meta, "fileid", PARAM_NUM)->num;
name = papi_find_result2(meta, "name", PARAM_STR);
if (sq)
psql_reset(sq);
else
sq = psql_query(
"SELECT parentfolderid, userid, size, hash, name FROM file WHERE id=?");
psql_bind_uint(sq, 1, fileid);
row = psql_fetch(sq);
if (!row) {
pdbg_logf(D_ERROR,
"got modify for non-existing file %lu (%s), processing as create",
(unsigned long)fileid, name->str);
process_createfile(entry);
return;
}
oldsize = psync_get_number(row[2]);
if (psync_get_number(row[1]) == psync_my_userid)
used_quota -= oldsize;
// Get old path before database update (for move detection)
oldparentfolderid = psync_get_number(row[0]);
oldname = psync_get_lstring(row[4], &oldnamelen);
char *oldfilepath = pfs_get_path_by_fileid(fileid);
char *oldfilepath_rel = pfolder_file_path(fileid, NULL);
if (!st)
st = psql_prepare(
"UPDATE file SET id=?, parentfolderid=?, userid=?, size=?, hash=?, "
"name=?, ctime=?, mtime=?, category=?, thumb=?, icon=?, "
"artist=?, album=?, title=?, genre=?, trackno=?, width=?, height=?, "
"duration=?, fps=?, videocodec=?, audiocodec=?, videobitrate=?, "
"audiobitrate=?, audiosamplerate=?, rotate=? WHERE id=?");
size = papi_find_result2(meta, "size", PARAM_NUM)->num;
parentfolderid = papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num;
hash = papi_find_result2(meta, "hash", PARAM_NUM)->num;
enc = papi_check_result2(meta, "encrypted", PARAM_BOOL);
if (enc && enc->num) {
res = psql_prepare(
"DELETE FROM cryptofilekey WHERE fileid=? AND hash!=?");
psql_bind_uint(res, 1, fileid);
psql_bind_uint(res, 2, hash);
psql_run_free(res);
}
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num) {
userid = psync_my_userid;
used_quota += size;
} else
userid = papi_find_result2(meta, "userid", PARAM_NUM)->num;
check_for_deletedfileid(meta);
psql_bind_uint(st, 1, fileid);
psql_bind_uint(st, 2, parentfolderid);
psql_bind_uint(st, 3, userid);
psql_bind_uint(st, 4, size);
psql_bind_uint(st, 5, hash);
psql_bind_lstr(st, 6, name->str, name->length);
i = bind_meta(st, meta, 7);
psql_bind_uint(st, i, fileid);
psql_run(st);
insert_revision(fileid, hash,
papi_find_result2(meta, "modified", PARAM_NUM)->num, size);
// Log file move/rename or modification (both synced and FUSE-only)
{
int is_move = (oldparentfolderid != parentfolderid ||
name->length != oldnamelen ||
memcmp(name->str, oldname, oldnamelen) != 0);
int is_content_change = (hash != psync_get_number(row[3]) || size != oldsize);
if (is_move) {
char *newfilepath = pfs_get_path_by_fileid(fileid);
if (likely(oldfilepath && newfilepath)) {
pdbg_write_fs_event("file moved %s -> %s", oldfilepath, newfilepath);
}
pmem_free(PMEM_SUBSYS_SYNC, newfilepath);
char *newfilepath_rel = pfolder_file_path(fileid, NULL);
if (likely(oldfilepath_rel && newfilepath_rel)) {
pdbg_logf(D_NOTICE, "remote file moved %s -> %s", oldfilepath_rel, newfilepath_rel);
}
pmem_free(PMEM_SUBSYS_SYNC, newfilepath_rel);
} else if (is_content_change) {
char *filepath = pfs_get_path_by_fileid(fileid);
if (likely(filepath)) {
pdbg_write_fs_event("file modified %s", filepath);
pmem_free(PMEM_SUBSYS_SYNC, filepath);
}
filepath = pfolder_file_path(fileid, NULL);
if (likely(filepath)) {
pdbg_logf(D_NOTICE, "remote file modified %s", filepath);
pmem_free(PMEM_SUBSYS_SYNC, filepath);
}
}
pmem_free(PMEM_SUBSYS_SYNC, oldfilepath);
pmem_free(PMEM_SUBSYS_SYNC, oldfilepath_rel);
}
oldsync = psyncer_dl_has_folder(oldparentfolderid);
if (oldparentfolderid == parentfolderid)
newsync = oldsync;
else {
newsync = psyncer_dl_has_folder(parentfolderid);
psync_diff_refresh_fs_add_folder(oldparentfolderid);
}
if (oldsync || newsync) {
if (psync_is_name_to_ignore(name->str)) {
char *path;
pdownload_tasks_delete(fileid, 0, 1);
path = pfolder_file_path(fileid, NULL);
ptask_lfile_rm(fileid, path);
pmem_free(PMEM_SUBSYS_SYNC, path);
pmem_free(PMEM_SUBSYS_SYNC, oldfilepath);
pmem_free(PMEM_SUBSYS_SYNC, oldfilepath_rel);
needdownload = 1;
return;
}
lneeddownload = hash != psync_get_number(row[3]) || size != oldsize;
if (lneeddownload)
pdownload_tasks_delete(fileid, 0, 0);
needrename = oldparentfolderid != parentfolderid ||
name->length != oldnamelen ||
memcmp(name->str, oldname, oldnamelen);
res = psql_query(
"SELECT syncid, localfolderid, synctype FROM syncedfolder WHERE "
"folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, oldparentfolderid);
fres1 = psql_fetchall_int(res);
res = psql_query(
"SELECT syncid, localfolderid, synctype FROM syncedfolder WHERE "
"folderid=? AND " PSYNC_SQL_DOWNLOAD);
psql_bind_uint(res, 1, parentfolderid);
fres2 = psql_fetchall_int(res);
group_results_by_col(fres1, fres2, 0);
cnt = fres2->rows > fres1->rows ? fres1->rows : fres2->rows;
// pdbg_logf(D_NOTICE, "cnt=%u fres1->rows=%u, fres2->rows=%u,
// oldparentfolderid=%lu, parentfolderid=%lu", cnt, fres1->rows,
// fres2->rows, oldparentfolderid, parentfolderid);
for (i = 0; i < cnt; i++) {
if (needrename) {
ptask_lfile_rename(psync_get_result_cell(fres1, i, 0),
psync_get_result_cell(fres2, i, 0), fileid,
psync_get_result_cell(fres1, i, 1),
psync_get_result_cell(fres2, i, 1),
name->str);
needdownload = 1;
}
if (lneeddownload) {
res = psql_query(
"SELECT 1 FROM localfile WHERE localparentfolderid=? AND fileid=? "
"AND hash=? AND syncid=?");
psql_bind_uint(res, 1, psync_get_result_cell(fres2, i, 1));
psql_bind_uint(res, 2, fileid);
psql_bind_uint(res, 3, hash);
psql_bind_uint(res, 4, psync_get_result_cell(fres2, i, 0));
row = psql_fetch(res);
psql_free(res);
if (row)
pdbg_logf(D_NOTICE,
"ignoring update for file %s, has correct hash in the database",
name->str);
else {
ptask_download_q(
psync_get_result_cell(fres2, i, 0), fileid,
psync_get_result_cell(fres2, i, 1), name->str);
needdownload = 1;
}
}
}
for (/*i is already=cnt*/; i < fres2->rows; i++) {
ptask_download_q(
psync_get_result_cell(fres2, i, 0), fileid,
psync_get_result_cell(fres2, i, 1), name->str);
needdownload = 1;
}
for (/*i is already=cnt*/; i < fres1->rows; i++) {
char *path = pfolder_file_path(fileid, NULL);
ptask_lfile_rm_id(psync_get_result_cell(fres1, i, 0),
fileid, path);
pdownload_tasks_delete(
fileid, psync_get_result_cell(fres1, i, 0), 1);
pmem_free(PMEM_SUBSYS_SYNC, path);
needdownload = 1;
}
pmem_free(PMEM_SUBSYS_SYNC, fres1);
pmem_free(PMEM_SUBSYS_SYNC, fres2);
}
}
static void process_deletefile(const binresult *entry) {
static psync_sql_res *st = NULL;
const binresult *meta;
char *path;
psync_fileid_t fileid;
if (!entry) {
if (st) {
psql_free(st);
st = NULL;
}
return;
}
if (!st) {
st = psql_prepare("DELETE FROM file WHERE id=?");
if (!st)
return;
}
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
fileid = papi_find_result2(meta, "fileid", PARAM_NUM)->num;
if (psyncer_dl_has_folder(
papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num)) {
pdownload_tasks_delete(fileid, 0, 1);
path = pfolder_file_path(fileid, NULL);
if (likely(path)) {
ptask_lfile_rm(fileid, path);
pmem_free(PMEM_SUBSYS_SYNC, path);
needdownload = 1;
}
}
// Get path BEFORE deleting from database
path = pfolder_file_path(fileid, NULL);
char *fullpath = pfs_get_path_by_fileid(fileid);
psql_bind_uint(st, 1, fileid);
psql_run(st);
if (psql_affected()) {
// Log all remote file deletions (both synced and FUSE-only)
if (likely(fullpath)) {
pdbg_write_fs_event("file deleted %s", fullpath);
}
if (likely(path)) {
pdbg_logf(D_NOTICE, "remote file deleted %s", path);
}
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num)
used_quota -= papi_find_result2(meta, "size", PARAM_NUM)->num;
pfs_xatr_file_deleted(fileid);
}
if (path)
pmem_free(PMEM_SUBSYS_SYNC, path);
if (fullpath)
pmem_free(PMEM_SUBSYS_SYNC, fullpath);
}
static void start_download() {
if (needdownload) {
pdownload_wake();
pstatus_download_recalc();
pstatus_send_status_update();
needdownload = 0;
}
}
static void stop_crypto_thread() {
pcryptofolder_lock();
psync_delete_cached_crypto_keys();
}
static void process_modifyuserinfo(const binresult *entry) {
const binresult *res, *cres;
psync_sql_res *q;
uint64_t u, crexp, crsub = 0;
int crst = 0, crstat;
if (!entry)
return;
res = papi_find_result2(entry, "userinfo", PARAM_HASH);
q = psql_prepare(
"REPLACE INTO setting (id, value) VALUES (?, ?)");
cres = papi_check_result2(res, "userid", PARAM_NUM);
if (cres) {
psql_bind_str(q, 1, "userid");
psql_bind_uint(q, 2, cres->num);
psql_run(q);
}
psql_bind_str(q, 1, "quota");
current_quota = papi_find_result2(res, "quota", PARAM_NUM)->num;
psql_bind_uint(q, 2, current_quota);
psql_run(q);
cres = papi_check_result2(res, "freequota", PARAM_NUM);
if (cres) {
free_quota = cres->num;
}
psql_bind_str(q, 1, "freequota");
psql_bind_uint(q, 2, free_quota);
psql_run(q);
u = papi_find_result2(res, "premium", PARAM_BOOL)->num;
psql_bind_str(q, 1, "premium");
psql_bind_uint(q, 2, u);
psql_run(q);
if (u)
u = papi_find_result2(res, "premiumexpires", PARAM_NUM)->num;
else
u = 0;
psql_bind_str(q, 1, "premiumexpires");
psql_bind_uint(q, 2, u);
psql_run(q);
psql_bind_str(q, 1, "emailverified");
psql_bind_uint(q, 2,
papi_find_result2(res, "emailverified", PARAM_BOOL)->num);
psql_run(q);
psql_bind_str(q, 1, "username");
psql_bind_str(q, 2, papi_find_result2(res, "email", PARAM_STR)->str);
psql_run(q);
psql_bind_str(q, 1, "language");
psql_bind_str(q, 2,
papi_find_result2(res, "language", PARAM_STR)->str);
psql_run(q);
psql_bind_str(q, 1, "plan");
psql_bind_uint(q, 2, papi_find_result2(res, "plan", PARAM_NUM)->num);
psql_run(q);
psql_bind_str(q, 1, "business");
psql_bind_uint(q, 2,
papi_find_result2(res, "business", PARAM_BOOL)->num);
psql_run(q);
psql_bind_str(q, 1, "premiumlifetime");
psql_bind_uint(
q, 2, papi_find_result2(res, "premiumlifetime", PARAM_BOOL)->num);
psql_run(q);
cres = papi_check_result2(res, "vivapcloud", PARAM_BOOL);
if (cres) {
psql_bind_str(q, 1, "vivapcloud");
psql_bind_uint(q, 2, cres->num);
psql_run(q);
}
cres = papi_check_result2(res, "family", PARAM_HASH);
if (cres) {
psql_bind_str(q, 1, "owner");
psql_bind_uint(q, 2,
papi_find_result2(cres, "owner", PARAM_BOOL)->num);
psql_run(q);
}
cres = papi_check_result2(res, "cryptov2isactive", PARAM_BOOL);
psync_set_bool_setting("cryptov2isactive", cres ? cres->num : 0);
u = papi_find_result2(res, "cryptosetup", PARAM_BOOL)->num;
psql_bind_str(q, 1, "cryptosetup");
psql_bind_uint(q, 2, u);
psql_run(q);
if (!u)
prun_thread("stop crypto moduserinfo", stop_crypto_thread);
else
crst = 1;
psql_bind_str(q, 1, "cryptosubscription");
crsub = papi_find_result2(res, "cryptosubscription", PARAM_BOOL)->num;
psql_bind_uint(q, 2, crsub);
psql_run(q);
cres = papi_check_result2(res, "cryptoexpires", PARAM_NUM);
crexp = cres ? cres->num : 0;
psql_bind_str(q, 1, "cryptoexpires");
psql_bind_uint(q, 2, crexp);
psql_run(q);
if (psync_is_business || crsub) {
if (crst)
crstat = 5;
else
crstat = 4;
} else {
if (!crst)
crstat = 1;
else {
if (psys_time_seconds() > crexp)
crstat = 3;
else
crstat = 2;
}
}
psql_bind_str(q, 1, "cryptostatus");
psql_bind_uint(q, 2, crstat);
psql_run(q);
psql_free(q);
pqevent_queue_eventid(PEVENT_USERINFO_CHANGED);
}
static void send_share_notify(psync_eventtype_t eventid, const binresult *share,
int isba) {
psync_share_event_t *e;
char *str, *sharename;
const char *message;
char *email = "tralalal@tralala.com";
const binresult *br;
uint64_t ctime;
size_t stringslen, sharenamelen, messagelen;
size_t emaillen = 254;
int freesharename;
const binresult *permissions;
uint64_t teamid = 0;
uint64_t touserid = 0;
uint64_t fromuserid = 0;
if (initialdownload)
return;
stringslen = 0;
ctime = 0;
if (!(br = papi_check_result2(share, "frommail", PARAM_STR)) &&
!(br = papi_check_result2(share, "tomail", PARAM_STR))) {
if (!(br = papi_check_result2(share, "touserid", PARAM_NUM)) &&
!(br = papi_check_result2(share, "fromuserid", PARAM_NUM)) &&
!(br = papi_check_result2(share, "toteamid", PARAM_NUM))) {
pdbg_logf(D_WARNING,
"Neigher frommail or tomail nor buissines share found for "
"eventtype %u",
(unsigned)eventid);
return;
}
}
if (isba) {
if ((br = papi_check_result2(share, "user", PARAM_BOOL)) && br->num)
touserid = papi_find_result2(share, "touserid", PARAM_NUM)->num;
if ((br = papi_check_result2(share, "team", PARAM_BOOL)) && br->num)
teamid = papi_find_result2(share, "toteamid", PARAM_NUM)->num;
if ((br = papi_check_result2(share, "fromuserid", PARAM_NUM)))
fromuserid = br->num;
stringslen += ++emaillen;
stringslen += ++emaillen;
} else {
email = (char *)br->str;
emaillen = br->length + 1;
stringslen += 2 * (br->length + 1);
}
if ((br = papi_check_result2(share, "message", PARAM_STR))) {
message = br->str;
messagelen = br->length + 1;
stringslen += br->length + 1;
} else {
message = NULL;
messagelen = 0;
}
if ((br = papi_check_result2(share, "foldername", PARAM_STR)) ||
(br = papi_check_result2(share, "sharename", PARAM_STR))) {
sharename = (char *)br->str;
sharenamelen = br->length + 1;
stringslen += br->length + 1;
freesharename = 0;
} else {
psync_sql_res *res;
psync_variant_row row;
const char *cstr;
if ((br = papi_check_result2(share, "shareid", PARAM_NUM)))
if (isba)
res = psql_query(
"SELECT name, ctime FROM bsharedfolder WHERE id=? ");
else
res =
psql_query("SELECT name, ctime FROM sharedfolder WHERE id=? ");
else if ((br = papi_check_result2(share, "sharerequestid", PARAM_NUM)))
res = psql_query("SELECT name, ctime FROM sharerequest WHERE id=? ");
else {
pdbg_logf(
D_WARNING,
"Neither sharename, shareid or sharerequestid found for eventtype %u",
(unsigned)eventid);
return;
}
psql_bind_uint(res, 1, br->num);
if ((row = psql_fetch(res))) {
cstr = psync_get_lstring(row[0], &sharenamelen);
stringslen += ++sharenamelen;
sharename = (char *)pmem_malloc(PMEM_SUBSYS_SYNC, sharenamelen);
memcpy(sharename, cstr, sharenamelen);
freesharename = 1;
ctime = psync_get_number(row[1]);
} else
sharename = NULL;
psql_free(res);
if (!sharename) {
pdbg_logf(D_WARNING,
"Could not find sharedfolder or sharerequest in the database.");
return;
}
}
e = (psync_share_event_t *)pmem_malloc(PMEM_SUBSYS_SYNC, sizeof(psync_share_event_t) +
stringslen);
str = (char *)(e + 1);
memset(e, 0, sizeof(psync_share_event_t));
e->folderid = papi_find_result2(share, "folderid", PARAM_NUM)->num;
fill_str(e->sharename, sharename, sharenamelen);
if (freesharename)
pmem_free(PMEM_SUBSYS_SYNC, sharename);
fill_str(e->message, message, messagelen);
if ((br = papi_check_result2(share, "userid", PARAM_NUM)))
e->userid = br->num;
if ((br = papi_check_result2(share, "shareid", PARAM_NUM)))
e->shareid = br->num;
if ((br = papi_check_result2(share, "sharerequestid", PARAM_NUM)))
e->sharerequestid = br->num;
if (isba) {
if ((br = papi_check_result2(share, "shared", PARAM_NUM)))
ctime = br->num;
} else if ((br = papi_check_result2(share, "created", PARAM_NUM)))
ctime = br->num;
e->created = ctime;
permissions = papi_check_result2(share, "permissions", PARAM_HASH);
if (isba && permissions) {
e->canread = papi_find_result2(permissions, "canread", PARAM_BOOL)->num;
e->cancreate = papi_find_result2(permissions, "cancreate", PARAM_BOOL)->num;
e->canmodify = papi_find_result2(permissions, "canmodify", PARAM_BOOL)->num;
e->candelete = papi_find_result2(permissions, "candelete", PARAM_BOOL)->num;
e->canmanage = papi_find_result2(permissions, "canmanage", PARAM_BOOL)->num;
} else {
const binresult *canread = papi_check_result2(share, "canread", PARAM_BOOL);
if (canread) {
e->canread = canread->num;
e->cancreate = papi_find_result2(share, "cancreate", PARAM_BOOL)->num;
e->canmodify = papi_find_result2(share, "canmodify", PARAM_BOOL)->num;
e->candelete = papi_find_result2(share, "candelete", PARAM_BOOL)->num;
} else {
e->canread = 0;
e->cancreate = 0;
e->canmodify = 0;
e->candelete = 0;
}
}
if (isba) {
notify_paramst *params = pmem_malloc(PMEM_SUBSYS_SYNC, sizeof(notify_paramst));
params->eventid = eventid;
params->event_data = e;
params->touserid = touserid;
params->fromuserid = fromuserid;
params->teamid = teamid;
params->str = str;
prun_thread1("Share notify", do_send_eventdata, params);
} else {
fill_str(e->toemail, email, emaillen);
fill_str(e->fromemail, email, emaillen);
pqevent_queue_event(eventid, e);
}
}
static void do_send_eventdata(void *param) {
notify_paramst *data = (notify_paramst *)param;
char *email;
size_t emaillen;
char *str = data->str;
get_ba_member_email(data->fromuserid, &email, &emaillen);
fill_str(data->event_data->fromemail, email, emaillen);
pmem_free(PMEM_SUBSYS_SYNC, email);
if (data->touserid)
get_ba_member_email(data->touserid, &email, &emaillen);
else
get_ba_team_name(data->teamid, &email, &emaillen);
fill_str(data->event_data->toemail, email, emaillen);
pmem_free(PMEM_SUBSYS_SYNC, email);
if (email) {
pdiff_lock();
pqevent_queue_event(data->eventid, data->event_data);
pdiff_unlock();
}
pmem_free(PMEM_SUBSYS_SYNC, param);
}
static void process_requestsharein(const binresult *entry) {
psync_sql_res *q;
const binresult *share, *br;
int isincomming = 1;
uint64_t folderowneruserid = 0, owneruserid, folderid;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
folderid = papi_find_result2(share, "folderid", PARAM_NUM)->num;
psync_get_folder_ownerid(folderid, &folderowneruserid);
psync_get_current_userid(&owneruserid);
isincomming = (folderowneruserid == owneruserid) ? 0 : 1;
send_share_notify(
((isincomming) ? PEVENT_SHARE_REQUESTIN : PEVENT_SHARE_REQUESTOUT), share,
0);
q = psql_prepare(
"REPLACE INTO sharerequest (id, folderid, ctime, etime, permissions, "
"userid, mail, name, message, isincoming, isba) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
psql_bind_uint(
q, 1, papi_find_result2(share, "sharerequestid", PARAM_NUM)->num);
psql_bind_uint(q, 2,
papi_find_result2(share, "folderid", PARAM_NUM)->num);
psql_bind_uint(q, 3,
papi_find_result2(share, "created", PARAM_NUM)->num);
psql_bind_uint(q, 4,
papi_find_result2(share, "expires", PARAM_NUM)->num);
psql_bind_uint(q, 5, pfileops_get_perms(share));
psql_bind_uint(q, 6,
papi_find_result2(share, "fromuserid", PARAM_NUM)->num);
br = papi_find_result2(share, "frommail", PARAM_STR);
psql_bind_lstr(q, 7, br->str, br->length);
if (!(br = papi_check_result2(share, "foldername", PARAM_STR)))
br = papi_check_result2(share, "sharename", PARAM_STR);
psql_bind_lstr(q, 8, br->str, br->length);
br = papi_check_result2(share, "message", PARAM_STR);
if (br)
psql_bind_lstr(q, 9, br->str, br->length);
else
psql_bind_null(q, 9);
psql_bind_uint(q, 10, isincomming);
psql_bind_uint(q, 11, !isincomming);
psql_run_free(q);
}
static void process_requestshareout(const binresult *entry) {
psync_sql_res *q;
const binresult *share, *br;
int isincomming = 0;
uint64_t folderowneruserid = 0, owneruserid, folderid;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
folderid = papi_find_result2(share, "folderid", PARAM_NUM)->num;
psync_get_folder_ownerid(folderid, &folderowneruserid);
psync_get_current_userid(&owneruserid);
isincomming = (folderowneruserid == owneruserid) ? 0 : 1;
send_share_notify(
((isincomming) ? PEVENT_SHARE_REQUESTIN : PEVENT_SHARE_REQUESTOUT), share,
0);
q = psql_prepare(
"REPLACE INTO sharerequest (id, folderid, ctime, etime, permissions, "
"userid, mail, name, message, isincoming, isba) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
psql_bind_uint(
q, 1, papi_find_result2(share, "sharerequestid", PARAM_NUM)->num);
psql_bind_uint(q, 2, folderid);
psql_bind_uint(q, 3,
papi_find_result2(share, "created", PARAM_NUM)->num);
psql_bind_uint(q, 4,
papi_find_result2(share, "expires", PARAM_NUM)->num);
psql_bind_uint(q, 5, pfileops_get_perms(share));
psql_bind_uint(q, 6, folderowneruserid);
br = papi_find_result2(share, "tomail", PARAM_STR);
psql_bind_lstr(q, 7, br->str, br->length);
if (!(br = papi_check_result2(share, "foldername", PARAM_STR)))
br = papi_check_result2(share, "sharename", PARAM_STR);
psql_bind_lstr(q, 8, br->str, br->length);
br = papi_check_result2(share, "message", PARAM_STR);
if (br)
psql_bind_lstr(q, 9, br->str, br->length);
else
psql_bind_null(q, 9);
psql_bind_uint(q, 10, isincomming);
psql_bind_uint(q, 11, isincomming);
psql_run_free(q);
}
static void process_acceptedsharein(const binresult *entry) {
psync_sql_res *q;
const binresult *share, *br;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_ACCEPTIN, share, 0);
q = psql_prepare("DELETE FROM sharerequest WHERE id=?");
psql_bind_uint(
q, 1, papi_find_result2(share, "sharerequestid", PARAM_NUM)->num);
psql_run_free(q);
q = psql_prepare(
"REPLACE INTO sharedfolder (id, isincoming, folderid, ctime, "
"permissions, userid, mail, name) "
"VALUES (?, 1, ?, ?, ?, ?, ?, ?)");
pdbg_logf(D_WARNING, "INSERT NORMAL SHARE IN id: %lld",
(long long)papi_find_result2(share, "shareid", PARAM_NUM)->num);
psql_bind_uint(q, 1,
papi_find_result2(share, "shareid", PARAM_NUM)->num);
psql_bind_uint(q, 2,
papi_find_result2(share, "folderid", PARAM_NUM)->num);
psql_bind_uint(q, 3,
papi_find_result2(share, "created", PARAM_NUM)->num);
psql_bind_uint(q, 4, pfileops_get_perms(share));
psql_bind_uint(q, 5,
papi_find_result2(share, "fromuserid", PARAM_NUM)->num);
br = papi_find_result2(share, "frommail", PARAM_STR);
psql_bind_lstr(q, 6, br->str, br->length);
if (!(br = papi_check_result2(share, "foldername", PARAM_STR)))
br = papi_check_result2(share, "sharename", PARAM_STR);
psql_bind_lstr(q, 7, br->str, br->length);
psql_run_free(q);
}
static void process_establishbsharein(const binresult *entry) {
psync_sql_res *q;
const binresult *share, *br;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_ACCEPTIN, share, 1);
q = psql_prepare(
"REPLACE INTO bsharedfolder (id, isincoming, folderid, ctime, "
"permissions, message, name, isuser, "
"touserid, isteam, toteamid, fromuserid, folderownerid)"
"VALUES (?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
psql_bind_int(q, 1, papi_find_result2(share, "shareid", PARAM_NUM)->num);
psql_bind_uint(q, 2,
papi_find_result2(share, "folderid", PARAM_NUM)->num);
if ((br = papi_check_result2(share, "shared", PARAM_NUM)) ||
(br = papi_check_result2(entry, "time", PARAM_NUM)))
psql_bind_uint(q, 3, br->num);
else
psql_bind_uint(q, 3, 0);
psql_bind_uint(q, 4,
pfileops_get_perms(
papi_find_result2(share, "permissions", PARAM_HASH)));
br = papi_check_result2(share, "message", PARAM_STR);
if (br)
psql_bind_lstr(q, 5, br->str, br->length);
else
psql_bind_null(q, 5);
if (!(br = papi_check_result2(share, "foldername", PARAM_STR)))
br = papi_check_result2(share, "sharename", PARAM_STR);
psql_bind_lstr(q, 6, br->str, br->length);
br = papi_check_result2(share, "user", PARAM_BOOL);
if (br)
psql_bind_int(q, 7, br->num);
else
psql_bind_int(q, 7, 0);
br = papi_check_result2(share, "touserid", PARAM_NUM);
if (br)
psql_bind_int(q, 8, br->num);
else
psql_bind_null(q, 8);
br = papi_check_result2(share, "team", PARAM_BOOL);
if (br)
psql_bind_int(q, 9, br->num);
else
psql_bind_int(q, 9, 0);
br = papi_check_result2(share, "toteamid", PARAM_NUM);
if (br)
psql_bind_int(q, 10, br->num);
else
psql_bind_null(q, 10);
psql_bind_int(q, 11,
papi_find_result2(share, "fromuserid", PARAM_NUM)->num);
psql_bind_int(q, 12,
papi_find_result2(share, "folderownerid", PARAM_NUM)->num);
psql_run_free(q);
}
static void process_acceptedshareout(const binresult *entry) {
psync_sql_res *q;
const binresult *share, *br;
uint32_t aff = 0;
int isincomming = 0;
uint64_t folderowneruserid = 0, owneruserid, folderid;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
q = psql_prepare("DELETE FROM sharerequest WHERE id=?");
psql_bind_uint(
q, 1, papi_find_result2(share, "sharerequestid", PARAM_NUM)->num);
psql_run(q);
aff = psql_affected();
psql_free(q);
if (aff) {
folderid = papi_find_result2(share, "folderid", PARAM_NUM)->num;
psync_get_folder_ownerid(folderid, &folderowneruserid);
psync_get_current_userid(&owneruserid);
isincomming = (folderowneruserid == owneruserid) ? 0 : 1;
send_share_notify(
((isincomming) ? PEVENT_SHARE_REQUESTIN : PEVENT_SHARE_REQUESTOUT),
share, 0);
q = psql_prepare(
"REPLACE INTO sharedfolder (id, folderid, ctime, permissions, userid, "
"mail, name, isincoming) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
psql_bind_uint(q, 1,
papi_find_result2(share, "shareid", PARAM_NUM)->num);
psql_bind_uint(q, 2,
papi_find_result2(share, "folderid", PARAM_NUM)->num);
psql_bind_uint(q, 3,
papi_find_result2(share, "created", PARAM_NUM)->num);
psql_bind_uint(q, 4, pfileops_get_perms(share));
psql_bind_uint(q, 5,
papi_find_result2(share, "touserid", PARAM_NUM)->num);
br = papi_find_result2(share, "tomail", PARAM_STR);
psql_bind_lstr(q, 6, br->str, br->length);
if (!(br = papi_check_result2(share, "foldername", PARAM_STR)))
br = papi_check_result2(share, "sharename", PARAM_STR);
psql_bind_lstr(q, 7, br->str, br->length);
psql_bind_uint(q, 8, isincomming);
psql_run_free(q);
}
}
static void process_establishbshareout(const binresult *entry) {
psync_sql_res *q;
const binresult *share, *br, *ownid, *fromuserid;
char *email = 0;
int isincomming = 0;
uint64_t folderowneruserid, owneruserid;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
ownid = papi_check_result2(share, "folderownerid", PARAM_NUM);
if (ownid) {
folderowneruserid = ownid->num;
psync_get_current_userid(&owneruserid);
fromuserid = papi_check_result2(share, "fromuserid", PARAM_NUM);
if (fromuserid && fromuserid->num == owneruserid) {
isincomming = 0;
} else {
isincomming = (folderowneruserid == owneruserid) ? 0 : 1;
}
}
send_share_notify(
((isincomming) ? PEVENT_SHARE_REQUESTIN : PEVENT_SHARE_REQUESTOUT), share,
1);
q = psql_prepare(
"REPLACE INTO bsharedfolder (id, folderid, ctime, permissions, message, "
"name, isuser, "
"touserid, isteam, toteamid, fromuserid, folderownerid, isincoming)"
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
psql_bind_int(q, 1, papi_find_result2(share, "shareid", PARAM_NUM)->num);
psql_bind_uint(q, 2,
papi_find_result2(share, "folderid", PARAM_NUM)->num);
if ((br = papi_check_result2(share, "shared", PARAM_NUM)) ||
(br = papi_check_result2(entry, "time", PARAM_NUM)))
psql_bind_uint(q, 3, br->num);
else
psql_bind_uint(q, 3, 0);
psql_bind_uint(q, 4,
pfileops_get_perms(
papi_find_result2(share, "permissions", PARAM_HASH)));
br = papi_find_result2(share, "message", PARAM_STR);
psql_bind_lstr(q, 5, br->str, br->length);
if (!(br = papi_check_result2(share, "foldername", PARAM_STR)))
br = papi_check_result2(share, "sharename", PARAM_STR);
psql_bind_lstr(q, 6, br->str, br->length);
br = papi_check_result2(share, "user", PARAM_BOOL);
if (br)
psql_bind_int(q, 7, br->num);
else
psql_bind_int(q, 7, 0);
br = papi_check_result2(share, "touserid", PARAM_NUM);
if (br)
psql_bind_int(q, 8, br->num);
else
psql_bind_null(q, 8);
br = papi_check_result2(share, "team", PARAM_BOOL);
if (br)
psql_bind_int(q, 9, br->num);
else
psql_bind_int(q, 9, 0);
br = papi_check_result2(share, "toteamid", PARAM_NUM);
if (br)
psql_bind_int(q, 10, br->num);
else
psql_bind_null(q, 10);
psql_bind_int(q, 11,
papi_find_result2(share, "fromuserid", PARAM_NUM)->num);
psql_bind_int(q, 12,
papi_find_result2(share, "folderownerid", PARAM_NUM)->num);
psql_bind_int(q, 13, isincomming);
psql_run_free(q);
if (email)
pmem_free(PMEM_SUBSYS_SYNC, email);
}
static void delete_share_request(const binresult *share) {
psync_sql_res *q;
q = psql_prepare("DELETE FROM sharerequest WHERE id=?");
psql_bind_uint(
q, 1, papi_find_result2(share, "sharerequestid", PARAM_NUM)->num);
psql_run_free(q);
}
static void process_declinedsharein(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_DECLINEIN, share, 0);
delete_share_request(share);
}
static void process_declinedshareout(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_DECLINEOUT, share, 0);
delete_share_request(share);
}
static void process_cancelledsharein(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_CANCELIN, share, 0);
delete_share_request(share);
}
static void process_cancelledshareout(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_CANCELOUT, share, 0);
delete_share_request(share);
}
static void delete_shared_folder(const binresult *share) {
psync_sql_res *q;
uint64_t shareid;
q = psql_prepare("DELETE FROM sharedfolder WHERE id=?");
shareid = papi_find_result2(share, "shareid", PARAM_NUM)->num;
psql_bind_uint(q, 1, shareid);
psql_run_free(q);
}
static void delete_bsshared_folder(const binresult *share) {
psync_sql_res *q;
uint64_t shareid;
shareid = papi_find_result2(share, "shareid", PARAM_NUM)->num;
q = psql_prepare("DELETE FROM bsharedfolder WHERE id=?");
psql_bind_uint(q, 1, shareid);
psql_run_free(q);
}
static void process_removedsharein(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_REMOVEIN, share, 0);
delete_shared_folder(share);
}
static void process_removebsharein(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_REMOVEIN, share, 1);
delete_bsshared_folder(share);
}
static void process_removedshareout(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_REMOVEOUT, share, 0);
delete_shared_folder(share);
}
static void process_removebshareout(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_REMOVEOUT, share, 1);
delete_bsshared_folder(share);
}
static void modify_shared_folder(const binresult *perms, uint64_t shareid) {
psync_sql_res *q;
q = psql_prepare(
"UPDATE sharedfolder SET permissions=? WHERE id=?");
psql_bind_uint(q, 1, pfileops_get_perms(perms));
psql_bind_uint(q, 2, shareid);
psql_run_free(q);
}
static void modify_bshared_folder(const binresult *perms, uint64_t shareid) {
psync_sql_res *q;
q = psql_prepare(
"UPDATE bsharedfolder SET permissions=? WHERE id=?");
psql_bind_uint(q, 1, pfileops_get_perms(perms));
psql_bind_uint(q, 2, shareid);
psql_run_free(q);
}
static void process_modifiedsharein(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_MODIFYIN, share, 0);
modify_shared_folder(share,
papi_find_result2(share, "shareid", PARAM_NUM)->num);
}
static void process_modifiedshareout(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_MODIFYOUT, share, 0);
modify_shared_folder(share,
papi_find_result2(share, "shareid", PARAM_NUM)->num);
}
static void process_modifybsharein(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_MODIFYIN, share, 1);
modify_bshared_folder(papi_find_result2(share, "permissions", PARAM_HASH),
papi_find_result2(share, "shareid", PARAM_NUM)->num);
}
static void process_modifybshareout(const binresult *entry) {
const binresult *share;
if (!entry)
return;
share = papi_find_result2(entry, "share", PARAM_HASH);
send_share_notify(PEVENT_SHARE_MODIFYOUT, share, 1);
modify_bshared_folder(papi_find_result2(share, "permissions", PARAM_HASH),
papi_find_result2(share, "shareid", PARAM_NUM)->num);
}
static void process_cryptopasschange(const binresult *entry) {
psync_delete_cached_crypto_keys();
}
static void process_modifyaccountinfo(const binresult *entry) {
const binresult *res;
psync_userid_t ret;
if (!entry)
return;
res = papi_find_result2(entry, "metadata", PARAM_HASH);
psync_set_string_setting(
"companyname", papi_find_result2(res, "companyname", PARAM_STR)->str);
psync_set_uint_setting("owneruserid",
papi_find_result2(res, "owneruserid", PARAM_NUM)->num);
psync_get_current_userid(&ret);
if (psync_get_uint_setting("owneruserid") == ret) {
psync_set_bool_value("owner", 1);
}
psync_set_string_setting(
"ownerfirstname",
papi_find_result2(res, "ownerfirstname", PARAM_STR)->str);
psync_set_string_setting(
"ownerlastname", papi_find_result2(res, "ownerlastname", PARAM_STR)->str);
psync_set_string_setting(
"owneremail", papi_find_result2(res, "owneremail", PARAM_STR)->str);
psync_set_bool_setting(
"owner_cryptosetup",
papi_find_result2(res, "cryptosetup", PARAM_BOOL)->num);
}
static struct {
void (*process)(const binresult *);
const char *name;
uint32_t len;
uint8_t used;
} event_list[] = {
FN(createfolder), FN(modifyfolder), FN(deletefolder),
FN(createfile), FN(modifyfile), FN(deletefile),
FN(modifyuserinfo), FN(requestsharein), FN(requestshareout),
FN(acceptedsharein), FN(acceptedshareout), FN(declinedsharein),
FN(declinedshareout), FN(cancelledsharein), FN(cancelledshareout),
FN(removedsharein), FN(removedshareout), FN(modifiedsharein),
FN(modifiedshareout), FN(establishbsharein), FN(establishbshareout),
FN(modifybsharein), FN(modifybshareout), FN(removebsharein),
FN(removebshareout), FN(cryptopasschange), FN(modifyaccountinfo)};
static uint64_t process_entries(const binresult *entries, uint64_t newdiffid) {
const binresult *entry, *etype;
uint64_t oused_quota;
uint32_t i, j;
oused_quota = used_quota;
needdownload = 0;
pdiff_lock();
if (pstatus_get(PSTATUS_TYPE_AUTH) != PSTATUS_AUTH_PROVIDED) {
pdiff_unlock();
return psql_cellint("SELECT value FROM setting WHERE id='diffid'", 0);
}
psql_start();
if (entries->length >= 10000)
psql_statement("DELETE FROM setting WHERE id='lastanalyze'");
for (i = 0; i < entries->length; i++) {
entry = entries->array[i];
etype = papi_find_result2(entry, "event", PARAM_STR);
for (j = 0; j < event_list_size; j++)
if (etype->length == event_list[j].len &&
!memcmp(etype->str, event_list[j].name, etype->length)) {
event_list[j].process(entry);
event_list[j].used = 1;
}
}
for (j = 0; j < event_list_size; j++)
if (event_list[j].used)
event_list[j].process(NULL);
psync_set_uint_value("diffid", newdiffid);
psync_set_uint_value("usedquota", used_quota);
// update_ba_emails();
// update_ba_teams();
ppathstatus_clear_cache();
psql_commit();
pdiff_unlock();
if (needdownload) {
pdownload_wake();
pstatus_download_recalc();
pstatus_send_status_update();
needdownload = 0;
}
used_quota =
psql_cellint("SELECT value FROM setting WHERE id='usedquota'", 0);
if (oused_quota != used_quota)
pqevent_queue_eventid(PEVENT_USEDQUOTA_CHANGED);
return psql_cellint("SELECT value FROM setting WHERE id='diffid'", 0);
}
static void check_overquota() {
static int lisover = 0;
int isover = (used_quota >= current_quota);
if (isover != lisover) {
lisover = isover;
if (isover) {
pstatus_set(PSTATUS_TYPE_ACCFULL, PSTATUS_ACCFULL_OVERQUOTA);
} else
pstatus_set(PSTATUS_TYPE_ACCFULL, PSTATUS_ACCFULL_QUOTAOK);
}
}
static void diff_exception_handler() {
pdbg_logf(D_NOTICE, "got exception");
if (likely(exceptionsockwrite != INVALID_SOCKET)) {
ssize_t ret = write(exceptionsockwrite, "e", 1);
if (ret == -1) {
perror("write failed");
} else if (ret != 1) {
fprintf(stderr, "Partial write occurred\n");
}
}
}
static int setup_exeptions() {
int pfds[2];
if (pipe(pfds) == SOCKET_ERROR)
return INVALID_SOCKET;
exceptionsockwrite = pfds[1];
ptimer_exception_handler(diff_exception_handler);
return pfds[0];
}
static int send_diff_command(psock_t *sock, subscribed_ids ids) {
if (pnotify_running()) {
const char *ts = pnotify_get_thumb_size();
if (ts) {
if (psync_is_business) {
binparam diffparams[] = {
PAPI_STR(
"subscribefor",
"diff,notifications,publinks,uploadlinks,teams,users,contacts"),
PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("difflimit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid),
PAPI_NUM("notificationid", ids.notificationid),
PAPI_STR("notificationthumbsize", ts),
PAPI_NUM("publinkid", ids.publinkid),
PAPI_NUM("uploadlinkid", ids.uploadlinkid)};
return papi_send_no_res(sock, "subscribe", diffparams) ? 0 : -1;
} else {
binparam diffparams[] = {
PAPI_STR("subscribefor",
"diff,notifications,publinks,uploadlinks,contacts"),
PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("difflimit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid),
PAPI_NUM("notificationid", ids.notificationid),
PAPI_STR("notificationthumbsize", ts),
PAPI_NUM("publinkid", ids.publinkid),
PAPI_NUM("uploadlinkid", ids.uploadlinkid)};
return papi_send_no_res(sock, "subscribe", diffparams) ? 0 : -1;
}
} else {
if (psync_is_business) {
binparam diffparams[] = {
PAPI_STR(
"subscribefor",
"diff,notifications,publinks,uploadlinks,teams,users,contacts"),
PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("difflimit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid),
PAPI_NUM("notificationid", ids.notificationid),
PAPI_NUM("publinkid", ids.publinkid),
PAPI_NUM("uploadlinkid", ids.uploadlinkid)};
return papi_send_no_res(sock, "subscribe", diffparams) ? 0 : -1;
} else {
binparam diffparams[] = {
PAPI_STR("subscribefor",
"diff,notifications,publinks,uploadlinks,contacts"),
PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("difflimit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid),
PAPI_NUM("notificationid", ids.notificationid),
PAPI_NUM("publinkid", ids.publinkid),
PAPI_NUM("uploadlinkid", ids.uploadlinkid)};
return papi_send_no_res(sock, "subscribe", diffparams) ? 0 : -1;
}
}
} else {
if (psync_is_business) {
binparam diffparams[] = {
PAPI_STR("subscribefor",
"diff,publinks,uploadlinks,teams,users,contacts"),
PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("difflimit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid),
PAPI_NUM("publinkid", ids.publinkid),
PAPI_NUM("uploadlinkid", ids.uploadlinkid)};
return papi_send_no_res(sock, "subscribe", diffparams) ? 0 : -1;
} else {
binparam diffparams[] = {
PAPI_STR("subscribefor", "diff,publinks,uploadlinks,contacts"),
PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("difflimit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid),
PAPI_NUM("publinkid", ids.publinkid),
PAPI_NUM("uploadlinkid", ids.uploadlinkid)};
return papi_send_no_res(sock, "subscribe", diffparams) ? 0 : -1;
}
}
}
static void handle_exception(psock_t **sock, subscribed_ids *ids,
char ex) {
if (ex == 'c') {
if (last_event >= ptimer_time() - 1)
return;
if (psock_select_in(&(*sock)->sock, 1, 1000) != 0) {
pdbg_logf(D_NOTICE, "got a pdiff_wake() but no diff events in one "
"second, closing socket");
psock_close(*sock);
if (pstatus_get(PSTATUS_TYPE_AUTH) != PSTATUS_AUTH_PROVIDED)
ids->notificationid = 0;
pdbg_logf(D_NOTICE, "waiting for new socket");
*sock = get_connected_socket();
pdbg_logf(D_NOTICE, "got new socket");
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_ONLINE);
psyncer_check_delayed();
ids->diffid =
psql_cellint("SELECT value FROM setting WHERE id='diffid'", 0);
send_diff_command(*sock, *ids);
}
return;
}
pdbg_logf(D_NOTICE, "exception handler %c", ex);
if (ex == 'r' || pstatus_get(PSTATUS_TYPE_RUN) == PSTATUS_RUN_STOP ||
pstatus_get(PSTATUS_TYPE_AUTH) != PSTATUS_AUTH_PROVIDED ||
psync_setting_get_bool(_PS(usessl)) != psock_is_ssl(*sock)) {
psock_close(*sock);
if (pstatus_get(PSTATUS_TYPE_AUTH) != PSTATUS_AUTH_PROVIDED)
ids->notificationid = 0;
pdbg_logf(D_NOTICE, "waiting for new socket");
*sock = get_connected_socket();
pdbg_logf(D_NOTICE, "got new socket");
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_ONLINE);
psyncer_check_delayed();
ids->diffid =
psql_cellint("SELECT value FROM setting WHERE id='diffid'", 0);
send_diff_command(*sock, *ids);
} else if (ex == 'e') {
binparam diffparams[] = {PAPI_STR("id", "ignore")};
if (!papi_send_no_res(*sock, "nop", diffparams) ||
psock_select_in(&(*sock)->sock, 1,
PSYNC_SOCK_TIMEOUT_ON_EXCEPTION * 1000) != 0) {
const char *prefixes[] = {"API:", "HTTP"};
pdbg_logf(D_NOTICE, "reconnecting diff");
psock_close_bad(*sock);
pcache_clean_oneof(prefixes, ARRAY_SIZE(prefixes));
*sock = get_connected_socket();
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_ONLINE);
psyncer_check_delayed();
send_diff_command(*sock, *ids);
} else {
pdbg_logf(D_NOTICE, "diff socket seems to be alive");
(*sock)->pending = 1;
}
}
}
static int cmp_folderid(const void *ptr1, const void *ptr2) {
return pdiff_cmp_folderid(ptr1, ptr2);
}
static void psync_diff_refresh_fs_add_folder(psync_folderid_t folderid) {
if (pfs_need_per_folder_refresh()) {
if (refresh_allocated == refresh_last) {
if (refresh_allocated)
refresh_allocated *= 2;
else
refresh_allocated = 8;
refresh_folders = (psync_folderid_t *)pmem_realloc(
PMEM_SUBSYS_SYNC, refresh_folders, sizeof(psync_folderid_t) * refresh_allocated);
}
refresh_folders[refresh_last++] = folderid;
}
}
static void psync_diff_refresh_thread(void *ptr) {
refresh_folders_ptr_t *fr;
psync_folderid_t lastfolderid;
uint32_t i;
psys_sleep_milliseconds(1000);
fr = (refresh_folders_ptr_t *)ptr;
qsort(fr->refresh_folders, fr->refresh_last, sizeof(psync_folderid_t),
cmp_folderid);
lastfolderid = (psync_folderid_t)-1;
for (i = 0; i < fr->refresh_last; i++)
if (fr->refresh_folders[i] != lastfolderid) {
pfs_refresh_folder(fr->refresh_folders[i]);
lastfolderid = fr->refresh_folders[i];
}
pmem_free(PMEM_SUBSYS_SYNC, fr->refresh_folders);
pmem_free(PMEM_SUBSYS_SYNC, fr);
}
static void psync_diff_refresh_fs(const binresult *entries) {
if (pfs_need_per_folder_refresh()) {
const binresult *meta;
refresh_folders_ptr_t *ptr;
psync_folderid_t folderid, lastfolderid;
uint32_t i;
lastfolderid = (psync_folderid_t)-1;
for (i = 0; i < entries->length; i++) {
meta = papi_check_result2(entries->array[i], "metadata", PARAM_HASH);
if (!meta)
continue;
meta = papi_check_result2(meta, "parentfolderid", PARAM_NUM);
if (!meta)
continue;
folderid = meta->num;
if (folderid == lastfolderid)
continue;
psync_diff_refresh_fs_add_folder(folderid);
lastfolderid = folderid;
}
if (!refresh_last)
return;
ptr = pmem_malloc(PMEM_SUBSYS_SYNC, sizeof(refresh_folders_ptr_t));
ptr->refresh_folders = refresh_folders;
ptr->refresh_last = refresh_last;
prun_thread1("fs folder refresh", psync_diff_refresh_thread, ptr);
refresh_folders = NULL;
refresh_allocated = 0;
refresh_last = 0;
}
}
static void psync_run_analyze_if_needed() {
if (ptimer_time() >
psql_cellint("SELECT value FROM setting WHERE id='lastanalyze'", 0) +
24 * 3600) {
static const char *skiptables[] = {"pagecache", "sqlite_stat1"};
psync_sql_res *res;
psync_uint_row row;
psync_str_row srow;
char **tablenames;
char *sql;
size_t tablecnt, i;
pdbg_logf(D_NOTICE, "running ANALYZE on tables");
res = psql_query_rdlock(
"SELECT COUNT(*) FROM sqlite_master WHERE type='table'");
if ((row = psql_fetch_int(res)))
tablecnt = row[0];
else
tablecnt = 0;
psql_free(res);
tablenames = pmem_malloc_array(PMEM_SUBSYS_SYNC, tablecnt, sizeof(char *));
res = psql_query_rdlock(
"SELECT name FROM sqlite_master WHERE type='table' LIMIT ?");
psql_bind_uint(res, 1, tablecnt);
tablecnt = 0;
while ((srow = psql_fetch_str(res))) {
for (i = 0; i < ARRAY_SIZE(skiptables); i++)
if (!strcmp(srow[0], skiptables[i]))
goto skip;
tablenames[tablecnt++] = putil_strdup(srow[0]);
skip:;
}
psql_free(res);
while (tablecnt) {
--tablecnt;
pdbg_logf(D_NOTICE, "running ANALYZE on %s", tablenames[tablecnt]);
sql = putil_strcat("ANALYZE ", tablenames[tablecnt], ";", NULL);
pmem_free(PMEM_SUBSYS_SYNC, tablenames[tablecnt]);
psql_statement(sql);
pmem_free(PMEM_SUBSYS_SYNC, sql);
pdbg_logf(D_NOTICE, "table done");
psys_sleep_milliseconds(5);
}
pmem_free(PMEM_SUBSYS_SYNC, tablenames);
res = psql_prepare(
"REPLACE INTO setting (id, value) VALUES (?, ?)");
psql_bind_str(res, 1, "lastanalyze");
psql_bind_uint(res, 2, ptimer_time());
psql_run_free(res);
pdbg_logf(D_NOTICE, "done running ANALYZE on tables");
}
}
static int psync_diff_check_quota(psock_t *sock) {
binparam diffparams[] = {PAPI_STR("timeformat", "timestamp"),
PAPI_BOOL("getapiserver", 1)};
binresult *res;
const binresult *uq;
uint64_t oused_quota, result;
oused_quota = used_quota;
res = papi_send2(sock, "userinfo", diffparams);
if (!res)
return -1;
result = papi_find_result2(res, "result", PARAM_NUM)->num;
if (unlikely(result))
pdbg_logf(D_WARNING, "userinfo returned error %u: %s", (unsigned)result,
papi_find_result2(res, "error", PARAM_STR)->str);
else {
uq = papi_check_result2(res, "usedquota", PARAM_NUM);
if (pdbg_likely(uq))
used_quota = uq->num;
}
if (used_quota != oused_quota) {
pdbg_logf(D_WARNING, "corrected locally calculated quota from %lu to %lu",
(unsigned long)oused_quota, (unsigned long)used_quota);
psync_set_uint_value("usedquota", used_quota);
pqevent_queue_eventid(PEVENT_USEDQUOTA_CHANGED);
}
uq = papi_find_result2(papi_find_result2(res, "apiserver", PARAM_HASH),
"binapi", PARAM_ARRAY);
if (uq->length)
psync_apipool_set_server(uq->array[0]->str);
pmem_free(PMEM_SUBSYS_SYNC, res);
return 0;
}
static void psync_diff_adapter_hash(void *out) {
psync_fast_hash256_ctx ctx;
psock_ifaces_t *list;
list = psock_list_adapters();
pcrc32c_fast_hash256_init(&ctx);
pcrc32c_fast_hash256_update(&ctx, list->interfaces,
list->interfacecnt * sizeof(psock_iface_t));
pcrc32c_fast_hash256_final(out, &ctx);
pmem_free(PMEM_SUBSYS_SYNC, list);
}
static void psync_diff_adapter_timer(psync_timer_t timer, void *ptr) {
unsigned char hash[PSYNC_FAST_HASH256_LEN];
psync_diff_adapter_hash(hash);
if (memcmp(adapter_hash, hash, PSYNC_FAST_HASH256_LEN)) {
memcpy(adapter_hash, hash, PSYNC_FAST_HASH256_LEN);
pdbg_logf(D_NOTICE, "network adapter list changed, sending exception");
ssize_t ret = write(exceptionsockwrite, "e", 1);
if (ret == -1) {
pdbg_logf(D_ERROR, "Failed to write exception: %s", strerror(errno));
} else if (ret != 1) {
pdbg_logf(D_WARNING, "Partial write occurred when sending exception");
}
}
}
static void psync_diff_thread() {
psock_t *sock;
binresult *res = NULL;
const binresult *entries;
uint64_t newdiffid, result;
int exceptionsock, socks[2];
subscribed_ids ids = {0, 0, 0, 0};
int sel, ret = 0;
char ex;
char *err = NULL;
int should_free_res = 0;
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_CONNECTING);
pstatus_send_status_update();
restart:
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_CONNECTING);
sock = get_connected_socket();
pdbg_logf(D_NOTICE, "connected");
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_SCANNING);
ids.diffid =
psql_cellint("SELECT value FROM setting WHERE id='diffid'", 0);
if (ids.diffid == 0) {
initialdownload = 1;
}
used_quota =
psql_cellint("SELECT value FROM setting WHERE id='usedquota'", 0);
do {
binparam diffparams[] = {PAPI_STR("timeformat", "timestamp"),
PAPI_NUM("limit", PSYNC_DIFF_LIMIT),
PAPI_NUM("diffid", ids.diffid)};
if (!psync_do_run)
goto cleanup;
res = papi_send2(sock, "diff", diffparams);
should_free_res = 1;
if (!res) {
psock_close(sock);
goto restart;
}
result = papi_find_result2(res, "result", PARAM_NUM)->num;
if (unlikely(result)) {
pdbg_logf(D_ERROR, "diff returned error %u: %s", (unsigned int)result,
papi_find_result2(res, "error", PARAM_STR)->str);
psock_close(sock);
psys_sleep_milliseconds(PSYNC_SLEEP_BEFORE_RECONNECT);
goto restart;
}
entries = papi_find_result2(res, "entries", PARAM_ARRAY);
if (entries->length) {
newdiffid = papi_find_result2(res, "diffid", PARAM_NUM)->num;
pdbg_logf(D_NOTICE, "processing diff with %u entries",
(unsigned)entries->length);
ids.diffid = process_entries(entries, newdiffid);
pdbg_logf(D_NOTICE, "got diff with %u entries, new diffid %lu",
(unsigned)entries->length, (unsigned long)ids.diffid);
}
result = entries->length;
if (should_free_res) {
pmem_free(PMEM_SUBSYS_SYNC, res);
should_free_res = 0;
res = NULL;
}
} while (result);
pfs_refresh_folder(0);
pdbg_logf(D_NOTICE, "initial sync finished");
if (psync_diff_check_quota(sock)) {
psock_close(sock);
psys_sleep_milliseconds(PSYNC_SLEEP_BEFORE_RECONNECT);
goto restart;
}
check_overquota();
pstatus_set(PSTATUS_TYPE_ONLINE, PSTATUS_ONLINE_ONLINE);
initialdownload = 0;
psync_run_analyze_if_needed();
psyncer_check_delayed();
exceptionsock = setup_exeptions();
if (unlikely(exceptionsock == INVALID_SOCKET)) {
pdbg_logf(D_ERROR, "could not create pipe");
psock_close(sock);
goto cleanup;
}
socks[0] = exceptionsock;
socks[1] = sock->sock;
psync_diff_adapter_hash(adapter_hash);
ptimer_register(psync_diff_adapter_timer,
PSYNC_DIFF_CHECK_ADAPTER_CHANGE_SEC, NULL);
send_diff_command(sock, ids);
psys_sleep_milliseconds(50);
last_event = 0;
while (psync_do_run) {
if (unlinked) {
unlinked = 0;
initialdownload = 1;
}
if (psync_recache_contacts) {
if (psync_is_business) {
cache_account_emails();
cache_account_teams();
cache_ba_my_teams();
}
cache_links_all();
cache_contacts();
cache_shares();
psync_notify_cache_change(PACCOUNT_CHANGE_ALL);
psync_recache_contacts = 0;
}
if (psock_pendingdata(sock))
sel = 1;
else
sel = psock_select_in(socks, 2, -1);
if (sel == 0) {
if (!psync_do_run)
break;
if (read(exceptionsock, &ex, 1) != 1)
continue;
handle_exception(&sock, &ids, ex);
while (psock_select_in(socks, 1, 0) == 0 &&
read(exceptionsock, &ex, 1) == 1)
;
socks[1] = sock->sock;
} else if (sel == 1) {
sock->pending = 1;
res = papi_result(sock);
should_free_res = 1;
if (pdbg_unlikely(!res)) {
ptimer_notify_exception();
handle_exception(&sock, &ids, 'r');
socks[1] = sock->sock;
last_event = 0;
continue;
}
last_event = ptimer_time();
result = papi_find_result2(res, "result", PARAM_NUM)->num;
if (unlikely(result)) {
if (result == 6003 || result == 6002) { // timeout or cancel
pdbg_logf(D_NOTICE, "got \"%s\" from the socket",
papi_find_result2(res, "error", PARAM_STR)->str);
send_diff_command(sock, ids);
continue;
}
pdbg_logf(D_ERROR, "diff returned error %u: %s", (unsigned int)result,
papi_find_result2(res, "error", PARAM_STR)->str);
handle_exception(&sock, &ids, 'r');
socks[1] = sock->sock;
continue;
}
entries = papi_check_result2(res, "from", PARAM_STR);
if (entries) {
if (entries->length == 4 && !strcmp(entries->str, "diff")) {
entries = papi_find_result2(res, "entries", PARAM_ARRAY);
if (entries->length) {
newdiffid = papi_find_result2(res, "diffid", PARAM_NUM)->num;
ids.diffid = process_entries(entries, newdiffid);
psync_diff_refresh_fs(entries);
psync_diff_check_quota(sock);
check_overquota();
if (initialdownload)
initialdownload = 0;
} else
pdbg_logf(D_NOTICE, "diff with 0 entries, did we send a nop recently?");
} else if (entries->length == 13 &&
!strcmp(entries->str, "notifications")) {
ids.notificationid =
papi_find_result2(res, "notificationid", PARAM_NUM)->num;
pnotify_notify(res);
should_free_res = 0; // Don't free res in this case
} else if (entries->length == 8 && !strcmp(entries->str, "publinks")) {
ids.publinkid = papi_find_result2(res, "publinkid", PARAM_NUM)->num;
ret = cache_links(err, 256);
if (ret < 0)
pdbg_logf(D_ERROR, "Cacheing links failed with err %s", err);
else
psync_notify_cache_change(PACCOUNT_CHANGE_LINKS);
} else if (entries->length == 11 &&
!strcmp(entries->str, "uploadlinks")) {
ids.uploadlinkid =
papi_find_result2(res, "uploadlinkid", PARAM_NUM)->num;
ret = cache_upload_links(&err);
if (ret < 0)
pdbg_logf(D_ERROR, "Cacheing upload links failed with err %s", err);
else
psync_notify_cache_change(PACCOUNT_CHANGE_LINKS);
} else if (entries->length == 5 && !strcmp(entries->str, "teams")) {
cache_account_teams();
cache_ba_my_teams();
psync_notify_cache_change(PACCOUNT_CHANGE_TEAMS);
} else if (entries->length == 5 && !strcmp(entries->str, "users")) {
cache_account_emails();
psync_notify_cache_change(PACCOUNT_CHANGE_EMAILS);
} else if (entries->length == 8 && !strcmp(entries->str, "contacts")) {
cache_contacts();
psync_notify_cache_change(PACCOUNT_CHANGE_CONTACTS);
} else {
pdbg_logf(D_NOTICE, "got no from, did we send a nop recently?");
}
send_diff_command(sock, ids);
} else {
pdbg_logf(D_NOTICE, "got no from, did we send a nop recently?");
}
}
if (should_free_res) {
pmem_free(PMEM_SUBSYS_SYNC, res);
should_free_res = 0;
res = NULL;
}
}
cleanup:
if (should_free_res && res) {
pmem_free(PMEM_SUBSYS_SYNC, res);
}
psock_close(sock);
close(exceptionsock);
close(exceptionsockwrite);
}
void do_register_account_events_callback(paccount_cache_callback_t callback) {
psync_cache_callback = callback;
}
void pdiff_init() {
prun_thread("diff", psync_diff_thread);
}
void pdiff_wake() {
if (last_event >= ptimer_time() - 1) {
return;
}
ssize_t ret = write(exceptionsockwrite, "c", 1);
if (ret == -1) {
pdbg_logf(D_ERROR, "Failed to write wake signal: %s", strerror(errno));
} else if (ret != 1) {
pdbg_logf(D_WARNING, "Partial write occurred when sending wake signal");
}
}
void pdiff_file_create(const binresult *meta) {
psync_sql_res *st;
const binresult *name;
uint64_t userid, fileid, hash, size;
st = psql_prepare(
"INSERT OR IGNORE INTO file (id, parentfolderid, userid, size, hash, "
"name, ctime, mtime, category, thumb, icon, "
"artist, album, title, genre, trackno, width, height, duration, fps, "
"videocodec, audiocodec, videobitrate, "
"audiobitrate, audiosamplerate, rotate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, "
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
name = papi_find_result2(meta, "name", PARAM_STR);
check_for_deletedfileid(meta);
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num)
userid = psync_my_userid;
else
userid = papi_find_result2(meta, "userid", PARAM_NUM)->num;
fileid = papi_find_result2(meta, "fileid", PARAM_NUM)->num;
size = papi_find_result2(meta, "size", PARAM_NUM)->num;
hash = papi_find_result2(meta, "hash", PARAM_NUM)->num;
psql_bind_uint(st, 1, fileid);
psql_bind_uint(
st, 2, papi_find_result2(meta, "parentfolderid", PARAM_NUM)->num);
psql_bind_uint(st, 3, userid);
psql_bind_uint(st, 4, size);
psql_bind_uint(st, 5, hash);
psql_bind_lstr(st, 6, name->str, name->length);
bind_meta(st, meta, 7);
psql_run_free(st);
insert_revision(fileid, hash,
papi_find_result2(meta, "modified", PARAM_NUM)->num, size);
insert_revision(0, 0, 0, 0);
}
void pdiff_file_update(const binresult *meta) {
create_entry();
process_modifyfile(&entry);
process_modifyfile(NULL);
start_download();
}
void pdiff_file_delete(const binresult *meta) {
create_entry();
process_deletefile(&entry);
process_deletefile(NULL);
start_download();
}
void pdiff_fldr_update(const binresult *meta) {
create_entry();
process_modifyfolder(&entry);
process_modifyfolder(NULL);
start_download();
}
void pdiff_fldr_delete(const binresult *meta) {
create_entry();
process_deletefolder(&entry);
process_deletefolder(NULL);
start_download();
}
void pdiff_lock() {
pthread_mutex_lock(&diff_mutex);
}
void pdiff_unlock() {
pthread_mutex_unlock(&diff_mutex);
}