Don't show messages from Ignored nodes (#11068)

* Honor Node Ignore messages

* Screenless node fix
This commit is contained in:
HarukiToreda
2026-07-19 06:32:34 -05:00
committed by GitHub
co-authored by GitHub
parent b8b5582943
commit 8c6cc5dbde
16 changed files with 195 additions and 45 deletions
+108 -21
View File
@@ -7,6 +7,7 @@
#include "SafeFile.h" #include "SafeFile.h"
#include "gps/RTC.h" #include "gps/RTC.h"
#include "memory/MemAudit.h" #include "memory/MemAudit.h"
#include <cassert>
#include <cstring> // memcpy #include <cstring> // memcpy
#ifndef MESSAGE_TEXT_POOL_SIZE #ifndef MESSAGE_TEXT_POOL_SIZE
@@ -65,6 +66,15 @@ static inline const char *getTextFromPool(uint16_t offset)
return &g_messagePool[offset]; return &g_messagePool[offset];
} }
static inline bool isIgnoredNodeNum(uint32_t nodeNum)
{
if (nodeNum == 0 || nodeNum == NODENUM_BROADCAST)
return false;
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeNum);
return nodeInfoLiteIsIgnored(node);
}
// Helper: assign a timestamp (RTC if available, else boot-relative) // Helper: assign a timestamp (RTC if available, else boot-relative)
static inline void assignTimestamp(StoredMessage &sm) static inline void assignTimestamp(StoredMessage &sm)
{ {
@@ -163,9 +173,44 @@ static inline void autosaveTick(MessageStore *store)
} }
#endif #endif
// Add from incoming/outgoing packet bool MessageStore::shouldStorePacket(const meshtastic_MeshPacket &packet) const
const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
{ {
const uint32_t localNode = nodeDB->getNodeNum();
const bool isDM = packet.to != 0 && packet.to != NODENUM_BROADCAST;
if (isDM) {
const bool outgoing = packet.from == 0 || packet.from == localNode;
const uint32_t peer = outgoing ? packet.to : packet.from;
return !isIgnoredNodeNum(peer);
}
if (packet.from != 0 && packet.from != localNode)
return !isIgnoredNodeNum(packet.from);
return true;
}
bool MessageStore::isMessageVisible(const StoredMessage &msg) const
{
const uint32_t localNode = nodeDB->getNodeNum();
if (msg.type == MessageType::DM_TO_US) {
const uint32_t peer = (msg.sender == localNode) ? msg.dest : msg.sender;
return !isIgnoredNodeNum(peer);
}
if (msg.sender != 0 && msg.sender != localNode)
return !isIgnoredNodeNum(msg.sender);
return true;
}
// Add from incoming/outgoing packet
const StoredMessage *MessageStore::tryAddFromPacket(const meshtastic_MeshPacket &packet)
{
if (!shouldStorePacket(packet)) {
LOG_DEBUG("Drop store 0x%08x", packet.from);
return nullptr;
}
StoredMessage sm; StoredMessage sm;
assignTimestamp(sm); assignTimestamp(sm);
sm.channelIndex = packet.channel; sm.channelIndex = packet.channel;
@@ -196,7 +241,14 @@ const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &pa
markMessageStoreUnsaved(); markMessageStoreUnsaved();
#endif #endif
return liveMessages.back(); return &liveMessages.back();
}
const StoredMessage &MessageStore::addFromPacket(const meshtastic_MeshPacket &packet)
{
const StoredMessage *stored = tryAddFromPacket(packet);
assert(stored);
return *stored;
} }
// Outgoing/manual message // Outgoing/manual message
@@ -323,28 +375,33 @@ void MessageStore::loadFromFlash()
resetMessagePool(); // reset pool when loading resetMessagePool(); // reset pool when loading
#ifdef FSCom #ifdef FSCom
concurrency::LockGuard guard(spiLock); {
concurrency::LockGuard guard(spiLock);
if (!FSCom.exists(filename.c_str())) if (!FSCom.exists(filename.c_str()))
return; return;
auto f = FSCom.open(filename.c_str(), FILE_O_READ); auto f = FSCom.open(filename.c_str(), FILE_O_READ);
if (!f) if (!f)
return; return;
uint8_t count = 0; uint8_t count = 0;
f.readBytes(reinterpret_cast<char *>(&count), 1); f.readBytes(reinterpret_cast<char *>(&count), 1);
if (count > MAX_MESSAGES_SAVED) if (count > MAX_MESSAGES_SAVED)
count = MAX_MESSAGES_SAVED; count = MAX_MESSAGES_SAVED;
for (uint8_t i = 0; i < count; ++i) { for (uint8_t i = 0; i < count; ++i) {
StoredMessage m; StoredMessage m;
if (!readMessageRecord(f, m)) if (!readMessageRecord(f, m))
break; break;
liveMessages.push_back(m); liveMessages.push_back(m);
}
f.close();
} }
f.close(); if (pruneHiddenMessages())
saveToFlash();
#endif #endif
// Loading messages does not trigger an autosave // Loading messages does not trigger an autosave
g_messageStoreHasUnsavedChanges = false; g_messageStoreHasUnsavedChanges = false;
@@ -406,6 +463,13 @@ template <typename Predicate> static void eraseAllMatches(std::deque<StoredMessa
} }
} }
bool MessageStore::pruneHiddenMessages()
{
const size_t before = liveMessages.size();
eraseAllMatches(liveMessages, [&](const StoredMessage &m) { return !isMessageVisible(m); });
return liveMessages.size() != before;
}
// Delete oldest message (RAM + persisted queue) // Delete oldest message (RAM + persisted queue)
void MessageStore::deleteOldestMessage() void MessageStore::deleteOldestMessage()
{ {
@@ -443,6 +507,20 @@ void MessageStore::deleteAllMessagesWithPeer(uint32_t peer)
saveToFlash(); saveToFlash();
} }
void MessageStore::deleteAllMessagesFromNode(uint32_t nodeNum)
{
const uint32_t local = nodeDB->getNodeNum();
auto pred = [&](const StoredMessage &m) {
if (m.sender == nodeNum)
return true;
if (m.type != MessageType::DM_TO_US)
return false;
return m.sender == local ? m.dest == nodeNum : m.sender == nodeNum;
};
eraseAllMatches(liveMessages, pred);
saveToFlash();
}
// Delete oldest message in a direct chat with a node // Delete oldest message in a direct chat with a node
void MessageStore::deleteOldestMessageWithPeer(uint32_t peer) void MessageStore::deleteOldestMessageWithPeer(uint32_t peer)
{ {
@@ -460,7 +538,7 @@ std::deque<StoredMessage> MessageStore::getChannelMessages(uint8_t channel) cons
{ {
std::deque<StoredMessage> result; std::deque<StoredMessage> result;
for (const auto &m : liveMessages) { for (const auto &m : liveMessages) {
if (m.type == MessageType::BROADCAST && m.channelIndex == channel) { if (isMessageVisible(m) && m.type == MessageType::BROADCAST && m.channelIndex == channel) {
result.push_back(m); result.push_back(m);
} }
} }
@@ -471,13 +549,22 @@ std::deque<StoredMessage> MessageStore::getDirectMessages() const
{ {
std::deque<StoredMessage> result; std::deque<StoredMessage> result;
for (const auto &m : liveMessages) { for (const auto &m : liveMessages) {
if (m.type == MessageType::DM_TO_US) { if (isMessageVisible(m) && m.type == MessageType::DM_TO_US) {
result.push_back(m); result.push_back(m);
} }
} }
return result; return result;
} }
bool MessageStore::hasVisibleMessages() const
{
for (const auto &m : liveMessages) {
if (isMessageVisible(m))
return true;
}
return false;
}
// Upgrade boot-relative timestamps once RTC is valid // Upgrade boot-relative timestamps once RTC is valid
// Only same-boot boot-relative messages are healed. // Only same-boot boot-relative messages are healed.
// Persisted boot-relative messages from old boots stay ??? forever. // Persisted boot-relative messages from old boots stay ??? forever.
+6 -2
View File
@@ -93,7 +93,7 @@ class MessageStore
void addLiveMessage(StoredMessage &&msg); void addLiveMessage(StoredMessage &&msg);
void addLiveMessage(const StoredMessage &msg); // convenience overload void addLiveMessage(const StoredMessage &msg); // convenience overload
const std::deque<StoredMessage> &getLiveMessages() const { return liveMessages; } const std::deque<StoredMessage> &getLiveMessages() const { return liveMessages; }
const StoredMessage *tryAddFromPacket(const meshtastic_MeshPacket &mp); // Incoming/outgoing -> RAM only
// Add new messages from packets or manual input // Add new messages from packets or manual input
const StoredMessage &addFromPacket(const meshtastic_MeshPacket &mp); // Incoming/outgoing → RAM only const StoredMessage &addFromPacket(const meshtastic_MeshPacket &mp); // Incoming/outgoing → RAM only
void addFromString(uint32_t sender, uint8_t channelIndex, const std::string &text); // Manual add void addFromString(uint32_t sender, uint8_t channelIndex, const std::string &text); // Manual add
@@ -111,13 +111,16 @@ class MessageStore
void deleteOldestMessageWithPeer(uint32_t peer); void deleteOldestMessageWithPeer(uint32_t peer);
void deleteAllMessagesInChannel(uint8_t channel); void deleteAllMessagesInChannel(uint8_t channel);
void deleteAllMessagesWithPeer(uint32_t peer); void deleteAllMessagesWithPeer(uint32_t peer);
void deleteAllMessagesFromNode(uint32_t nodeNum);
// Unified accessor (for UI code, defaults to RAM buffer) // Unified accessor (for UI code, defaults to RAM buffer)
const std::deque<StoredMessage> &getMessages() const { return liveMessages; } const std::deque<StoredMessage> &getMessages() const { return liveMessages; }
bool hasVisibleMessages() const;
// Helper filters for future use // Helper filters for future use
std::deque<StoredMessage> getChannelMessages(uint8_t channel) const; // Only broadcast messages on a channel std::deque<StoredMessage> getChannelMessages(uint8_t channel) const; // Only broadcast messages on a channel
std::deque<StoredMessage> getDirectMessages() const; // Only direct messages std::deque<StoredMessage> getDirectMessages() const; // Only direct messages
bool shouldStorePacket(const meshtastic_MeshPacket &mp) const;
bool isMessageVisible(const StoredMessage &msg) const;
// Upgrade boot-relative timestamps once RTC is valid // Upgrade boot-relative timestamps once RTC is valid
void upgradeBootRelativeTimestamps(); void upgradeBootRelativeTimestamps();
@@ -129,6 +132,7 @@ class MessageStore
static uint16_t storeText(const char *src, size_t len); static uint16_t storeText(const char *src, size_t len);
private: private:
bool pruneHiddenMessages();
std::deque<StoredMessage> liveMessages; // Single in-RAM message buffer (also used for persistence) std::deque<StoredMessage> liveMessages; // Single in-RAM message buffer (also used for persistence)
std::string filename; // Flash filename for persistence std::string filename; // Flash filename for persistence
}; };
+6 -6
View File
@@ -2110,7 +2110,7 @@ int Screen::handleInputEvent(const InputEvent *event)
if (ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) { if (ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) {
if (event->inputEvent == INPUT_BROKER_UP) { if (event->inputEvent == INPUT_BROKER_UP) {
if (messageStore.getMessages().empty()) { if (!messageStore.hasVisibleMessages()) {
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST); cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST);
} else { } else {
graphics::MessageRenderer::scrollUp(); graphics::MessageRenderer::scrollUp();
@@ -2120,7 +2120,7 @@ int Screen::handleInputEvent(const InputEvent *event)
} }
if (event->inputEvent == INPUT_BROKER_DOWN) { if (event->inputEvent == INPUT_BROKER_DOWN) {
if (messageStore.getMessages().empty()) { if (!messageStore.hasVisibleMessages()) {
cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST); cannedMessageModule->LaunchWithDestination(NODENUM_BROADCAST);
} else { } else {
graphics::MessageRenderer::scrollDown(); graphics::MessageRenderer::scrollDown();
@@ -2169,9 +2169,9 @@ int Screen::handleInputEvent(const InputEvent *event)
if (!inputIntercepted) { if (!inputIntercepted) {
#if defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2 #if defined(INPUTDRIVER_ENCODER_TYPE) && INPUTDRIVER_ENCODER_TYPE == 2
bool handledEncoderScroll = false; bool handledEncoderScroll = false;
const bool isTextMessageFrame = (framesetInfo.positions.textMessage != 255 && const bool isTextMessageFrame =
this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage && (framesetInfo.positions.textMessage != 255 &&
!messageStore.getMessages().empty()); this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage && messageStore.hasVisibleMessages());
if (isTextMessageFrame) { if (isTextMessageFrame) {
if (event->inputEvent == INPUT_BROKER_UP_LONG) { if (event->inputEvent == INPUT_BROKER_UP_LONG) {
graphics::MessageRenderer::nudgeScroll(-1); graphics::MessageRenderer::nudgeScroll(-1);
@@ -2254,7 +2254,7 @@ int Screen::handleInputEvent(const InputEvent *event)
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) { } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.lora) {
menuHandler::loraMenu(); menuHandler::loraMenu();
} else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) { } else if (this->ui->getUiState()->currentFrame == framesetInfo.positions.textMessage) {
if (!messageStore.getMessages().empty()) { if (messageStore.hasVisibleMessages()) {
menuHandler::messageResponseMenu(); menuHandler::messageResponseMenu();
} else { } else {
if (currentResolution == ScreenResolution::UltraLow) { if (currentResolution == ScreenResolution::UltraLow) {
+7 -4
View File
@@ -70,12 +70,15 @@ const StoredMessage *getNewestMessageForActiveThread()
const uint32_t peer = graphics::MessageRenderer::getThreadPeer(); const uint32_t peer = graphics::MessageRenderer::getThreadPeer();
const uint32_t localNode = nodeDB->getNodeNum(); const uint32_t localNode = nodeDB->getNodeNum();
if (mode == graphics::MessageRenderer::ThreadMode::ALL) {
return &messages.back();
}
for (auto it = messages.rbegin(); it != messages.rend(); ++it) { for (auto it = messages.rbegin(); it != messages.rend(); ++it) {
const StoredMessage &m = *it; const StoredMessage &m = *it;
if (!messageStore.isMessageVisible(m)) {
continue;
}
if (mode == graphics::MessageRenderer::ThreadMode::ALL) {
return &m;
}
if (mode == graphics::MessageRenderer::ThreadMode::CHANNEL) { if (mode == graphics::MessageRenderer::ThreadMode::CHANNEL) {
if (m.type == MessageType::BROADCAST && static_cast<int>(m.channelIndex) == channel) { if (m.type == MessageType::BROADCAST && static_cast<int>(m.channelIndex) == channel) {
+2
View File
@@ -403,6 +403,8 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
// Filter messages based on thread mode // Filter messages based on thread mode
std::deque<StoredMessage> filtered; std::deque<StoredMessage> filtered;
for (const auto &m : messageStore.getLiveMessages()) { for (const auto &m : messageStore.getLiveMessages()) {
if (!messageStore.isMessageVisible(m))
continue;
bool include = false; bool include = false;
switch (currentMode) { switch (currentMode) {
case ThreadMode::ALL: case ThreadMode::ALL:
@@ -234,7 +234,8 @@ std::string InkHUD::NotificationApplet::getNotificationText(uint16_t widthAvaila
// Pick source of message // Pick source of message
const StoredMessage *message = const StoredMessage *message =
msgIsBroadcast ? &inkhud->persistence->latestMessage.broadcast : &inkhud->persistence->latestMessage.dm; msgIsBroadcast ? &inkhud->persistence->latestMessage.broadcast : &inkhud->persistence->latestMessage.dm;
if (!message->sender || !messageStore.isMessageVisible(*message))
return parse(text);
// Find info about the sender // Find info about the sender
meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(message->sender); meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(message->sender);
@@ -270,4 +271,4 @@ std::string InkHUD::NotificationApplet::getNotificationText(uint16_t widthAvaila
return parse(text); return parse(text);
} }
#endif #endif
@@ -46,7 +46,7 @@ void InkHUD::AllMessageApplet::onRender(bool full)
message = &latestMessage->dm; message = &latestMessage->dm;
// Short circuit: no text message // Short circuit: no text message
if (!message->sender) { if (!message->sender || !messageStore.isMessageVisible(*message)) {
printAt(X(0.5), Y(0.5), "No Message", CENTER, MIDDLE); printAt(X(0.5), Y(0.5), "No Message", CENTER, MIDDLE);
return; return;
} }
@@ -138,4 +138,4 @@ bool InkHUD::AllMessageApplet::approveNotification(Notification &n)
return true; return true;
} }
#endif #endif
@@ -42,7 +42,7 @@ int InkHUD::DMApplet::onReceiveTextMessage(const meshtastic_MeshPacket *p)
void InkHUD::DMApplet::onRender(bool full) void InkHUD::DMApplet::onRender(bool full)
{ {
// Abort if no text message // Abort if no text message
if (!latestMessage->dm.sender) { if (!latestMessage->dm.sender || !messageStore.isMessageVisible(latestMessage->dm)) {
printAt(X(0.5), Y(0.5), "No DMs", CENTER, MIDDLE); printAt(X(0.5), Y(0.5), "No DMs", CENTER, MIDDLE);
return; return;
} }
@@ -131,4 +131,4 @@ bool InkHUD::DMApplet::approveNotification(Notification &n)
return true; return true;
} }
#endif #endif
@@ -191,7 +191,8 @@ ProcessMessage InkHUD::ThreadedMessageApplet::handleReceived(const meshtastic_Me
return ProcessMessage::CONTINUE; return ProcessMessage::CONTINUE;
// Store in the global messageStore - this handles sender, timestamp, channel, text, and ack status // Store in the global messageStore - this handles sender, timestamp, channel, text, and ack status
messageStore.addFromPacket(mp); if (!messageStore.tryAddFromPacket(mp))
return ProcessMessage::CONTINUE;
// If this was an incoming message, suggest that our applet becomes foreground, if permitted // If this was an incoming message, suggest that our applet becomes foreground, if permitted
if (getFrom(&mp) != nodeDB->getNodeNum()) if (getFrom(&mp) != nodeDB->getNodeNum())
+7 -1
View File
@@ -534,13 +534,19 @@ int InkHUD::Events::onReceiveTextMessage(const meshtastic_MeshPacket *packet)
if (getFrom(packet) == nodeDB->getNodeNum()) if (getFrom(packet) == nodeDB->getNodeNum())
return 0; return 0;
if (!messageStore.shouldStorePacket(*packet))
return 0;
bool isBroadcastMsg = isBroadcast(packet->to); bool isBroadcastMsg = isBroadcast(packet->to);
inkhud->persistence->latestMessage.wasBroadcast = isBroadcastMsg; inkhud->persistence->latestMessage.wasBroadcast = isBroadcastMsg;
if (!isBroadcastMsg) { if (!isBroadcastMsg) {
// DMs never pass through ThreadedMessageApplet, so add them to the global store here // DMs never pass through ThreadedMessageApplet, so add them to the global store here
// so they survive reboots. Derive the latestMessage cache entry from the stored result. // so they survive reboots. Derive the latestMessage cache entry from the stored result.
inkhud->persistence->latestMessage.dm = messageStore.addFromPacket(*packet); const StoredMessage *stored = messageStore.tryAddFromPacket(*packet);
if (!stored)
return 0;
inkhud->persistence->latestMessage.dm = *stored;
} else { } else {
// Broadcasts are added to the global store by ThreadedMessageApplet::handleReceived(). // Broadcasts are added to the global store by ThreadedMessageApplet::handleReceived().
// Here we only update the latestMessage cache used by AllMessageApplet / NotificationApplet. // Here we only update the latestMessage cache used by AllMessageApplet / NotificationApplet.
@@ -26,6 +26,10 @@ void InkHUD::Persistence::loadLatestMessage()
int lastBroadcastPos = -1, lastDMPos = -1, pos = 0; int lastBroadcastPos = -1, lastDMPos = -1, pos = 0;
for (const StoredMessage &m : messageStore.getLiveMessages()) { for (const StoredMessage &m : messageStore.getLiveMessages()) {
if (!messageStore.isMessageVisible(m)) {
pos++;
continue;
}
if (m.type == MessageType::BROADCAST) { if (m.type == MessageType::BROADCAST) {
latestMessage.broadcast = m; latestMessage.broadcast = m;
lastBroadcastPos = pos; lastBroadcastPos = pos;
+2 -2
View File
@@ -257,8 +257,8 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
p.to != NODENUM_BROADCAST && p.to != 0) // DM only p.to != NODENUM_BROADCAST && p.to != 0) // DM only
{ {
perhapsDecode(&p); perhapsDecode(&p);
const StoredMessage &sm = messageStore.addFromPacket(p); if (const StoredMessage *sm = messageStore.tryAddFromPacket(p))
graphics::MessageRenderer::handleNewMessage(nullptr, sm, p); // notify UI graphics::MessageRenderer::handleNewMessage(nullptr, *sm, p); // notify UI
}) })
#if !MESHTASTIC_EXCLUDE_ADMIN #if !MESHTASTIC_EXCLUDE_ADMIN
// Note admin requests on their way out: AdminModule only accepts a response from a remote we // Note admin requests on their way out: AdminModule only accepts a response from a remote we
+3
View File
@@ -3268,6 +3268,9 @@ void NodeDB::addFromContact(meshtastic_SharedContact contact)
LOG_WARN(PROTECTED_CAP_WARN_FMT, "ignore", contact.node_num, MAX_NUM_NODES - 2); LOG_WARN(PROTECTED_CAP_WARN_FMT, "ignore", contact.node_num, MAX_NUM_NODES - 2);
nodeInfoLiteSetBit(info, NODEINFO_BITFIELD_IS_FAVORITE_MASK, false); nodeInfoLiteSetBit(info, NODEINFO_BITFIELD_IS_FAVORITE_MASK, false);
eraseNodeSatellites(contact.node_num); eraseNodeSatellites(contact.node_num);
#if HAS_SCREEN || defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
messageStore.deleteAllMessagesFromNode(contact.node_num);
#endif
} else { } else {
/* Clients are sending add_contact before every text message DM (because clients may hold a larger node database with /* Clients are sending add_contact before every text message DM (because clients may hold a larger node database with
* public keys than the radio holds). However, we don't want to update last_heard just because we sent someone a DM! * public keys than the radio holds). However, we don't want to update last_heard just because we sent someone a DM!
+8
View File
@@ -29,6 +29,7 @@
#include "Default.h" #include "Default.h"
#include "MeshRadio.h" #include "MeshRadio.h"
#include "MessageStore.h"
#include "RadioInterface.h" #include "RadioInterface.h"
#include "TypeConversions.h" #include "TypeConversions.h"
#include "mesh/RadioLibInterface.h" #include "mesh/RadioLibInterface.h"
@@ -537,7 +538,14 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
if (node != NULL) { if (node != NULL) {
if (nodeDB->setProtectedFlag(node, NODEINFO_BITFIELD_IS_IGNORED_MASK, true)) { if (nodeDB->setProtectedFlag(node, NODEINFO_BITFIELD_IS_IGNORED_MASK, true)) {
nodeDB->eraseNodeSatellites(node->num); nodeDB->eraseNodeSatellites(node->num);
#if HAS_SCREEN || defined(MESHTASTIC_INCLUDE_NICHE_GRAPHICS)
messageStore.deleteAllMessagesFromNode(node->num);
#endif
saveChanges(SEGMENT_NODEDATABASE, false); saveChanges(SEGMENT_NODEDATABASE, false);
#if HAS_SCREEN
if (screen)
screen->setFrames(graphics::Screen::FOCUS_PRESERVE);
#endif
} else if (mp.from == 0) { // local request from the phone - tell the user why it didn't take } else if (mp.from == 0) { // local request from the phone - tell the user why it didn't take
sendWarning(NodeDB::PROTECTED_CAP_WARN_FMT, "ignore", r->set_ignored_node, MAX_NUM_NODES - 2); sendWarning(NodeDB::PROTECTED_CAP_WARN_FMT, "ignore", r->set_ignored_node, MAX_NUM_NODES - 2);
} else { } else {
+4 -2
View File
@@ -25,12 +25,14 @@ ProcessMessage TextMessageModule::handleReceived(const meshtastic_MeshPacket &mp
// Guard against running in MeshtasticUI or with no screen // Guard against running in MeshtasticUI or with no screen
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) { if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_COLOR) {
// Store in the central message history // Store in the central message history
const StoredMessage &sm = messageStore.addFromPacket(mp); const StoredMessage *sm = messageStore.tryAddFromPacket(mp);
if (!sm)
return ProcessMessage::CONTINUE;
// Pass message to renderer (banner + thread switching + scroll reset) // Pass message to renderer (banner + thread switching + scroll reset)
// Use the global Screen singleton to retrieve the current OLED display // Use the global Screen singleton to retrieve the current OLED display
auto *display = screen ? screen->getDisplayDevice() : nullptr; auto *display = screen ? screen->getDisplayDevice() : nullptr;
graphics::MessageRenderer::handleNewMessage(display, sm, mp); graphics::MessageRenderer::handleNewMessage(display, *sm, mp);
}) })
// Only trigger screen wake if configuration allows it // Only trigger screen wake if configuration allows it
if (shouldWakeOnReceivedMessage()) { if (shouldWakeOnReceivedMessage()) {
+29
View File
@@ -55,6 +55,32 @@ static bool isConnected = false;
static uint32_t lastPositionUnavailableWarning = 0; static uint32_t lastPositionUnavailableWarning = 0;
static const uint32_t POSITION_UNAVAILABLE_WARNING_INTERVAL_MS = 15000; // 15 seconds static const uint32_t POSITION_UNAVAILABLE_WARNING_INTERVAL_MS = 15000; // 15 seconds
inline bool shouldDropMqttDownlink(const meshtastic_MeshPacket &packet)
{
if (is_in_repeated(config.lora.ignore_incoming, packet.from)) {
LOG_INFO("Drop MQTT ignored 0x%08x", packet.from);
return true;
}
const meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(packet.from);
if (nodeInfoLiteIsIgnored(node)) {
LOG_INFO("Drop MQTT node 0x%08x", packet.from);
return true;
}
if (packet.from == NODENUM_BROADCAST) {
LOG_INFO("Drop MQTT broadcast src");
return true;
}
if (config.lora.ignore_mqtt) {
LOG_INFO("Drop MQTT ignore_mqtt");
return true;
}
return false;
}
inline void onReceiveProto(char *topic, byte *payload, size_t length) inline void onReceiveProto(char *topic, byte *payload, size_t length)
{ {
const DecodedServiceEnvelope e(payload, length); const DecodedServiceEnvelope e(payload, length);
@@ -122,6 +148,9 @@ inline void onReceiveProto(char *topic, byte *payload, size_t length)
p->which_payload_variant = e.packet->which_payload_variant; p->which_payload_variant = e.packet->which_payload_variant;
memcpy(&p->decoded, &e.packet->decoded, std::max(sizeof(p->decoded), sizeof(p->encrypted))); memcpy(&p->decoded, &e.packet->decoded, std::max(sizeof(p->decoded), sizeof(p->encrypted)));
if (shouldDropMqttDownlink(*p))
return;
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
if (moduleConfig.mqtt.encryption_enabled) { if (moduleConfig.mqtt.encryption_enabled) {
LOG_INFO("Ignore decoded message on MQTT, encryption is enabled"); LOG_INFO("Ignore decoded message on MQTT, encryption is enabled");