From 31d602c88a04b52d38fd39bd2ecc6f4b56943d9e Mon Sep 17 00:00:00 2001 From: MarekZegare4 Date: Sun, 28 Jun 2026 12:27:16 +0200 Subject: [PATCH] fix(companion): reply to the right author in rooms (and keep nicks UTF-8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A room is viewed through DM history, where each post is stored "Author: text" and shown attributed to that author. The reply path, though, built the @[nick] prefix from _sel_contact.name — the room server's own name — so replying to someone's post in a room addressed the room, not the person. New buildDmReplyPrefix() derives the addressee from the same author the history shows (via dmDisplayParts): the post's author in a room, the contact name in a 1:1 DM. It also stores the nick raw (UTF-8), like the channel reply path, instead of running it through the lossy display transliterator — the prefix is sent over the air verbatim, so a non-ASCII nick was previously corrupted on the wire. Co-Authored-By: Claude Opus 4.8 --- .../companion_radio/ui-new/QuickMsgScreen.h | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/examples/companion_radio/ui-new/QuickMsgScreen.h b/examples/companion_radio/ui-new/QuickMsgScreen.h index b560f0b1..533bcb5e 100644 --- a/examples/companion_radio/ui-new/QuickMsgScreen.h +++ b/examples/companion_radio/ui-new/QuickMsgScreen.h @@ -258,6 +258,19 @@ class QuickMsgScreen : public UIScreen { return true; } + // Build "@[nick] " into _reply_prefix for a reply to a DM/room post, raw + // (UTF-8) so it goes out over the air intact — like buildChannelReplyPrefix, + // and unlike the old per-site code which ran the name through the lossy + // display transliterator. Addresses the same author the history shows + // (dmDisplayParts): in a room every post is stored "Author: text", so the + // addressee is that author, not the room server's own name (_sel_contact.name); + // a plain 1:1 DM uses the contact name. Caller ensures the post is incoming. + void buildDmReplyPrefix(const DmHistEntry& e) { + char nick[32]; + dmDisplayParts(e, _sel_contact.type == ADV_TYPE_ROOM, _sel_contact.name, nick, sizeof(nick)); + snprintf(_reply_prefix, sizeof(_reply_prefix), "@[%.31s] ", nick); + } + void startReply(bool to_channel) { _sending_to_channel = to_channel; _reply_mode = true; @@ -1788,10 +1801,7 @@ public: int ring_pos = dmHistEntryForContact(_sel_contact.id.pub_key, _dm_hist_sel); if (ring_pos >= 0) { bool reply_ok = !_dm_hist[ring_pos].outgoing; - if (reply_ok) { - char _tname[32]; DisplayDriver::translateUTF8Static(_tname, _sel_contact.name, sizeof(_tname)); - snprintf(_reply_prefix, sizeof(_reply_prefix), "@[%.31s] ", _tname); - } + if (reply_ok) buildDmReplyPrefix(_dm_hist[ring_pos]); buildFsMenu(_dm_hist[ring_pos].text, reply_ok); } } @@ -1847,10 +1857,7 @@ public: int ring_pos = dmHistEntryForContact(_sel_contact.id.pub_key, _dm_hist_sel); if (ring_pos >= 0) { bool reply_ok = !_dm_hist[ring_pos].outgoing; - if (reply_ok) { - char _tname[32]; DisplayDriver::translateUTF8Static(_tname, _sel_contact.name, sizeof(_tname)); - snprintf(_reply_prefix, sizeof(_reply_prefix), "@[%.31s] ", _tname); - } + if (reply_ok) buildDmReplyPrefix(_dm_hist[ring_pos]); buildFsMenu(_dm_hist[ring_pos].text, reply_ok); } return true;