From 0af35630d1788610a7822bddbcf03c0ea17ca786 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 6 Oct 2026 21:17:24 +0200 Subject: [PATCH] Expose full message data and stable identities in listings --- src/chat/chat_core.c | 68 +++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/src/chat/chat_core.c b/src/chat/chat_core.c index ffd4a61c..d62c3783 100644 --- a/src/chat/chat_core.c +++ b/src/chat/chat_core.c @@ -378,48 +378,40 @@ int chat_core_get_channels_json(struct UTUN_INSTANCE* inst, char* buf, size_t bu int chat_core_get_messages_json(struct UTUN_INSTANCE* inst, const char* ch_id, int count, int offset, char* buf, size_t buf_size, size_t* out_len) { - struct chat_core_ctx* cc = CC(inst); - if (!cc || !cc->initialized || !ch_id || !buf || !out_len) return -1; - char tbl[80]; msg_table_name(ch_id, tbl, sizeof(tbl)); - char* w = buf; char* end = buf + buf_size; - *w++ = '['; const char* sep = ""; - char sql[256]; + struct chat_core_ctx* cc = inst ? CC(inst) : NULL; + if (out_len) *out_len = 0; + if (!cc || !cc->initialized || !ch_id || !buf || !out_len || buf_size < 3 || offset < 0) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: invalid message listing arguments", CC_ID); return -1; + } + char table[80], sql[768]; msg_table_name(ch_id, table, sizeof(table)); snprintf(sql, sizeof(sql), - "SELECT m.id, m.timestamp, m.node_id, CAST(m.data AS TEXT), n.name, m.local_attrs " - "FROM \"%s\" m LEFT JOIN nodes n ON m.node_id=n.node_id " - "ORDER BY m.timestamp DESC LIMIT ? OFFSET ?", tbl); + "SELECT json_object('id',m.id,'message_id',lower(hex(m.message_id)),'ts',m.timestamp," + "'author_id',printf('0x%%016llx',m.node_id),'author_name',coalesce(n.name,'')," + "'content_type',CASE WHEN json_valid(CAST(m.data AS TEXT)) THEN json_extract(CAST(m.data AS TEXT),'$.ct') ELSE 'text' END," + "'data',coalesce(CAST(m.data AS TEXT),''),'local_attrs',coalesce(m.local_attrs,''))" + " FROM \"%s\" m LEFT JOIN nodes n ON m.node_id=n.node_id" + " ORDER BY m.timestamp DESC,m.author_signature DESC LIMIT ? OFFSET ?", table); sqlite3_stmt* st = NULL; - if (sqlite3_prepare_v2(cc->db, sql, -1, &st, NULL) != SQLITE_OK) { *out_len = 0; return -1; } - sqlite3_bind_int(st, 1, count > 0 ? count : 100); - sqlite3_bind_int(st, 2, offset); - while (sqlite3_step(st) == SQLITE_ROW) { - int64_t id = sqlite3_column_int64(st, 0); - int64_t ts = sqlite3_column_int64(st, 1); - uint64_t author_id = (uint64_t)sqlite3_column_int64(st, 2); - const char* data = (const char*)sqlite3_column_text(st, 3); - const char* author_name = (const char*)sqlite3_column_text(st, 4); - const char* la = (const char*)sqlite3_column_text(st, 5); - if (!data) data = ""; - if (!la) la = ""; - const char* ct = "text"; - char ctbuf[32] = {0}; - const char* ctpos = strstr(data, "\"ct\":\""); - if (ctpos) { ctpos += 6; int ci = 0; while (*ctpos && *ctpos != '"' && ci < 31) ctbuf[ci++] = *ctpos++; ct = ctbuf; } - char esc_data[4096], esc_aname[256], esc_la[256]; - json_escape(data, esc_data, sizeof(esc_data)); - json_escape(author_name ? author_name : "", esc_aname, sizeof(esc_aname)); - json_escape(la, esc_la, sizeof(esc_la)); - w += snprintf(w, (size_t)(end - w), - "%s{\"id\":%lld,\"ts\":%lld,\"author_id\":\"0x%016llx\",\"author_name\":\"%s\"," - "\"content_type\":\"%s\",\"data\":\"%.2000s\",\"local_attrs\":\"%s\"}", - sep, (long long)id, (long long)ts, (unsigned long long)author_id, esc_aname, ct, esc_data, esc_la); - sep = ","; + if (sqlite3_prepare_v2(cc->db, sql, -1, &st, NULL) != SQLITE_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: messages query ch=%s: %s", CC_ID, ch_id, sqlite3_errmsg(cc->db)); return -1; + } + sqlite3_bind_int(st, 1, count > 0 ? count : 100); sqlite3_bind_int(st, 2, offset); + size_t off = 1; buf[0] = '['; int step, result = 0; + while ((step = sqlite3_step(st)) == SQLITE_ROW) { + const char* row = (const char*)sqlite3_column_text(st, 0); size_t bytes = sqlite3_column_bytes(st, 0); + if (!row || bytes + (off > 1) + 2 > buf_size - off) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: messages exceed output buffer ch=%s capacity=%zu", CC_ID, ch_id, buf_size); + result = -1; break; + } + if (off > 1) buf[off++] = ','; + memcpy(buf + off, row, bytes); off += bytes; + } + if (result == 0 && step != SQLITE_DONE) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: messages read ch=%s: %s", CC_ID, ch_id, sqlite3_errmsg(cc->db)); result = -1; } sqlite3_finalize(st); - *w++ = ']'; - *w = '\0'; - *out_len = (size_t)(w - buf); - return 0; + if (result < 0) { buf[0] = 0; return -1; } + buf[off++] = ']'; buf[off] = 0; *out_len = off; return 0; } int chat_core_get_members_json(struct UTUN_INSTANCE* inst, const char* ch_id, char* buf, size_t buf_size, size_t* out_len) {