diff --git a/src/dm/dm_core.c b/src/dm/dm_core.c index 804dbc73..4762ded3 100644 --- a/src/dm/dm_core.c +++ b/src/dm/dm_core.c @@ -852,12 +852,13 @@ static void json_escape(const char* src, char* dst, size_t dst_sz) { int dm_list_conversations_json(struct UTUN_INSTANCE* inst, char* buf, size_t buf_size, size_t* out_len) { struct dm_state* dm = dm_of(inst); if (!buf || !out_len || !dm || !dm->db) return -1; - int off = 0; - off += snprintf(buf + off, buf_size - (size_t)off, "["); + *out_len = 0; + struct strbuf json = strbuf_new(); + int failed = strbuf_addf(&json, "[") < 0; sqlite3_stmt* st = NULL; if (sqlite3_prepare_v2(dm->db, "SELECT conv_id, peer_node_id, COALESCE(peer_name,''), last_ts, last_out_seq, last_in_seq" - " FROM dm_conversations ORDER BY last_ts DESC", + " FROM dm_conversations ORDER BY last_ts DESC LIMIT 200", -1, &st, NULL) == SQLITE_OK) { int first = 1; while (sqlite3_step(st) == SQLITE_ROW) { @@ -875,18 +876,26 @@ int dm_list_conversations_json(struct UTUN_INSTANCE* inst, char* buf, size_t buf } char esc_name[512]; json_escape(name ? name : "", esc_name, sizeof(esc_name)); - off += snprintf(buf + off, buf_size - (size_t)off, + if (strbuf_addf(&json, "%s{\"conv_id\":\"%s\",\"peer_node_id\":%llu,\"peer_name\":\"%s\"," "\"last_ts\":%llu,\"out_seq\":%llu,\"in_seq\":%llu}", first ? "" : ",", conv_id, (unsigned long long)peer, esc_name, (unsigned long long)last_ts, - (unsigned long long)out_seq, (unsigned long long)in_seq); + (unsigned long long)out_seq, (unsigned long long)in_seq) < 0) { failed = 1; break; } first = 0; } - } + if (sqlite3_errcode(dm->db) != SQLITE_DONE && sqlite3_errcode(dm->db) != SQLITE_OK) failed = 1; + } else failed = 1; if (st) sqlite3_finalize(st); - off += snprintf(buf + off, buf_size - (size_t)off, "]"); - *out_len = (size_t)off; + if (strbuf_addf(&json, "]") < 0) failed = 1; + if (failed || json.len >= buf_size) { + DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: conversations snapshot failed bytes=%zu capacity=%zu sql=%s", DM_ID, + json.len, buf_size, sqlite3_errmsg(dm->db)); + strbuf_free(&json); return -1; + } + memcpy(buf, strbuf_str(&json), json.len + 1); + *out_len = json.len; + strbuf_free(&json); return 0; } @@ -1017,3 +1026,17 @@ void dm_messages_trampoline(void* arg) { chat_event_post(inst, CHAT_EVT_DM_MESSAGES, evt, (int)(1 + cl + len)); u_free(evt); } + +void dm_conversations_trampoline(void* arg) { + struct dm_conversations_req* req = arg; + if (!req) return; + struct UTUN_INSTANCE* inst = req->inst; + u_free(req); + if (!dm_of(inst)) { DEBUG_WARN(DEBUG_CATEGORY_DM, "%s: conversations snapshot after stop", DM_ID); return; } + size_t cap = 256 * 1024, len = 0; + char* json = u_malloc(cap); + if (!json) { DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: conversations allocation failed", DM_ID); return; } + if (!dm_list_conversations_json(inst, json, cap, &len)) + chat_event_post(inst, CHAT_EVT_DM_CONVERSATIONS, (const uint8_t*)json, (int)len); + u_free(json); +}