From ec983c4613ad558b55f405496b11c2e14f231809 Mon Sep 17 00:00:00 2001 From: Michael Woods Date: Mon, 17 Mar 2025 23:48:29 -0400 Subject: [PATCH] cli client can now send messages. --- examples/misc/edit-storage-no-zeo.py | 3 +- src/packetserver/client/cli/__init__.py | 2 + src/packetserver/client/cli/message.py | 87 +++++++++++++++++++++++++ src/packetserver/client/messages.py | 5 +- src/packetserver/client/users.py | 2 +- src/packetserver/server/messages.py | 11 ++-- 6 files changed, 102 insertions(+), 8 deletions(-) diff --git a/examples/misc/edit-storage-no-zeo.py b/examples/misc/edit-storage-no-zeo.py index 8d1f5ce..05daef4 100644 --- a/examples/misc/edit-storage-no-zeo.py +++ b/examples/misc/edit-storage-no-zeo.py @@ -14,7 +14,8 @@ def all_done(): storage.close() #port = int(sys.argv[1]) -storage = ZODB.FileStorage.FileStorage('/home/alienhunter/.packetserver/data.zopedb') +storage = ZODB.FileStorage.FileStorage('/tmp/tmp_ps_data/data.zopedb') +#storage = ZODB.FileStorage.FileStorage('/home/alienhunter/.packetserver/data.zopedb') #db = ZEO.DB(('127.0.0.1',port)) db = ZODB.DB(storage) c = db.open() diff --git a/src/packetserver/client/cli/__init__.py b/src/packetserver/client/cli/__init__.py index f8e3778..082fb90 100644 --- a/src/packetserver/client/cli/__init__.py +++ b/src/packetserver/client/cli/__init__.py @@ -7,6 +7,7 @@ from packetserver.common import Request, Response from packetserver.client.cli.util import format_list_dicts, exit_client from packetserver.client.cli.job import job from packetserver.client.cli.object import objects +from packetserver.client.cli.message import message import ZODB import ZODB.FileStorage import ax25 @@ -184,6 +185,7 @@ cli.add_command(query_server) cli.add_command(job, name='job') cli.add_command(objects, name='object') cli.add_command(set_user, name='set') +cli.add_command(message) if __name__ == '__main__': cli() diff --git a/src/packetserver/client/cli/message.py b/src/packetserver/client/cli/message.py index e69de29..d1cca98 100644 --- a/src/packetserver/client/cli/message.py +++ b/src/packetserver/client/cli/message.py @@ -0,0 +1,87 @@ +import os +import sys +import os.path +from email.policy import default + +import click +from packetserver.client.cli.util import exit_client, format_list_dicts +from copy import deepcopy +from uuid import UUID +from packetserver.client.messages import * + +@click.group() +@click.pass_context +def message(ctx): + """Send, search, and filter messages to and from other users on the BBS system.""" + pass + +@click.command() +@click.argument("recipients", type=str) +@click.argument("body", type=str) +@click.option("--body-filename", '-f', is_flag=True, default=False, help="Treat body argument as a filename to read body text from. '-' to read from stdin.") +@click.option("--attachment", "-A", multiple=True, default=[], + help="Files to attach to message in form '[:]' use 't' for text (default), 'b' to interpret file as binary data.") +@click.pass_context +def send(ctx, recipients, body, body_filename, attachment): + """Send a message to one or more recipients. + + should be a comma-separated list of recipients to send the message to + + should be either body text, or a filename (or '-' for stdin) to read body text from + """ + client = ctx.obj['client'] + bbs = ctx.obj['bbs'] + + recips = [x.strip() for x in recipients.split(",") if x.strip() != ""] + + if len(recips) == 0: + click.echo("You must specify at least one recipient.", err=True) + exit_client(ctx.obj, 89) + + attachments = [] + for a in attachment: + is_text = True + filename = a + if len(a) > 1: + if a[1] == ":": + filename = a[2:] + if a[0].lower() == "b": + is_text = False + try: + attachments.append(attachment_from_file(filename, binary=not is_text)) + except Exception as e: + click.echo(str(e), err=True) + exit_client(ctx.obj, 89) + + if len(attachments) == 0: + attachments = None + + if body_filename: + if body == "-": + body_text = sys.stdin.read() + else: + if not os.path.isfile(body): + click.echo(f"{body} is not a file that can be read for body text.", err=True) + exit_client(ctx.obj, 92) + sys.exit(92) + try: + body_text = open(body, "r").read() + except: + click.echo(f"{body} is not a file that can be read for body text.", err=True) + exit_client(ctx.obj, 92) + sys.exit(92) + else: + body_text = body + + try: + resp = send_message(client, bbs, body_text, recips, attachments=attachments) + click.echo(f"Message received by server: {resp}") + exit_client(ctx.obj, 0) + except Exception as e: + click.echo(f"Error sending message: {str(e)}", err=True) + exit_client(ctx.obj, 53) + +message.add_command(send) + + + diff --git a/src/packetserver/client/messages.py b/src/packetserver/client/messages.py index b78e202..7135874 100644 --- a/src/packetserver/client/messages.py +++ b/src/packetserver/client/messages.py @@ -100,8 +100,9 @@ def send_message(client: Client, bbs_callsign: str, text: str, to: list[str], "to": to, "attachments": [] } - for a in attachments: - payload["attachments"].append(a.to_dict()) + if attachments is not None: + for a in attachments: + payload["attachments"].append(a.to_dict()) req = Request.blank() req.path = "message" diff --git a/src/packetserver/client/users.py b/src/packetserver/client/users.py index 7869c6c..f479559 100644 --- a/src/packetserver/client/users.py +++ b/src/packetserver/client/users.py @@ -118,5 +118,5 @@ def update_self(client: Client, bbs_callsign: str, email: str = None, bio: str = req.payload = payload response = client.send_receive_callsign(req, bbs_callsign) if response.status_code != 200: - raise RuntimeError(f"GET user {username} failed: {response.status_code}: {response.payload}") + raise RuntimeError(f"Updating profile failed: {response.status_code}: {response.payload}") return True \ No newline at end of file diff --git a/src/packetserver/server/messages.py b/src/packetserver/server/messages.py index ae33b68..7da96e1 100644 --- a/src/packetserver/server/messages.py +++ b/src/packetserver/server/messages.py @@ -234,6 +234,7 @@ class Message(persistent.Persistent): send_counter = send_counter + 1 for recipient in recipients: msg = Message(self.text, recipient, self.msg_from, attachments=[x.copy() for x in new_attachments]) + msg.msg_id = self.msg_id try: mailbox_create(recipient, db.root()) msg.msg_delivered = True @@ -245,9 +246,11 @@ class Message(persistent.Persistent): except: logging.error(f"Error sending message to {recipient}:\n{format_exc()}") failed.append(recipient) - self.msg_delivered = True - self.attachments = [x.copy() for x in new_attachments] - db.root.messages[self.msg_from.upper().strip()].append(msg) + self.msg_delivered = True + msg = Message(self.text, recipient, self.msg_from, attachments=[x.copy() for x in new_attachments]) + msg.msg_id = self.msg_id + msg.msg_to = self.msg_to + db.root.messages[self.msg_from.upper().strip()].append(msg) return send_counter, failed, self.msg_id DisplayOptions = namedtuple('DisplayOptions', ['get_text', 'limit', 'sort_by', 'reverse', 'search', @@ -451,7 +454,7 @@ def handle_message_post(req: Request, conn: PacketServerConnection, db: ZODB.DB) send_blank_response(conn, req, status_code=201, payload={ "successes": send_counter, "failed": failed, - 'msg_id': msg_id}) + 'msg_id': str(msg_id)}) def message_root_handler(req: Request, conn: PacketServerConnection, db: ZODB.DB): logging.debug(f"{req} being processed by message_root_handler")