Implemented paper message handling

This commit is contained in:
Mark Qvist 2022-11-19 20:04:01 +01:00
parent 08a9225cc9
commit 730c17c981
4 changed files with 207 additions and 6 deletions

View File

@ -227,6 +227,35 @@ class Conversation:
RNS.log("Destination is not known, cannot create LXMF Message.", RNS.LOG_VERBOSE)
return False
def paper_output(self, content="", title=""):
if self.send_destination:
try:
dest = self.send_destination
source = self.app.lxmf_destination
desired_method = LXMF.LXMessage.PAPER
lxm = LXMF.LXMessage(dest, source, content, title=title, desired_method=desired_method)
qr_code = lxm.as_qr()
qr_tmp_path = self.app.tmpfilespath+"/"+str(RNS.hexrep(lxm.hash, delimit=False))
qr_code.save(qr_tmp_path)
print_result = self.app.print_file(qr_tmp_path)
os.unlink(qr_tmp_path)
if print_result:
message_path = Conversation.ingest(lxm, self.app, originator=True)
self.messages.append(ConversationMessage(message_path))
return print_result
except Exception as e:
RNS.log("An error occurred while generating paper message, the contained exception was: "+str(e), RNS.LOG_ERROR)
return False
else:
RNS.log("Destination is not known, cannot create LXMF Message.", RNS.LOG_VERBOSE)
return False
def message_notification(self, message):
if message.state == LXMF.LXMessage.FAILED and hasattr(message, "try_propagation_on_fail") and message.try_propagation_on_fail:
RNS.log("Direct delivery of "+str(message)+" failed. Retrying as propagated message.", RNS.LOG_VERBOSE)

View File

@ -105,6 +105,7 @@ class NomadNetworkApp:
self.conversationpath = self.configdir+"/storage/conversations"
self.directorypath = self.configdir+"/storage/directory"
self.peersettingspath = self.configdir+"/storage/peersettings"
self.tmpfilespath = self.configdir+"/storage/tmp"
self.pagespath = self.configdir+"/storage/pages"
self.filespath = self.configdir+"/storage/files"
@ -145,6 +146,11 @@ class NomadNetworkApp:
if not os.path.isdir(self.cachepath):
os.makedirs(self.cachepath)
if not os.path.isdir(self.tmpfilespath):
os.makedirs(self.tmpfilespath)
else:
self.clear_tmp_dir()
if os.path.isfile(self.configpath):
try:
self.config = ConfigObj(self.configpath)
@ -514,6 +520,26 @@ class NomadNetworkApp:
return False
def print_file(self, filename):
print_command = self.print_command+" "+filename
try:
return_code = subprocess.call(shlex.split(print_command), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception as e:
RNS.log("An error occurred while executing print command: "+str(print_command), RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
return False
if return_code == 0:
RNS.log("Successfully printed "+str(filename)+" using print command: "+print_command, RNS.LOG_DEBUG)
return True
else:
RNS.log("Printing "+str(filename)+" failed using print command: "+print_command, RNS.LOG_DEBUG)
return False
def print_message(self, message, received = None):
try:
template = self.printing_template_msg
@ -547,8 +573,7 @@ class NomadNetworkApp:
f.write(output.encode("utf-8"))
f.close()
print_command = "lp -d thermal -o cpi=16 -o lpi=8 "+filename
return_code = subprocess.call(shlex.split(print_command), stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.print_file(filename)
os.unlink(filename)
@ -576,6 +601,12 @@ class NomadNetworkApp:
if os.path.isfile(self.conversationpath + "/" + source_hash + "/unread"):
os.unlink(self.conversationpath + "/" + source_hash + "/unread")
def clear_tmp_dir(self):
if os.path.isdir(self.tmpfilespath):
for file in os.listdir(self.tmpfilespath):
fpath = self.tmpfilespath+"/"+file
os.unlink(fpath)
def createDefaultConfig(self):
self.config = ConfigObj(__default_nomadnet_config__)
self.config.filename = self.configpath

View File

@ -121,7 +121,9 @@ GLYPHS = {
("decoration_menu", " +", " +", " \uf93a"),
("unread_menu", " !", " \u2709", urm_char),
("globe", "", "", "\uf484"),
("sent", "/\\", "\u2191", "\ufbf4")
("sent", "/\\", "\u2191", "\ufbf4"),
("papermsg", "P", "\u25a4", "\uf719"),
("qrcode", "QR", "\u25a4", "\uf029"),
}
class TextUI:

View File

@ -14,13 +14,13 @@ class ConversationListDisplayShortcuts():
def __init__(self, app):
self.app = app
self.widget = urwid.AttrMap(urwid.Text("[C-e] Peer Info [C-x] Delete [C-r] Sync [C-n] New [C-g] Fullscreen"), "shortcutbar")
self.widget = urwid.AttrMap(urwid.Text("[C-e] Peer Info [C-x] Delete [C-r] Sync [C-n] New [C-u] Ingest URL [C-g] Fullscreen"), "shortcutbar")
class ConversationDisplayShortcuts():
def __init__(self, app):
self.app = app
self.widget = urwid.AttrMap(urwid.Text("[C-d] Send [C-k] Clear [C-w] Close [C-t] Title [C-p] Purge [C-x] Clear History [C-o] Sort"), "shortcutbar")
self.widget = urwid.AttrMap(urwid.Text("[C-d] Send [C-p] Paper Msg [C-t] Title [C-k] Clear [C-w] Close [C-u] Purge [C-x] Clear History [C-o] Sort"), "shortcutbar")
class ConversationsArea(urwid.LineBox):
def keypress(self, size, key):
@ -30,6 +30,8 @@ class ConversationsArea(urwid.LineBox):
self.delegate.delete_selected_conversation()
elif key == "ctrl n":
self.delegate.new_conversation()
elif key == "ctrl u":
self.delegate.ingest_lxm_url()
elif key == "ctrl r":
self.delegate.sync_conversations()
elif key == "ctrl g":
@ -330,6 +332,110 @@ class ConversationsDisplay():
options = self.columns_widget.options("given", ConversationsDisplay.given_list_width)
self.columns_widget.contents[0] = (overlay, options)
def ingest_lxm_url(self):
self.dialog_open = True
lxm_url = ""
e_url = urwid.Edit(caption="URL : ",edit_text=lxm_url)
def dismiss_dialog(sender):
self.update_conversation_list()
self.dialog_open = False
def confirmed(sender):
try:
local_delivery_signal = "local_delivery_occurred"
duplicate_signal = "duplicate_lxm"
lxm_url = e_url.get_edit_text()
ingest_result = self.app.message_router.ingest_lxm_url(
lxm_url,
signal_local_delivery=local_delivery_signal,
signal_duplicate=duplicate_signal
)
if ingest_result == False:
raise ValueError("The URL contained no decodable messages")
elif ingest_result == local_delivery_signal:
rdialog_pile = urwid.Pile([
urwid.Text("Message was decoded, decrypted successfully, and added to your conversation list."),
urwid.Text(""),
urwid.Columns([("weight", 0.6, urwid.Text("")), ("weight", 0.4, urwid.Button("OK", on_press=dismiss_dialog))])
])
rdialog_pile.error_display = False
rdialog = DialogLineBox(rdialog_pile, title="Ingest message URL")
rdialog.delegate = self
bottom = self.listbox
roverlay = urwid.Overlay(rdialog, bottom, align="center", width=("relative", 100), valign="middle", height="pack", left=2, right=2)
options = self.columns_widget.options("given", ConversationsDisplay.given_list_width)
self.columns_widget.contents[0] = (roverlay, options)
elif ingest_result == duplicate_signal:
rdialog_pile = urwid.Pile([
urwid.Text("The decoded message has already been processed by the LXMF Router, and will not be ingested again."),
urwid.Text(""),
urwid.Columns([("weight", 0.6, urwid.Text("")), ("weight", 0.4, urwid.Button("OK", on_press=dismiss_dialog))])
])
rdialog_pile.error_display = False
rdialog = DialogLineBox(rdialog_pile, title="Ingest message URL")
rdialog.delegate = self
bottom = self.listbox
roverlay = urwid.Overlay(rdialog, bottom, align="center", width=("relative", 100), valign="middle", height="pack", left=2, right=2)
options = self.columns_widget.options("given", ConversationsDisplay.given_list_width)
self.columns_widget.contents[0] = (roverlay, options)
else:
if self.app.enable_node:
propagation_text = "The decoded message was not addressed to this LXMF address, but has been added to the propagation node queues, and will be distributed on the propagation network."
else:
propagation_text = "The decoded message was not addressed to this LXMF address, and has been discarded."
rdialog_pile = urwid.Pile([
urwid.Text(propagation_text),
urwid.Text(""),
urwid.Columns([("weight", 0.6, urwid.Text("")), ("weight", 0.4, urwid.Button("OK", on_press=dismiss_dialog))])
])
rdialog_pile.error_display = False
rdialog = DialogLineBox(rdialog_pile, title="Ingest message URL")
rdialog.delegate = self
bottom = self.listbox
roverlay = urwid.Overlay(rdialog, bottom, align="center", width=("relative", 100), valign="middle", height="pack", left=2, right=2)
options = self.columns_widget.options("given", ConversationsDisplay.given_list_width)
self.columns_widget.contents[0] = (roverlay, options)
except Exception as e:
RNS.log("Could not ingest LXM URL. The contained exception was: "+str(e), RNS.LOG_VERBOSE)
if not dialog_pile.error_display:
dialog_pile.error_display = True
options = dialog_pile.options(height_type="pack")
dialog_pile.contents.append((urwid.Text(""), options))
dialog_pile.contents.append((urwid.Text(("error_text", "Could ingest LXM from URL data. Check your input."), align="center"), options))
dialog_pile = urwid.Pile([
e_url,
urwid.Text(""),
urwid.Columns([("weight", 0.45, urwid.Button("Ingest", on_press=confirmed)), ("weight", 0.1, urwid.Text("")), ("weight", 0.45, urwid.Button("Back", on_press=dismiss_dialog))])
])
dialog_pile.error_display = False
dialog = DialogLineBox(dialog_pile, title="Ingest message URL")
dialog.delegate = self
bottom = self.listbox
overlay = urwid.Overlay(dialog, bottom, align="center", width=("relative", 100), valign="middle", height="pack", left=2, right=2)
options = self.columns_widget.options("given", ConversationsDisplay.given_list_width)
self.columns_widget.contents[0] = (overlay, options)
def delete_conversation(self, source_hash):
if source_hash in ConversationsDisplay.cached_conversation_widgets:
conversation = ConversationsDisplay.cached_conversation_widgets[source_hash]
@ -636,6 +742,8 @@ class MessageEdit(urwid.Edit):
def keypress(self, size, key):
if key == "ctrl d":
self.delegate.send_message()
elif key == "ctrl p":
self.delegate.paper_message()
elif key == "ctrl k":
self.delegate.clear_editor()
elif key == "up":
@ -800,7 +908,7 @@ class ConversationWidget(urwid.WidgetWrap):
self.toggle_focus_area()
elif key == "ctrl w":
self.close()
elif key == "ctrl p":
elif key == "ctrl u":
self.conversation.purge_failed()
self.conversation_changed(None)
elif key == "ctrl t":
@ -860,6 +968,34 @@ class ConversationWidget(urwid.WidgetWrap):
else:
pass
def paper_message(self):
content = self.content_editor.get_edit_text()
title = self.title_editor.get_edit_text()
if not content == "":
if self.conversation.paper_output(content, title):
self.clear_editor()
else:
self.paper_message_failed()
def paper_message_failed(self):
def dismiss_dialog(sender):
self.dialog_open = False
self.conversation_changed(None)
dialog = DialogLineBox(
urwid.Pile([
urwid.Text("Could not output paper message,\ncheck your settings. See the log\nfile for any error messages.\n", align="center"),
urwid.Columns([("weight", 0.6, urwid.Text("")), ("weight", 0.4, urwid.Button("OK", on_press=dismiss_dialog))])
]), title="!"
)
dialog.delegate = self
bottom = self.messagelist
overlay = urwid.Overlay(dialog, bottom, align="center", width=34, valign="middle", height="pack", left=2, right=2)
self.frame.contents["body"] = (overlay, self.frame.options())
self.frame.set_focus("body")
def close(self):
self.delegate.close_conversation(self)
@ -890,6 +1026,9 @@ class LXMessageWidget(urwid.WidgetWrap):
elif message.lxm.method == LXMF.LXMessage.PROPAGATED and message.lxm.state == LXMF.LXMessage.SENT:
header_style = "msg_header_propagated"
title_string = g["sent"]+" "+title_string
elif message.lxm.method == LXMF.LXMessage.PAPER and message.lxm.state == LXMF.LXMessage.PAPER:
header_style = "msg_header_propagated"
title_string = g["papermsg"]+" "+title_string
elif message.lxm.state == LXMF.LXMessage.SENT:
header_style = "msg_header_sent"
title_string = g["sent"]+" "+title_string