@ -453,7 +453,7 @@ uint32_t chat_core_cursor_open(const char* ch_id) {
if ( g_cc . cursors [ i ] ) continue ;
char tbl [ 80 ] ; msg_table_name ( ch_id , tbl , sizeof ( tbl ) ) ;
char sql [ 256 ] ; snprintf ( sql , sizeof ( sql ) ,
" SELECT timestamp, datahash, node_id, content_type, data "
" SELECT timestamp, datahash, node_id, content_type, data, chain_hash "
" FROM \" %s \" ORDER BY timestamp, datahash ASC " , tbl ) ;
sqlite3_stmt * stmt = NULL ;
if ( sqlite3_prepare_v2 ( g_cc . db , sql , - 1 , & stmt , NULL ) ! = SQLITE_OK ) return 0 ;
@ -479,10 +479,12 @@ int chat_core_cursor_next(uint32_t cursor_id, uint8_t* buf, size_t buf_size,
uint64_t nid = ( uint64_t ) sqlite3_column_int64 ( stmt , 2 ) ;
const char * ct = ( const char * ) sqlite3_column_text ( stmt , 3 ) ;
int ct_len = sqlite3_column_bytes ( stmt , 3 ) ;
const uint8_t * data = ( const uint8_t * ) sqlite3_column_blob ( stmt , 4 ) ;
const uint8_t * dptr = ( const uint8_t * ) sqlite3_column_blob ( stmt , 4 ) ;
int dlen = sqlite3_column_bytes ( stmt , 4 ) ;
const uint8_t * ch_ptr = ( const uint8_t * ) sqlite3_column_blob ( stmt , 5 ) ;
int ch_len = sqlite3_column_bytes ( stmt , 5 ) ;
size_t need = 8 + 8 + 8 + 1 + ( size_t ) ct_len + 4 + ( size_t ) dlen ;
size_t need = 8 + 8 + 8 + 1 + ( size_t ) ct_len + 4 + ( size_t ) dlen + 32 ;
if ( need > buf_size ) return - 1 ;
uint8_t * out = buf ;
@ -493,7 +495,9 @@ int chat_core_cursor_next(uint32_t cursor_id, uint8_t* buf, size_t buf_size,
if ( ct_len ) { memcpy ( out , ct , ( size_t ) ct_len ) ; out + = ct_len ; }
uint32_t dl32 = ( uint32_t ) dlen ;
memcpy ( out , & dl32 , 4 ) ; out + = 4 ;
if ( dlen ) { memcpy ( out , data , ( size_t ) dlen ) ; out + = dlen ; }
if ( dlen ) { memcpy ( out , dptr , ( size_t ) dlen ) ; out + = dlen ; }
if ( ch_ptr & & ch_len > = 32 ) memcpy ( out , ch_ptr , 32 ) ; else memset ( out , 0 , 32 ) ;
out + = 32 ;
* out_len = ( size_t ) ( out - buf ) ;
return 0 ;
}
@ -994,22 +998,40 @@ static void si_register(struct DB_SYNC_INSTANCE* si, const char* ch_id) {
static void on_db_sync_insert ( struct DB_SYNC_INSTANCE * si , const char * data , size_t len , uint64_t author , void * arg ) {
const char * ch_id = ( const char * ) arg ;
uint64_t dh ; compute_datahash ( ( const uint8_t * ) data , len , & dh ) ;
/* parse JSON: {"n":<uint64>,"ch":"<str>","ct":"<str>","d":"<str>"} */
const char * p = data ; const char * end = data + len ; uint64_t jn = 0 ;
{ /* "n" */
const char * n = strstr ( p , " \" n \" : " ) ; if ( ! n ) return ;
n + = 4 ; jn = strtoull ( n , NULL , 0 ) ; p = n ;
}
const char * jct = " text/plain " ; size_t jct_len = 10 ;
{ /* "ct" */
const char * ct = strstr ( p , " \" ct \" : \" " ) ; if ( ct ) { ct + = 6 ; const char * ce = strchr ( ct , ' " ' ) ; if ( ce ) { jct = ct ; jct_len = ( size_t ) ( ce - ct ) ; p = ce ; } }
}
const char * jd_start = NULL ; size_t jd_len = 0 ;
{ /* "d" */
const char * d = strstr ( p , " \" d \" : \" " ) ; if ( d ) { d + = 5 ; const char * de = d ; while ( de < end ) { if ( * de = = ' " ' & & ( de = = d | | * ( de - 1 ) ! = ' \\ ' ) ) break ; de + + ; } if ( de < end ) { jd_start = d ; jd_len = ( size_t ) ( de - d ) ; } }
}
if ( ! jd_start ) return ;
uint64_t dh ; compute_datahash ( ( const uint8_t * ) jd_start , jd_len , & dh ) ;
uint64_t ts = get_time_us ( ) ;
char tbl [ 80 ] ; msg_table_name ( ch_id , tbl , sizeof ( tbl ) ) ;
uint8_t prev_ch [ 32 ] ; get_last_chain_hash ( ch_id , prev_ch ) ;
uint8_t chain_h [ 32 ] ; compute_chain_hash ( prev_ch , ( int64_t ) ts , dh , chain_h ) ;
char sql [ 512 ] ; snprintf ( sql , sizeof ( sql ) ,
" INSERT OR IGNORE INTO \" %s \" (node_id,content_type,data,timestamp,datahash,chain_hash,signature,is_outgoing,is_read,sync_flags) "
" VALUES(?,?,?,?,?,?,?,?,?,?) " , tbl ) ;
sqlite3_stmt * st = NULL ;
if ( sqlite3_prepare_v2 ( g_cc . db , sql , - 1 , & st , NULL ) ! = SQLITE_OK ) return ;
sqlite3_bind_int64 ( st , 1 , ( sqlite3_int64 ) author ) ;
sqlite3_bind_text ( st , 2 , " text/plain " , - 1 , SQLITE_STATIC ) ;
sqlite3_bind_blob ( st , 3 , data , ( int ) len , SQLITE_STATIC ) ;
sqlite3_bind_int64 ( st , 1 , ( sqlite3_int64 ) jn ) ;
sqlite3_bind_text ( st , 2 , jct , ( int ) jct_len , SQLITE_STATIC ) ;
sqlite3_bind_blob ( st , 3 , jd_start , ( int ) jd_ len, SQLITE_STATIC ) ;
sqlite3_bind_int64 ( st , 4 , ( sqlite3_int64 ) ts ) ;
sqlite3_bind_int64 ( st , 5 , ( sqlite3_int64 ) dh ) ;
{ static const uint8_t z32 [ 32 ] = { 0 } ; sqlite3_bind_blob ( st , 6 , z32 , 32 , SQLITE_STATIC ) ; }
sqlite3_bind_blob ( st , 6 , chain_h , 32 , SQLITE_STATIC ) ;
{ static const uint8_t z64 [ 64 ] = { 0 } ; sqlite3_bind_blob ( st , 7 , z64 , 64 , SQLITE_STATIC ) ; }
sqlite3_bind_int ( st , 8 , author = = g_cc . my_node_id ? 1 : 0 ) ;
sqlite3_bind_int ( st , 8 , ( uint64_t ) jn = = g_cc . my_node_id ? 1 : 0 ) ;
sqlite3_bind_int ( st , 9 , 1 ) ; sqlite3_bind_int ( st , 10 , 0 ) ;
int rc = sqlite3_step ( st ) ; sqlite3_finalize ( st ) ;
if ( rc = = SQLITE_DONE ) {