Don't show messages from Ignored nodes (#11068)
* Honor Node Ignore messages * Screenless node fix
This commit is contained in:
+108
-21
@@ -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
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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!
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user