fix(companion): clear stale channel-index refs when a channel is removed

CMD_SET_CHANNEL clearing a slot (empty secret) left bot_channel_idx,
loc_share_channel_idx, and the per-channel melody bitmasks pointing at that
index. A new channel added later at the same slot would then silently
inherit the old one's bot target, Live Share target, or notification
melody. New onChannelRemoved() hook, mirroring onContactRemoved(), turns
the bot/Live Share channel target off (fail closed) and clears the melody
bits for that index.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
MarekZegare4
2026-06-27 00:39:10 +02:00
co-authored by Claude Sonnet 4.6
parent 43c3f43e10
commit 6a394e2d7a
4 changed files with 45 additions and 0 deletions
+13
View File
@@ -1665,6 +1665,11 @@ void MyMesh::startInterface(BaseSerialInterface &serial) {
serial.enable();
}
static bool isAllZero(const uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) if (buf[i]) return false;
return true;
}
void MyMesh::handleCmdFrame(size_t len) {
if (cmd_frame[0] == CMD_DEVICE_QUERY && len >= 2) { // sent when app establishes connection
app_target_ver = cmd_frame[1]; // which version of protocol does app understand
@@ -2378,6 +2383,12 @@ void MyMesh::handleCmdFrame(size_t len) {
memcpy(channel.channel.secret, &cmd_frame[2 + 32], 32); // 256-bit key
if (setChannel(channel_idx, channel)) {
saveChannels();
// An all-zero secret is this codebase's "empty slot" sentinel (same
// check loadChannels()/saveChannels() use) -- the app just cleared this
// channel, so drop anything that referenced it by index, the same way
// onContactRemoved() does for contacts.
if (_ui && isAllZero(channel.channel.secret, sizeof(channel.channel.secret)))
_ui->onChannelRemoved(channel_idx);
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx
@@ -2390,6 +2401,8 @@ void MyMesh::handleCmdFrame(size_t len) {
memcpy(channel.channel.secret, &cmd_frame[2 + 32], 16); // 128-bit key
if (setChannel(channel_idx, channel)) {
saveChannels();
if (_ui && isAllZero(channel.channel.secret, sizeof(channel.channel.secret)))
_ui->onChannelRemoved(channel_idx);
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_NOT_FOUND); // bad channel_idx