From a140fde1c15acd620630ada232760e87f675c7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Mon, 15 Jul 2019 20:40:21 +0300 Subject: [PATCH] Allow referring to peers by nick --- ethermess.py | 127 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 39 deletions(-) diff --git a/ethermess.py b/ethermess.py index 73d8362..cf0fcff 100644 --- a/ethermess.py +++ b/ethermess.py @@ -54,12 +54,14 @@ def writeall(f, b): while written < len(b): written += f.write(b[written:]) +class ReadallError(Exception): pass + def readall(f, length): read = bytearray() while len(read) < length: data = f.read(length - len(read)) if data == b'': - raise ConnectionError('Could not satisfy read of %i bytes' % length) + raise ReadallError('Could not satisfy read of %i bytes' % length) read.extend(data) return bytes(read) @@ -67,18 +69,47 @@ def readall_u16(f): u16_bytes = readall(f, 2) return (u16_bytes[0] << 8) | u16_bytes[1] +class MACParseError(Exception): pass + def parse_mac(text): parts = text.split(':') if len(parts) != 6: - raise ValueError('Invalid MAC format: %s' % text) + raise MACParseError('Invalid MAC format: %s' % text) try: parsed = bytes(int(field, 16) for field in parts) except ValueError: - raise ValueError('Invalid MAC format %s' % text) + raise MACParseError('Invalid MAC format %s' % text) return parsed +class NoMatchesError(Exception): pass +class TooManyMatchesError(Exception): pass + +def mac_from_name(text): + global peers + + # Try to parse as a MAC address + try: + mac = parse_mac(text) + return mac + except MACParseError as err: + pass + + # It was not, try to find a matching nick + hits = 0 + for peer_mac, peer in peers.items(): + if text == peer.nick or text == '~' + peer.nick: + hits += 1 + mac = peer_mac + + if hits == 0: + raise NoMatchesError(text) + elif hits > 1: + raise TooManyMatchesError(text) + + return mac + def format_mac(mac): return ':'.join(mac[i:i+1].hex() for i in range(len(mac))) @@ -129,45 +160,63 @@ def handle_user_command(backend, line): if len(line) > 0 and line[0] == '/': command, _, rest = line.partition(' ') - if command == '/': - # Send quoted message - if default_target_mac is None: - print('--- Default target not set, set with /target') + + try: + if command == '/': + # Send quoted message + # TODO: Validate message + if default_target_mac is None: + print('--- Default target not set, set with /target') + else: + queue_message(backend, default_target_mac, rest) + + elif command == '/msg': + # Send message to target + target, _, message = rest.partition(' ') + mac = mac_from_name(target) + queue_message(backend, mac, message) + + elif command == '/status': + # Request status + mac = mac_from_name(rest) + if mac in peers: + print('=== ~%s (%s) [%s]' % (peers[mac].nick, peers[mac].status.name, format_mac(mac))) + else: + send_status_request(backend, mac) + + elif command == '/available' and rest == '': + # Set status to available + own_status = statuses.available + set_status_nick(backend, own_status, own_nick) + + elif command == '/unavailable' and rest == '': + # Set status to unavailable + own_status = statuses.unavailable + set_status_nick(backend, own_status, own_nick) + + elif command == '/nick': + # Change nick + # TODO: Validate nick + own_nick = rest + set_status_nick(backend, own_status, own_nick) + + elif command == '/target': + # Set default target of messages + default_target_mac = mac_from_name(rest) + + elif command == '/quit': + # Quit + return 'quit' + else: - queue_message(backend, default_target_mac, rest) + # Display usage + print('--- / ; /msg ; /status ; /available; /unavailable; /nick ; /target ; /quit') - elif command == '/msg': - # Send message to target - mac_str, _, message = rest.partition(' ') - mac = parse_mac(mac_str) - queue_message(backend, mac, message) + except NoMatchesError as err: + print('--- name %s matches no peers' % err.args[0]) - elif command == '/status': - # Request status - mac = parse_mac(rest) - send_status_request(backend, mac) - - elif command == '/available' and rest == '': - own_status = statuses.available - set_status_nick(backend, own_status, own_nick) - - elif command == '/unavailable' and rest == '': - own_status = statuses.unavailable - set_status_nick(backend, own_status, own_nick) - - elif command == '/nick': - own_nick = rest - set_status_nick(backend, own_status, own_nick) - - elif command == '/target': - default_target_mac = parse_mac(rest) - - elif command == '/quit': - return 'quit' - - else: - # Display usage - print('--- / ; /msg ; /status ; /available; /unavailable; /nick ; /target ; /quit') + except TooManyMatchesError as err: + print('--- name %s matches several peers' % err.args[0]) else: # Send message