2021-06-27 17:56:28 +00:00
# include "configuration.h"
2021-02-21 06:03:44 +00:00
# include "AdminPlugin.h"
2021-02-26 07:34:00 +00:00
# include "Channels.h"
2021-02-21 06:03:44 +00:00
# include "MeshService.h"
# include "NodeDB.h"
# include "Router.h"
# include "main.h"
2021-03-18 11:09:31 +00:00
# ifdef PORTDUINO
# include "unistd.h"
# endif
2021-02-21 06:03:44 +00:00
AdminPlugin * adminPlugin ;
2021-08-01 18:21:36 +00:00
/// A special reserved string to indicate strings we can not share with external nodes. We will use this 'reserved' word instead.
/// Also, to make setting work correctly, if someone tries to set a string to this reserved value we assume they don't really want a change.
static const char * secretReserved = " sekrit " ;
/// If buf is !empty, change it to secret
static void hideSecret ( char * buf ) {
if ( * buf ) {
strcpy ( buf , secretReserved ) ;
}
}
/// If buf is the reserved secret word, replace the buffer with currentVal
static void writeSecret ( char * buf , const char * currentVal ) {
if ( strcmp ( buf , secretReserved ) = = 0 ) {
strcpy ( buf , currentVal ) ;
}
}
2021-03-11 02:01:57 +00:00
void AdminPlugin : : handleGetChannel ( const MeshPacket & req , uint32_t channelIndex )
{
if ( req . decoded . want_response ) {
2021-02-26 07:34:00 +00:00
// We create the reply here
AdminMessage r = AdminMessage_init_default ;
r . get_channel_response = channels . getByIndex ( channelIndex ) ;
2021-02-26 12:10:41 +00:00
r . which_variant = AdminMessage_get_channel_response_tag ;
2021-04-06 02:34:23 +00:00
myReply = allocDataProtobuf ( r ) ;
2021-02-26 07:34:00 +00:00
}
}
void AdminPlugin : : handleGetRadio ( const MeshPacket & req )
{
if ( req . decoded . want_response ) {
// We create the reply here
AdminMessage r = AdminMessage_init_default ;
2021-03-11 05:02:00 +00:00
r . get_radio_response = radioConfig ;
2021-03-07 01:51:17 +00:00
2021-05-03 06:46:30 +00:00
// NOTE: The phone app needs to know the ls_secs & phone_timeout value so it can properly expect sleep behavior.
2021-03-07 01:51:17 +00:00
// So even if we internally use 0 to represent 'use default' we still need to send the value we are
// using to the app (so that even old phone apps work with new device loads).
r . get_radio_response . preferences . ls_secs = getPref_ls_secs ( ) ;
2021-05-03 06:46:30 +00:00
r . get_radio_response . preferences . phone_timeout_secs = getPref_phone_timeout_secs ( ) ;
2021-08-01 18:21:36 +00:00
// hideSecret(r.get_radio_response.preferences.wifi_ssid); // hmm - leave public for now, because only minimally private and useful for users to know current provisioning)
hideSecret ( r . get_radio_response . preferences . wifi_password ) ;
2021-03-07 01:51:17 +00:00
2021-02-26 12:10:41 +00:00
r . which_variant = AdminMessage_get_radio_response_tag ;
2021-04-06 02:34:23 +00:00
myReply = allocDataProtobuf ( r ) ;
2021-02-26 07:34:00 +00:00
}
}
2021-08-01 18:21:36 +00:00
bool AdminPlugin : : handleReceivedProtobuf ( const MeshPacket & mp , AdminMessage * r )
2021-02-21 06:03:44 +00:00
{
assert ( r ) ;
2021-02-26 07:34:00 +00:00
switch ( r - > which_variant ) {
case AdminMessage_set_owner_tag :
DEBUG_MSG ( " Client is setting owner \n " ) ;
handleSetOwner ( r - > set_owner ) ;
break ;
case AdminMessage_set_radio_tag :
DEBUG_MSG ( " Client is setting radio \n " ) ;
handleSetRadio ( r - > set_radio ) ;
break ;
case AdminMessage_set_channel_tag :
2021-03-19 15:40:41 +00:00
DEBUG_MSG ( " Client is setting channel %d \n " , r - > set_channel . index ) ;
2021-04-03 06:56:46 +00:00
if ( r - > set_channel . index < 0 | | r - > set_channel . index > = ( int ) MAX_NUM_CHANNELS )
2021-04-06 02:34:23 +00:00
myReply = allocErrorResponse ( Routing_Error_BAD_REQUEST , & mp ) ;
2021-03-23 03:44:51 +00:00
else
handleSetChannel ( r - > set_channel ) ;
2021-02-26 07:34:00 +00:00
break ;
2021-03-23 03:44:51 +00:00
case AdminMessage_get_channel_request_tag : {
uint32_t i = r - > get_channel_request - 1 ;
2021-03-23 03:54:53 +00:00
DEBUG_MSG ( " Client is getting channel %u \n " , i ) ;
2021-03-23 03:44:51 +00:00
if ( i > = MAX_NUM_CHANNELS )
2021-04-06 02:34:23 +00:00
myReply = allocErrorResponse ( Routing_Error_BAD_REQUEST , & mp ) ;
2021-03-23 03:44:51 +00:00
else
handleGetChannel ( mp , i ) ;
2021-02-26 07:34:00 +00:00
break ;
2021-03-23 03:44:51 +00:00
}
2021-02-26 07:34:00 +00:00
case AdminMessage_get_radio_request_tag :
DEBUG_MSG ( " Client is getting radio \n " ) ;
handleGetRadio ( mp ) ;
break ;
2021-03-27 02:19:59 +00:00
case AdminMessage_reboot_seconds_tag : {
int32_t s = r - > reboot_seconds ;
DEBUG_MSG ( " Rebooting in %d seconds \n " , s ) ;
rebootAtMsec = ( s < 0 ) ? 0 : ( millis ( ) + s * 1000 ) ;
break ;
}
2021-03-18 11:09:31 +00:00
# ifdef PORTDUINO
case AdminMessage_exit_simulator_tag :
2021-03-18 11:40:00 +00:00
DEBUG_MSG ( " Exiting simulator \n " ) ;
2021-03-18 11:09:31 +00:00
_exit ( 0 ) ;
break ;
# endif
2021-02-26 07:34:00 +00:00
default :
2021-03-12 06:10:36 +00:00
// Probably a message sent by us or sent to our local node. FIXME, we should avoid scanning these messages
DEBUG_MSG ( " Ignoring nonrelevant admin %d \n " , r - > which_variant ) ;
2021-02-26 07:34:00 +00:00
break ;
2021-02-21 06:03:44 +00:00
}
return false ; // Let others look at this message also if they want
}
void AdminPlugin : : handleSetOwner ( const User & o )
{
int changed = 0 ;
if ( * o . long_name ) {
changed | = strcmp ( owner . long_name , o . long_name ) ;
strcpy ( owner . long_name , o . long_name ) ;
}
if ( * o . short_name ) {
changed | = strcmp ( owner . short_name , o . short_name ) ;
strcpy ( owner . short_name , o . short_name ) ;
}
if ( * o . id ) {
changed | = strcmp ( owner . id , o . id ) ;
strcpy ( owner . id , o . id ) ;
}
2021-04-10 03:39:13 +00:00
if ( owner . is_licensed ! = o . is_licensed ) {
changed = true ;
owner . is_licensed = o . is_licensed ;
}
2021-02-21 06:03:44 +00:00
if ( changed ) // If nothing really changed, don't broadcast on the network or write to flash
service . reloadOwner ( ) ;
}
void AdminPlugin : : handleSetChannel ( const Channel & cc )
{
channels . setChannel ( cc ) ;
2021-03-11 10:29:47 +00:00
// Just update and save the channels - no need to update the radio for ! primary channel changes
if ( cc . index = = 0 ) {
// FIXME, this updates the user preferences also, which isn't needed - we really just want to notify on configChanged
service . reloadConfig ( ) ;
2021-03-19 07:24:24 +00:00
} else {
2021-03-11 10:29:47 +00:00
channels . onConfigChanged ( ) ; // tell the radios about this change
nodeDB . saveChannelsToDisk ( ) ;
}
2021-02-21 06:03:44 +00:00
}
2021-08-01 18:21:36 +00:00
void AdminPlugin : : handleSetRadio ( RadioConfig & r )
2021-02-21 06:03:44 +00:00
{
2021-08-01 18:21:36 +00:00
writeSecret ( r . preferences . wifi_password , radioConfig . preferences . wifi_password ) ;
2021-02-21 06:03:44 +00:00
radioConfig = r ;
2021-03-11 10:29:47 +00:00
service . reloadConfig ( ) ;
2021-02-21 06:03:44 +00:00
}
2021-02-26 07:34:00 +00:00
AdminPlugin : : AdminPlugin ( ) : ProtobufPlugin ( " Admin " , PortNum_ADMIN_APP , AdminMessage_fields )
{
2021-03-11 02:01:57 +00:00
// restrict to the admin channel for rx
2021-03-13 05:14:27 +00:00
boundChannel = Channels : : adminChannel ;
2021-02-21 06:03:44 +00:00
}