@ -52,6 +52,8 @@ static int blevel_to_android(int blevel) {
static utun_log_fn g_on_log = NULL ;
static utun_event_fn g_on_event = NULL ;
static char g_db_path [ 512 ] ;
static void bridge_log ( int level , const char * fmt , . . . ) {
va_list ap ;
va_start ( ap , fmt ) ;
@ -356,7 +358,7 @@ char* utun_bridge_get_messages_json(const char* channel_id, int limit) {
msg_table_name ( channel_id , tbl_msg , sizeof ( tbl_msg ) ) ;
char sql [ 256 ] ;
snprintf ( sql , sizeof ( sql ) , " SELECT id, node_id, data, timestamp FROM \" %s \" ORDER BY timestamp ASC LIMIT %d " , tbl_msg , limit ) ;
snprintf ( sql , sizeof ( sql ) , " SELECT id, node_id, data, timestamp, local_attrs FROM \" %s \" ORDER BY timestamp ASC LIMIT %d " , tbl_msg , limit ) ;
sqlite3_stmt * st = NULL ;
if ( sqlite3_prepare_v2 ( db , sql , - 1 , & st , NULL ) ! = SQLITE_OK ) return strdup ( " [] " ) ;
@ -373,6 +375,7 @@ char* utun_bridge_get_messages_json(const char* channel_id, int limit) {
int64_t ts = sqlite3_column_int64 ( st , 3 ) ;
const uint8_t * dptr = sqlite3_column_blob ( st , 2 ) ;
int dlen = sqlite3_column_bytes ( st , 2 ) ;
const char * lattr = ( const char * ) sqlite3_column_text ( st , 4 ) ;
char txt [ 256 ] = " " , ct [ 64 ] = " text/plain " ;
if ( dptr & & dlen > 0 ) {
@ -392,12 +395,29 @@ char* utun_bridge_get_messages_json(const char* channel_id, int limit) {
if ( ! author_name [ 0 ] )
snprintf ( author_name , sizeof ( author_name ) , " 0x%016llx " , ( unsigned long long ) node_id ) ;
size_t needed = snprintf ( NULL , 0 , " %s{ \" id \" :%lld, \" author \" : \" %s \" , \" text \" : \" %s \" , \" ts \" :%lld, \" isOutgoing \" :%s, \" contentType \" : \" %s \" } " ,
sep , ( long long ) msg_id , author_name , esc_txt , ( long long ) ts , is_out ? " true " : " false " , esc_ct ) ;
/* build filePath for voice/attachment messages */
char file_path [ 1024 ] = " " ;
if ( lattr ) {
const char * fps = strstr ( lattr , " \" fp \" : \" " ) ;
if ( fps ) { fps + = 6 ;
char * fpe = strchr ( ( char * ) fps , ' " ' ) ;
if ( fpe ) { size_t fpl = ( size_t ) ( fpe - fps ) ;
snprintf ( file_path , sizeof ( file_path ) , " %s/media/%s/%.*s " ,
g_db_path , channel_id , ( int ) fpl , fps ) ;
}
}
}
char * esc_fp = file_path [ 0 ] ? json_escape_alloc ( file_path ) : NULL ;
size_t needed = snprintf ( NULL , 0 , " %s{ \" id \" :%lld, \" author \" : \" %s \" , \" text \" : \" %s \" , \" ts \" :%lld, \" isOutgoing \" :%s, \" contentType \" : \" %s \" %s%s%s} " ,
sep , ( long long ) msg_id , author_name , esc_txt , ( long long ) ts , is_out ? " true " : " false " , esc_ct ,
esc_fp ? " , \" filePath \" : \" " : " " , esc_fp ? esc_fp : " " , esc_fp ? " \" " : " " ) ;
while ( pos + needed + 2 > cap ) { cap * = 2 ; char * tmp = u_realloc ( json , cap ) ; if ( ! tmp ) break ; json = tmp ; }
if ( pos + needed + 2 < = cap )
pos + = ( size_t ) snprintf ( json + pos , cap - pos , " %s{ \" id \" :%lld, \" author \" : \" %s \" , \" text \" : \" %s \" , \" ts \" :%lld, \" isOutgoing \" :%s, \" contentType \" : \" %s \" } " ,
sep , ( long long ) msg_id , author_name , esc_txt , ( long long ) ts , is_out ? " true " : " false " , esc_ct ) ;
pos + = ( size_t ) snprintf ( json + pos , cap - pos , " %s{ \" id \" :%lld, \" author \" : \" %s \" , \" text \" : \" %s \" , \" ts \" :%lld, \" isOutgoing \" :%s, \" contentType \" : \" %s \" %s%s%s} " ,
sep , ( long long ) msg_id , author_name , esc_txt , ( long long ) ts , is_out ? " true " : " false " , esc_ct ,
esc_fp ? " , \" filePath \" : \" " : " " , esc_fp ? esc_fp : " " , esc_fp ? " \" " : " " ) ;
if ( esc_fp ) u_free ( esc_fp ) ;
u_free ( esc_ct ) ;
u_free ( esc_txt ) ;
}
@ -584,7 +604,6 @@ static jobject g_config_callback = NULL;
static jobject g_log_callback = NULL ;
static jobject g_event_callback = NULL ;
static jmethodID g_event_mid = NULL ;
static char g_db_path [ 512 ] ;
JNIEXPORT jint JNICALL JNI_OnLoad ( JavaVM * vm , void * reserved ) {
( void ) reserved ;