diff --git a/src/chat/chat_channel.c b/src/chat/chat_channel.c index b5296c9e..4fe79c60 100644 --- a/src/chat/chat_channel.c +++ b/src/chat/chat_channel.c @@ -123,14 +123,12 @@ void chat_core_create_channel(struct UTUN_INSTANCE* inst, struct chat_channel_cr myid, inst->my_keys.public_key, join_ts, inst->my_ed25519_privkey, join_sig); - char juser3[256]; snprintf(juser3, sizeof(juser3), "{\"name\":\"%s\"}", - inst->name[0] ? inst->name : ""); /* корень дерева приглашений: подписан ключом группы (канальный ed25519) */ uint8_t root_sig[64]; memset(root_sig, 0, 64); member_sync_sign_pubkey(req->ed25519_privkey, inst->my_keys.public_key, root_sig); int mrc = member_sync_put(inst, req->channel_id, myid, inst->my_keys.public_key, inst->my_ed25519_pubkey, - join_sig, join_ts, NULL, 0, juser3, NULL, NULL, 0, 0, root_sig); + join_sig, join_ts, NULL, 0, "{}", NULL, NULL, 0, 0, root_sig); if (mrc < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: member_sync_put(self) FAILED ch=%s rc=%d", CC_ID, req->channel_id, mrc); diff --git a/src/chat/chat_core.h b/src/chat/chat_core.h index ae232f27..7f9e5e25 100644 --- a/src/chat/chat_core.h +++ b/src/chat/chat_core.h @@ -241,6 +241,9 @@ int chat_core_get_node_name(struct UTUN_INSTANCE* inst, uint64_t node_id, char* /* Аватарка лежит в avatars/.png внутри дерева своего UID/канала. server=0 удаляет ссылку. */ int chat_core_set_my_avatar(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t server, const char* file); +int chat_core_name_userinfo(const char* name, char* out, size_t capacity); +int chat_core_get_my_profile(struct UTUN_INSTANCE* inst, const char* channel, char* out, size_t capacity, + uint8_t signature[64], uint64_t* timestamp); struct chat_avatar_req { struct UTUN_INSTANCE* inst; uint64_t id, group, server; diff --git a/src/chat/chat_profile.c b/src/chat/chat_profile.c index ad34071e..86f8c6c8 100644 --- a/src/chat/chat_profile.c +++ b/src/chat/chat_profile.c @@ -85,6 +85,38 @@ static int profile_copy_pair(const char* key, const char* value, void* arg) { return profile_pair(p, key, value); } +int chat_core_name_userinfo(const char* name, char* out, size_t capacity) { + struct profile_json p = { .text = "{", .used = 1 }; + if (!name || !out || profile_pair(&p, "name", name) < 0 || p.used + 2 > capacity || p.used >= MS_USERINFO_MAX) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: cannot encode display name capacity=%zu", capacity); return -1; + } + p.text[p.used++] = '}'; p.text[p.used] = 0; memcpy(out, p.text, p.used + 1); return 0; +} + +int chat_core_get_my_profile(struct UTUN_INSTANCE* inst, const char* channel, char* out, size_t capacity, + uint8_t signature[64], uint64_t* timestamp) { + struct chat_core_ctx* cc = CC(inst); + if (!cc || !cc->db || !channel || !out || !signature || !timestamp) { + DEBUG_ERROR(DEBUG_CATEGORY_CHAT, "profile: invalid read request"); return -1; + } + char table[80], sql[256]; peers_table_name(channel, table, sizeof(table)); + snprintf(sql, sizeof(sql), "SELECT userinfo,update_sig,update_ts FROM \"%s\" WHERE node_id=?", table); + sqlite3_stmt* st = NULL; int result = -1; + if (sqlite3_prepare_v2(cc->db, sql, -1, &st, NULL) == SQLITE_OK) { + sqlite3_bind_int64(st, 1, (sqlite3_int64)cc->my_node_id); + if (sqlite3_step(st) == SQLITE_ROW) { + const char* json = (const char*)sqlite3_column_text(st, 0); size_t size = json ? strlen(json) : 0; + if (json && size <= MS_USERINFO_MAX && size < capacity && sqlite3_column_bytes(st, 1) == 64 && sqlite3_column_int64(st, 2) > 0) { + memcpy(out, json, size + 1); memcpy(signature, sqlite3_column_blob(st, 1), 64); + *timestamp = (uint64_t)sqlite3_column_int64(st, 2); result = 0; + } + } + sqlite3_finalize(st); + } + if (result) DEBUG_WARN(DEBUG_CATEGORY_CHAT, "profile: signed local profile unavailable channel=%s capacity=%zu", channel, capacity); + return result; +} + static int profile_update_channel(struct UTUN_INSTANCE* inst, const char* ch, int avatar, uint64_t server, const char* file) { struct chat_core_ctx* cc = CC(inst); if (!cc || !cc->initialized || !cc->db) {