Added command handling and sending
This commit is contained in:
parent
c1b5b776d7
commit
7076fae5cc
|
@ -829,7 +829,9 @@ class SidebandApp(MDApp):
|
||||||
self.message_send_action()
|
self.message_send_action()
|
||||||
|
|
||||||
if text == "l":
|
if text == "l":
|
||||||
if self.root.ids.screen_manager.current == "map_screen":
|
if self.root.ids.screen_manager.current == "messages_screen":
|
||||||
|
self.message_propagation_action(self)
|
||||||
|
elif self.root.ids.screen_manager.current == "map_screen":
|
||||||
self.map_layers_action()
|
self.map_layers_action()
|
||||||
else:
|
else:
|
||||||
self.announces_action(self)
|
self.announces_action(self)
|
||||||
|
@ -1006,6 +1008,7 @@ class SidebandApp(MDApp):
|
||||||
|
|
||||||
def open_conversation(self, context_dest, direction="left"):
|
def open_conversation(self, context_dest, direction="left"):
|
||||||
self.outbound_mode_paper = False
|
self.outbound_mode_paper = False
|
||||||
|
self.outbound_mode_command = False
|
||||||
if self.sideband.config["propagation_by_default"]:
|
if self.sideband.config["propagation_by_default"]:
|
||||||
self.outbound_mode_propagation = True
|
self.outbound_mode_propagation = True
|
||||||
else:
|
else:
|
||||||
|
@ -1075,7 +1078,26 @@ class SidebandApp(MDApp):
|
||||||
else:
|
else:
|
||||||
msg_content = self.messages_view.ids.message_text.text
|
msg_content = self.messages_view.ids.message_text.text
|
||||||
context_dest = self.messages_view.ids.messages_scrollview.active_conversation
|
context_dest = self.messages_view.ids.messages_scrollview.active_conversation
|
||||||
if self.outbound_mode_paper:
|
if self.outbound_mode_command:
|
||||||
|
if self.sideband.send_command(msg_content, context_dest, False):
|
||||||
|
self.messages_view.ids.message_text.text = ""
|
||||||
|
self.messages_view.ids.messages_scrollview.scroll_y = 0
|
||||||
|
self.jobs(0)
|
||||||
|
else:
|
||||||
|
self.messages_view.send_error_dialog = MDDialog(
|
||||||
|
title="Error",
|
||||||
|
text="Could not send the command. Check that the syntax is correct, and that the command is supported.",
|
||||||
|
buttons=[
|
||||||
|
MDRectangleFlatButton(
|
||||||
|
text="OK",
|
||||||
|
font_size=dp(18),
|
||||||
|
on_release=self.messages_view.close_send_error_dialog
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
self.messages_view.send_error_dialog.open()
|
||||||
|
|
||||||
|
elif self.outbound_mode_paper:
|
||||||
if self.sideband.paper_message(msg_content, context_dest):
|
if self.sideband.paper_message(msg_content, context_dest):
|
||||||
self.messages_view.ids.message_text.text = ""
|
self.messages_view.ids.message_text.text = ""
|
||||||
self.messages_view.ids.messages_scrollview.scroll_y = 0
|
self.messages_view.ids.messages_scrollview.scroll_y = 0
|
||||||
|
@ -1117,16 +1139,24 @@ class SidebandApp(MDApp):
|
||||||
self.object_details_action(self.messages_view, from_conv=True)
|
self.object_details_action(self.messages_view, from_conv=True)
|
||||||
|
|
||||||
def message_propagation_action(self, sender):
|
def message_propagation_action(self, sender):
|
||||||
if self.outbound_mode_paper:
|
if self.outbound_mode_command:
|
||||||
self.outbound_mode_paper = False
|
self.outbound_mode_paper = False
|
||||||
self.outbound_mode_propagation = False
|
self.outbound_mode_propagation = False
|
||||||
|
self.outbound_mode_command = False
|
||||||
else:
|
else:
|
||||||
if self.outbound_mode_propagation:
|
if self.outbound_mode_paper:
|
||||||
self.outbound_mode_paper = True
|
|
||||||
self.outbound_mode_propagation = False
|
|
||||||
else:
|
|
||||||
self.outbound_mode_propagation = True
|
|
||||||
self.outbound_mode_paper = False
|
self.outbound_mode_paper = False
|
||||||
|
self.outbound_mode_propagation = False
|
||||||
|
self.outbound_mode_command = True
|
||||||
|
else:
|
||||||
|
if self.outbound_mode_propagation:
|
||||||
|
self.outbound_mode_paper = True
|
||||||
|
self.outbound_mode_propagation = False
|
||||||
|
self.outbound_mode_command = False
|
||||||
|
else:
|
||||||
|
self.outbound_mode_propagation = True
|
||||||
|
self.outbound_mode_paper = False
|
||||||
|
self.outbound_mode_command = False
|
||||||
|
|
||||||
self.update_message_widgets()
|
self.update_message_widgets()
|
||||||
|
|
||||||
|
@ -1138,13 +1168,17 @@ class SidebandApp(MDApp):
|
||||||
mode_item.icon = "qrcode"
|
mode_item.icon = "qrcode"
|
||||||
self.messages_view.ids.message_text.hint_text = "Paper message"
|
self.messages_view.ids.message_text.hint_text = "Paper message"
|
||||||
else:
|
else:
|
||||||
if not self.outbound_mode_propagation:
|
if self.outbound_mode_command:
|
||||||
mode_item.icon = "lan-connect"
|
mode_item.icon = "console"
|
||||||
self.messages_view.ids.message_text.hint_text = "Message for direct delivery"
|
self.messages_view.ids.message_text.hint_text = "Send command or request"
|
||||||
else:
|
else:
|
||||||
mode_item.icon = "upload-network"
|
if not self.outbound_mode_propagation:
|
||||||
self.messages_view.ids.message_text.hint_text = "Message for propagation"
|
mode_item.icon = "lan-connect"
|
||||||
# self.root.ids.message_text.hint_text = "Write message for delivery via propagation nodes"
|
self.messages_view.ids.message_text.hint_text = "Message for direct delivery"
|
||||||
|
else:
|
||||||
|
mode_item.icon = "upload-network"
|
||||||
|
self.messages_view.ids.message_text.hint_text = "Message for propagation"
|
||||||
|
# self.root.ids.message_text.hint_text = "Write message for delivery via propagation nodes"
|
||||||
|
|
||||||
def key_query_action(self, sender):
|
def key_query_action(self, sender):
|
||||||
context_dest = self.messages_view.ids.messages_scrollview.active_conversation
|
context_dest = self.messages_view.ids.messages_scrollview.active_conversation
|
||||||
|
|
|
@ -1976,7 +1976,7 @@ class SidebandCore():
|
||||||
messages = messages[-limit:]
|
messages = messages[-limit:]
|
||||||
return messages
|
return messages
|
||||||
|
|
||||||
def _db_save_lxm(self, lxm, context_dest, originator = False):
|
def _db_save_lxm(self, lxm, context_dest, originator = False, own_command = False):
|
||||||
state = lxm.state
|
state = lxm.state
|
||||||
|
|
||||||
packed_telemetry = None
|
packed_telemetry = None
|
||||||
|
@ -1998,7 +1998,7 @@ class SidebandCore():
|
||||||
# TODO: Implement
|
# TODO: Implement
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if len(lxm.content) != 0 or len(lxm.title) != 0:
|
if own_command or len(lxm.content) != 0 or len(lxm.title) != 0:
|
||||||
db = self.__db_connect()
|
db = self.__db_connect()
|
||||||
dbc = db.cursor()
|
dbc = db.cursor()
|
||||||
|
|
||||||
|
@ -2977,7 +2977,7 @@ class SidebandCore():
|
||||||
RNS.log("Error while creating paper message: "+str(e), RNS.LOG_ERROR)
|
RNS.log("Error while creating paper message: "+str(e), RNS.LOG_ERROR)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def send_message(self, content, destination_hash, propagation):
|
def send_message(self, content, destination_hash, propagation, skip_fields=False):
|
||||||
try:
|
try:
|
||||||
if content == "":
|
if content == "":
|
||||||
raise ValueError("Message content cannot be empty")
|
raise ValueError("Message content cannot be empty")
|
||||||
|
@ -2991,7 +2991,54 @@ class SidebandCore():
|
||||||
else:
|
else:
|
||||||
desired_method = LXMF.LXMessage.DIRECT
|
desired_method = LXMF.LXMessage.DIRECT
|
||||||
|
|
||||||
lxm = LXMF.LXMessage(dest, source, content, title="", desired_method=desired_method, fields = self.get_message_fields(destination_hash))
|
if skip_fields:
|
||||||
|
fields = {}
|
||||||
|
else:
|
||||||
|
fields = self.get_message_fields(destination_hash)
|
||||||
|
|
||||||
|
lxm = LXMF.LXMessage(dest, source, content, title="", desired_method=desired_method, fields = fields)
|
||||||
|
lxm.register_delivery_callback(self.message_notification)
|
||||||
|
lxm.register_failed_callback(self.message_notification)
|
||||||
|
|
||||||
|
if self.message_router.get_outbound_propagation_node() != None:
|
||||||
|
if self.config["lxmf_try_propagation_on_fail"]:
|
||||||
|
lxm.try_propagation_on_fail = True
|
||||||
|
|
||||||
|
self.message_router.handle_outbound(lxm)
|
||||||
|
self.lxm_ingest(lxm, originator=True)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Error while sending message: "+str(e), RNS.LOG_ERROR)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def send_command(self, content, destination_hash, propagation):
|
||||||
|
try:
|
||||||
|
if content == "":
|
||||||
|
return False
|
||||||
|
|
||||||
|
commands = []
|
||||||
|
if content.startswith("echo "):
|
||||||
|
echo_content = content.replace("echo ", "").encode("utf-8")
|
||||||
|
if len(echo_content) > 0:
|
||||||
|
commands.append({Commands.ECHO: echo_content})
|
||||||
|
elif content.startswith("sig"):
|
||||||
|
commands.append({Commands.SIGNAL_REPORT: True})
|
||||||
|
|
||||||
|
if len(commands) == 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
dest_identity = RNS.Identity.recall(destination_hash)
|
||||||
|
dest = RNS.Destination(dest_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "lxmf", "delivery")
|
||||||
|
source = self.lxmf_destination
|
||||||
|
|
||||||
|
if propagation:
|
||||||
|
desired_method = LXMF.LXMessage.PROPAGATED
|
||||||
|
else:
|
||||||
|
desired_method = LXMF.LXMessage.DIRECT
|
||||||
|
|
||||||
|
lxm = LXMF.LXMessage(dest, source, "", title="", desired_method=desired_method, fields = {LXMF.FIELD_COMMANDS: commands})
|
||||||
lxm.register_delivery_callback(self.message_notification)
|
lxm.register_delivery_callback(self.message_notification)
|
||||||
lxm.register_failed_callback(self.message_notification)
|
lxm.register_failed_callback(self.message_notification)
|
||||||
|
|
||||||
|
@ -3060,6 +3107,7 @@ class SidebandCore():
|
||||||
should_notify = False
|
should_notify = False
|
||||||
is_trusted = False
|
is_trusted = False
|
||||||
telemetry_only = False
|
telemetry_only = False
|
||||||
|
own_command = False
|
||||||
unread_reason_tx = False
|
unread_reason_tx = False
|
||||||
|
|
||||||
if originator:
|
if originator:
|
||||||
|
@ -3069,18 +3117,21 @@ class SidebandCore():
|
||||||
context_dest = message.source_hash
|
context_dest = message.source_hash
|
||||||
is_trusted = self.is_trusted(context_dest)
|
is_trusted = self.is_trusted(context_dest)
|
||||||
|
|
||||||
|
if originator and LXMF.FIELD_COMMANDS in message.fields:
|
||||||
|
own_command = True
|
||||||
|
|
||||||
if self._db_message(message.hash):
|
if self._db_message(message.hash):
|
||||||
RNS.log("Message exists, setting state to: "+str(message.state), RNS.LOG_DEBUG)
|
RNS.log("Message exists, setting state to: "+str(message.state), RNS.LOG_DEBUG)
|
||||||
self._db_message_set_state(message.hash, message.state)
|
self._db_message_set_state(message.hash, message.state)
|
||||||
else:
|
else:
|
||||||
RNS.log("Message does not exist, saving", RNS.LOG_DEBUG)
|
RNS.log("Message does not exist, saving", RNS.LOG_DEBUG)
|
||||||
self._db_save_lxm(message, context_dest, originator)
|
self._db_save_lxm(message, context_dest, originator, own_command=own_command)
|
||||||
|
|
||||||
if is_trusted:
|
if is_trusted:
|
||||||
should_notify = True
|
should_notify = True
|
||||||
|
|
||||||
if len(message.content) == 0 and len(message.title) == 0:
|
if len(message.content) == 0 and len(message.title) == 0:
|
||||||
if (LXMF.FIELD_TELEMETRY in message.fields or LXMF.FIELD_TELEMETRY_STREAM in message.fields):
|
if (LXMF.FIELD_TELEMETRY in message.fields or LXMF.FIELD_TELEMETRY_STREAM in message.fields or LXMF.FIELD_COMMANDS in message.fields):
|
||||||
RNS.log("Squelching notification due to telemetry-only message", RNS.LOG_DEBUG)
|
RNS.log("Squelching notification due to telemetry-only message", RNS.LOG_DEBUG)
|
||||||
telemetry_only = True
|
telemetry_only = True
|
||||||
|
|
||||||
|
@ -3236,16 +3287,57 @@ class SidebandCore():
|
||||||
RNS.log("LXMF delivery "+str(time_string)+". "+str(signature_string)+".", RNS.LOG_DEBUG)
|
RNS.log("LXMF delivery "+str(time_string)+". "+str(signature_string)+".", RNS.LOG_DEBUG)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
context_dest = message.source_hash
|
||||||
if self.config["lxmf_ignore_unknown"] == True:
|
if self.config["lxmf_ignore_unknown"] == True:
|
||||||
context_dest = message.source_hash
|
|
||||||
if self._db_conversation(context_dest) == None:
|
if self._db_conversation(context_dest) == None:
|
||||||
RNS.log("Dropping message from unknown sender "+RNS.prettyhexrep(context_dest), RNS.LOG_DEBUG)
|
RNS.log("Dropping message from unknown sender "+RNS.prettyhexrep(context_dest), RNS.LOG_DEBUG)
|
||||||
return
|
return
|
||||||
|
|
||||||
self.lxm_ingest(message)
|
if message.signature_validated and LXMF.FIELD_COMMANDS in message.fields:
|
||||||
|
if self.requests_allowed_from(context_dest):
|
||||||
|
commands = message.fields[LXMF.FIELD_COMMANDS]
|
||||||
|
self.handle_commands(commands, message)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.lxm_ingest(message)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
RNS.log("Error while ingesting LXMF message "+RNS.prettyhexrep(message.hash)+" to database: "+str(e))
|
RNS.log("Error while ingesting LXMF message "+RNS.prettyhexrep(message.hash)+" to database: "+str(e))
|
||||||
|
|
||||||
|
def handle_commands(self, commands, message):
|
||||||
|
try:
|
||||||
|
context_dest = message.source_hash
|
||||||
|
RNS.log("Handling commands from "+str(context_dest), RNS.LOG_DEBUG)
|
||||||
|
for command in commands:
|
||||||
|
if Commands.TELEMETRY_REQUEST in command:
|
||||||
|
timebase = int(command[Commands.TELEMETRY_REQUEST])
|
||||||
|
RNS.log("Handling telemetry request with timebase "+str(timebase), RNS.LOG_DEBUG)
|
||||||
|
|
||||||
|
elif Commands.ECHO in command:
|
||||||
|
msg_content = "Echo reply: "+command[Commands.ECHO].decode("utf-8")
|
||||||
|
RNS.log("Handling echo request", RNS.LOG_DEBUG)
|
||||||
|
self.send_message(msg_content, context_dest, False, skip_fields=True)
|
||||||
|
|
||||||
|
elif Commands.SIGNAL_REPORT in command:
|
||||||
|
RNS.log("Handling signal report", RNS.LOG_DEBUG)
|
||||||
|
phy_str = ""
|
||||||
|
if message.q != None:
|
||||||
|
phy_str += f"Link Quality: {message.q}%\n"
|
||||||
|
if message.rssi != None:
|
||||||
|
phy_str += f"RSSI: {message.rssi} dBm\n"
|
||||||
|
if message.snr != None:
|
||||||
|
phy_str += f"SNR: {message.rssi} dB\n"
|
||||||
|
if len(phy_str) != 0:
|
||||||
|
phy_str = phy_str[:-1]
|
||||||
|
else:
|
||||||
|
phy_str = "No reception info available"
|
||||||
|
|
||||||
|
self.send_message(phy_str, context_dest, False, skip_fields=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
RNS.log("Error while handling commands: "+str(e), RNS.LOG_ERROR)
|
||||||
|
|
||||||
|
|
||||||
def get_display_name_bytes(self):
|
def get_display_name_bytes(self):
|
||||||
return self.config["display_name"].encode("utf-8")
|
return self.config["display_name"].encode("utf-8")
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ from .geo import azalt, angle_to_horizon, radio_horizon, shared_radio_horizon
|
||||||
|
|
||||||
class Commands():
|
class Commands():
|
||||||
TELEMETRY_REQUEST = 0x01
|
TELEMETRY_REQUEST = 0x01
|
||||||
|
ECHO = 0x02
|
||||||
|
SIGNAL_REPORT = 0x03
|
||||||
|
|
||||||
class Telemeter():
|
class Telemeter():
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
|
@ -22,11 +22,11 @@ import subprocess
|
||||||
import shlex
|
import shlex
|
||||||
|
|
||||||
if RNS.vendor.platformutils.get_platform() == "android":
|
if RNS.vendor.platformutils.get_platform() == "android":
|
||||||
from sideband.sense import Telemeter
|
from sideband.sense import Telemeter, Commands
|
||||||
from ui.helpers import ts_format, file_ts_format, mdc
|
from ui.helpers import ts_format, file_ts_format, mdc
|
||||||
from ui.helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light
|
from ui.helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light
|
||||||
else:
|
else:
|
||||||
from sbapp.sideband.sense import Telemeter
|
from sbapp.sideband.sense import Telemeter, Commands
|
||||||
from .helpers import ts_format, file_ts_format, mdc
|
from .helpers import ts_format, file_ts_format, mdc
|
||||||
from .helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light
|
from .helpers import color_received, color_delivered, color_propagated, color_paper, color_failed, color_unknown, intensity_msgs_dark, intensity_msgs_light
|
||||||
|
|
||||||
|
@ -178,14 +178,29 @@ class Messages():
|
||||||
txstr = time.strftime(ts_format, time.localtime(m["sent"]))
|
txstr = time.strftime(ts_format, time.localtime(m["sent"]))
|
||||||
rxstr = time.strftime(ts_format, time.localtime(m["received"]))
|
rxstr = time.strftime(ts_format, time.localtime(m["received"]))
|
||||||
titlestr = ""
|
titlestr = ""
|
||||||
|
extra_content = ""
|
||||||
extra_telemetry = {}
|
extra_telemetry = {}
|
||||||
telemeter = None
|
telemeter = None
|
||||||
|
signature_valid = False
|
||||||
|
|
||||||
|
if "lxm" in m and m["lxm"] != None and m["lxm"].signature_validated:
|
||||||
|
signature_valid = True
|
||||||
|
|
||||||
if "extras" in m and m["extras"] != None and "packed_telemetry" in m["extras"]:
|
if "extras" in m and m["extras"] != None and "packed_telemetry" in m["extras"]:
|
||||||
try:
|
try:
|
||||||
telemeter = Telemeter.from_packed(m["extras"]["packed_telemetry"])
|
telemeter = Telemeter.from_packed(m["extras"]["packed_telemetry"])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if "lxm" in m and m["lxm"] != None and m["lxm"].fields != None and LXMF.FIELD_COMMANDS in m["lxm"].fields:
|
||||||
|
commands = m["lxm"].fields[LXMF.FIELD_COMMANDS]
|
||||||
|
for command in commands:
|
||||||
|
if Commands.ECHO in command:
|
||||||
|
extra_content = "[font=RobotoMono-Regular]> echo "+command[Commands.ECHO].decode("utf-8")+"[/font]\n"
|
||||||
|
if Commands.SIGNAL_REPORT in command:
|
||||||
|
extra_content = "[font=RobotoMono-Regular]> sig[/font]\n"
|
||||||
|
extra_content = extra_content[:-1]
|
||||||
|
|
||||||
if telemeter == None and "lxm" in m and m["lxm"] and m["lxm"].fields != None and LXMF.FIELD_TELEMETRY in m["lxm"].fields:
|
if telemeter == None and "lxm" in m and m["lxm"] and m["lxm"].fields != None and LXMF.FIELD_TELEMETRY in m["lxm"].fields:
|
||||||
try:
|
try:
|
||||||
packed_telemetry = m["lxm"].fields[LXMF.FIELD_TELEMETRY]
|
packed_telemetry = m["lxm"].fields[LXMF.FIELD_TELEMETRY]
|
||||||
|
@ -272,8 +287,12 @@ class Messages():
|
||||||
if rcvd_d_str != "":
|
if rcvd_d_str != "":
|
||||||
heading_str += rcvd_d_str
|
heading_str += rcvd_d_str
|
||||||
|
|
||||||
|
pre_content = ""
|
||||||
|
if not signature_valid:
|
||||||
|
pre_content += "[b]Warning![/b] The signature for this message could not be validated. Check that you have received an announce from this sender. If you already have, or other messages from the sender do not display this warning, [b]this message is likely to be fake[/b].\n\n"
|
||||||
|
|
||||||
item = ListLXMessageCard(
|
item = ListLXMessageCard(
|
||||||
text=m["content"].decode("utf-8"),
|
text=pre_content+m["content"].decode("utf-8")+extra_content,
|
||||||
heading=heading_str,
|
heading=heading_str,
|
||||||
md_bg_color=msg_color,
|
md_bg_color=msg_color,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue