From 2c0ace2519d9c910b3b8fd1cba93f0a61e705d35 Mon Sep 17 00:00:00 2001 From: Scott Powell Date: Sun, 23 Aug 2026 22:04:05 +1000 Subject: [PATCH] * new TXT_TYPE_CLI_COMMAND (3) --- examples/companion_radio/MyMesh.cpp | 18 +++++++++--------- examples/companion_radio/MyMesh.h | 2 ++ examples/simple_repeater/MyMesh.cpp | 2 +- examples/simple_room_server/MyMesh.cpp | 4 ++-- examples/simple_secure_chat/main.cpp | 6 +++++- examples/simple_sensor/SensorMesh.cpp | 2 +- src/helpers/BaseChatMesh.cpp | 8 ++++++-- src/helpers/BaseChatMesh.h | 3 ++- src/helpers/TxtDataHelpers.h | 4 +++- 9 files changed, 31 insertions(+), 18 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 489fd69c0..99b3196d5 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -530,20 +530,20 @@ void MyMesh::onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t queueMessage(from, TXT_TYPE_PLAIN, pkt, sender_timestamp, NULL, 0, text); } -void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, +void MyMesh::onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) { + markConnectionActive(from); // in case this is from a server, and we have a connection + queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); +} + +void MyMesh::onCLICommandRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text, char* reply) { markConnectionActive(from); // in case this is from a server, and we have a connection if (from.isRemoteCLIAllowed()) { - if (text[0] == '>') { // is this a CLI reply? - queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, &text[1]); - } else { - *reply++ = '>'; // ensure the special 'is reply' prefix - if (!handleCommand(text, sender_timestamp, reply)) { - strcat(reply, "Unknown command"); // reply may have cmd prefix from 'text' - } + if (!handleCommand(text, sender_timestamp, reply)) { + strcat(reply, "Unknown command"); // reply may have cmd prefix from 'text' } } else { - queueMessage(from, TXT_TYPE_CLI_DATA, pkt, sender_timestamp, NULL, 0, text); + queueMessage(from, TXT_TYPE_CLI_COMMAND, pkt, sender_timestamp, NULL, 0, text); } } diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index b60030a6d..780de35dd 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -134,6 +134,8 @@ protected: void onMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text) override; void onCommandDataRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, + const char *text) override; + void onCLICommandRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const char *text, char* reply) override; void onSignedMessageRecv(const ContactInfo &from, mesh::Packet *pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override; diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index a711ec0a5..9f3c90e9b 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -704,7 +704,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, memcpy(&sender_timestamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong) uint8_t flags = (data[4] >> 2); // message attempt number, and other flags - if (!(flags == TXT_TYPE_PLAIN || flags == TXT_TYPE_CLI_DATA)) { + if (!(flags == TXT_TYPE_PLAIN || flags == TXT_TYPE_CLI_DATA || flags == TXT_TYPE_CLI_COMMAND)) { MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported text type received: flags=%02x", (uint32_t)flags); } else if (sender_timestamp >= client->last_timestamp) { // prevent replay attacks bool is_retry = (sender_timestamp == client->last_timestamp); diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 546d094fc..b786241aa 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -443,7 +443,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, memcpy(&sender_timestamp, data, 4); // timestamp (by sender's RTC clock - which could be wrong) uint8_t flags = (data[4] >> 2); // message attempt number, and other flags - if (!(flags == TXT_TYPE_PLAIN || flags == TXT_TYPE_CLI_DATA)) { + if (!(flags == TXT_TYPE_PLAIN || flags == TXT_TYPE_CLI_DATA || flags == TXT_TYPE_CLI_COMMAND)) { MESH_DEBUG_PRINTLN("onPeerDataRecv: unsupported command flags received: flags=%02x", (uint32_t)flags); } else if (sender_timestamp >= client->last_timestamp) { // prevent replay attacks, but send Acks for retries bool is_retry = (sender_timestamp == client->last_timestamp); @@ -463,7 +463,7 @@ void MyMesh::onPeerDataRecv(mesh::Packet *packet, uint8_t type, int sender_idx, uint8_t temp[166]; bool send_ack; - if (flags == TXT_TYPE_CLI_DATA) { + if (flags == TXT_TYPE_CLI_DATA || flags == TXT_TYPE_CLI_COMMAND) { if (client->isAdmin()) { if (is_retry) { temp[5] = 0; // no reply diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 241fe1c21..159249dfa 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -240,8 +240,12 @@ protected: } } - void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text, char* reply) override { + void onCommandDataRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) override { } + + void onCLICommandRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text, char* reply) override { + } + void onSignedMessageRecv(const ContactInfo& from, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) override { } diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index 9bfa5ec6a..b4b42f646 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -576,7 +576,7 @@ void SensorMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender_i sendAckTo(*from, ack_hash, packet->getPathHashSize()); } } - } else if (flags == TXT_TYPE_CLI_DATA) { + } else if (flags == TXT_TYPE_CLI_DATA || flags == TXT_TYPE_CLI_COMMAND) { from->last_timestamp = sender_timestamp; from->last_activity = getRTCClock()->getCurrentTime(); diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index bf8a861c9..d66aabca4 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -256,13 +256,17 @@ void BaseChatMesh::onPeerDataRecv(mesh::Packet* packet, uint8_t type, int sender sendAckTo(from, ack_hash, 6); } } else if (flags == TXT_TYPE_CLI_DATA) { + char *text = (char *)&data[5]; + onCommandDataRecv(from, packet, sender_timestamp, text); // let UI know + // NOTE: no ack expected for CLI_DATA replies + } else if (flags == TXT_TYPE_CLI_COMMAND) { uint8_t temp[166]; char *command = (char *)&data[5]; char *reply = (char *)&temp[5]; *reply = 0; - onCommandDataRecv(from, packet, sender_timestamp, command, reply); // let UI know - // NOTE: no ack expected for CLI_DATA replies + onCLICommandRecv(from, packet, sender_timestamp, command, reply); // let UI know + // NOTE: no ack expected for CLI_COMMAND replies int text_len = strlen(reply); if (text_len > 0) { diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 331d1041b..a5fe54d5e 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -113,7 +113,8 @@ protected: virtual void onContactPathUpdated(const ContactInfo& contact) = 0; virtual bool onContactPathRecv(ContactInfo& from, uint8_t* in_path, uint8_t in_path_len, uint8_t* out_path, uint8_t out_path_len, uint8_t extra_type, uint8_t* extra, uint8_t extra_len); virtual void onMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0; - virtual void onCommandDataRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text, char* reply) = 0; + virtual void onCommandDataRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text) = 0; + virtual void onCLICommandRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const char *text, char* reply) = 0; virtual void onSignedMessageRecv(const ContactInfo& contact, mesh::Packet* pkt, uint32_t sender_timestamp, const uint8_t *sender_prefix, const char *text) = 0; virtual uint32_t calcFloodTimeoutMillisFor(uint32_t pkt_airtime_millis) const = 0; virtual uint32_t calcDirectTimeoutMillisFor(uint32_t pkt_airtime_millis, uint8_t path_len) const = 0; diff --git a/src/helpers/TxtDataHelpers.h b/src/helpers/TxtDataHelpers.h index ece494f29..693a47cad 100644 --- a/src/helpers/TxtDataHelpers.h +++ b/src/helpers/TxtDataHelpers.h @@ -4,8 +4,10 @@ #include #define TXT_TYPE_PLAIN 0 // a plain text message -#define TXT_TYPE_CLI_DATA 1 // a CLI command +#define TXT_TYPE_CLI_DATA 1 // a CLI command -or- reply #define TXT_TYPE_SIGNED_PLAIN 2 // plain text, signed by sender +#define TXT_TYPE_CLI_COMMAND 3 // a CLI command (explictly) + #define DATA_TYPE_RESERVED 0x0000 // reserved for future use #define DATA_TYPE_DEV 0xFFFF // developer namespace for experimenting with group/channel datagrams and building apps