diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 7bafa40e..336f788c 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -108,6 +108,8 @@ static uint32_t _atoi(const char* sp) { #define CMD_SET_ADVERT_LATLON 14 #define CMD_REMOVE_CONTACT 15 #define CMD_SHARE_CONTACT 16 +#define CMD_EXPORT_CONTACT 17 +#define CMD_IMPORT_CONTACT 18 #define RESP_CODE_OK 0 #define RESP_CODE_ERR 1 @@ -120,6 +122,7 @@ static uint32_t _atoi(const char* sp) { #define RESP_CODE_CHANNEL_MSG_RECV 8 // a reply to CMD_SYNC_NEXT_MESSAGE #define RESP_CODE_CURR_TIME 9 // a reply to CMD_GET_DEVICE_TIME #define RESP_CODE_NO_MORE_MESSAGES 10 // a reply to CMD_SYNC_NEXT_MESSAGE +#define RESP_CODE_EXPORT_CONTACT 11 // these are _pushed_ to client app at any time #define PUSH_CODE_ADVERT 0x80 @@ -712,6 +715,35 @@ public: } else { writeErrFrame(); // not found, or unable to send } + } else if (cmd_frame[0] == CMD_EXPORT_CONTACT) { + if (len < 1 + PUB_KEY_SIZE) { + // export SELF + auto pkt = createSelfAdvert(_prefs.node_name, _prefs.node_lat, _prefs.node_lon); + if (pkt) { + out_frame[0] = RESP_CODE_EXPORT_CONTACT; + uint8_t out_len = pkt->writeTo(&out_frame[1]); + releasePacket(pkt); // undo the obtainNewPacket() + _serial->writeFrame(out_frame, out_len + 1); + } else { + writeErrFrame(); // Error + } + } else { + uint8_t* pub_key = &cmd_frame[1]; + ContactInfo* recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); + uint8_t out_len; + if (recipient && (out_len = exportContact(*recipient, &out_frame[1])) > 0) { + out_frame[0] = RESP_CODE_EXPORT_CONTACT; + _serial->writeFrame(out_frame, out_len + 1); + } else { + writeErrFrame(); // not found + } + } + } else if (cmd_frame[0] == CMD_IMPORT_CONTACT && len > 2+32+64) { + if (importContact(&cmd_frame[1], len - 1)) { + writeOKFrame(); + } else { + writeErrFrame(); + } } else if (cmd_frame[0] == CMD_SYNC_NEXT_MESSAGE) { int out_len; if ((out_len = getFromOfflineQueue(out_frame)) > 0) { @@ -764,6 +796,7 @@ public: void loop() { BaseChatMesh::loop(); + size_t len = _serial->checkRecvFrame(cmd_frame); if (len > 0) { handleCmdFrame(len); diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 006fda0a..fa3e104f 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -200,17 +200,8 @@ class MyMesh : public BaseChatMesh, ContactVisitor { if (len % 2 == 0) { len >>= 1; // halve, for num bytes if (mesh::Utils::fromHex(tmp_buf, len, command)) { - auto pkt = obtainNewPacket(); - if (pkt) { - if (pkt->readFrom(tmp_buf, len) && pkt->getPayloadType() == PAYLOAD_TYPE_ADVERT) { - pkt->header |= ROUTE_TYPE_FLOOD; // simulate it being received flood-mode - onRecvPacket(pkt); // loop-back, as if received over radio - releasePacket(pkt); // undo the obtainNewPacket() - return; - } else { - releasePacket(pkt); // undo the obtainNewPacket() - } - } + importContact(tmp_buf, len); + return; } } } diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index 9c91f640..093e0400 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -262,6 +262,24 @@ bool BaseChatMesh::shareContactZeroHop(const ContactInfo& contact) { return true; // success } +uint8_t BaseChatMesh::exportContact(const ContactInfo& contact, uint8_t dest_buf[]) { + return getBlobByKey(contact.id.pub_key, PUB_KEY_SIZE, dest_buf); // retrieve last raw advert packet +} + +bool BaseChatMesh::importContact(const uint8_t src_buf[], uint8_t len) { + auto pkt = obtainNewPacket(); + if (pkt) { + if (pkt->readFrom(src_buf, len) && pkt->getPayloadType() == PAYLOAD_TYPE_ADVERT) { + pkt->header |= ROUTE_TYPE_FLOOD; // simulate it being received flood-mode + _pendingLoopback = pkt; // loop-back, as if received over radio + return true; // success + } else { + releasePacket(pkt); // undo the obtainNewPacket() + } + } + return false; // error +} + bool BaseChatMesh::sendLogin(const ContactInfo& recipient, const char* password, uint32_t& est_timeout) { uint8_t shared_secret[32]; self_id.calcSharedSecret(shared_secret, recipient.id); // TODO: cache this @@ -416,4 +434,10 @@ void BaseChatMesh::loop() { onSendTimeout(); txt_send_timeout = 0; } -} \ No newline at end of file + + if (_pendingLoopback) { + onRecvPacket(_pendingLoopback); // loop-back, as if received over radio + releasePacket(_pendingLoopback); // undo the obtainNewPacket() + _pendingLoopback = NULL; + } +} diff --git a/src/helpers/BaseChatMesh.h b/src/helpers/BaseChatMesh.h index 1fc79026..814336b5 100644 --- a/src/helpers/BaseChatMesh.h +++ b/src/helpers/BaseChatMesh.h @@ -60,6 +60,7 @@ class BaseChatMesh : public mesh::Mesh { mesh::GroupChannel channels[MAX_GROUP_CHANNELS]; int num_channels; #endif + mesh::Packet* _pendingLoopback; uint8_t temp_buf[MAX_TRANS_UNIT]; mesh::Packet* composeMsgPacket(const ContactInfo& recipient, uint32_t timestamp, uint8_t attempt, const char *text, uint32_t& expected_ack); @@ -73,6 +74,7 @@ protected: num_channels = 0; #endif txt_send_timeout = 0; + _pendingLoopback = NULL; } // 'UI' concepts, for sub-classes to implement @@ -108,6 +110,8 @@ public: bool sendGroupMessage(uint32_t timestamp, mesh::GroupChannel& channel, const char* sender_name, const char* text, int text_len); bool sendLogin(const ContactInfo& recipient, const char* password, uint32_t& est_timeout); bool shareContactZeroHop(const ContactInfo& contact); + uint8_t exportContact(const ContactInfo& contact, uint8_t dest_buf[]); + bool importContact(const uint8_t src_buf[], uint8_t len); void resetPathTo(ContactInfo& recipient); void scanRecentContacts(int last_n, ContactVisitor* visitor); ContactInfo* searchContactsByPrefix(const char* name_prefix);