Allow referring to peers by nick

This commit is contained in:
Juhani Krekelä 2019-07-15 20:40:21 +03:00
parent 76704d4a11
commit a140fde1c1
1 changed files with 88 additions and 39 deletions

View File

@ -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('--- / <message>; /msg <target> <message>; /status <target>; /available; /unavailable; /nick <nick>; /target <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('--- / <message>; /msg <MAC> <message>; /status <MAC>; /available; /unavailable; /nick <nick>; /target <MAC>; /quit')
except TooManyMatchesError as err:
print('--- name %s matches several peers' % err.args[0])
else:
# Send message