From 84281e906f104a14173ff49726d3b55888aa5fc2 Mon Sep 17 00:00:00 2001 From: sp9wpn Date: Sat, 21 Sep 2024 00:17:30 +0200 Subject: [PATCH] Some fixes and changes, hopefully non-breaking. --- mopp.py | 71 +++++++++++++++++++++++++++---------- udp_chat_server.py | 5 ++- udp_client_console.py | 81 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 22 deletions(-) create mode 100755 udp_client_console.py diff --git a/mopp.py b/mopp.py index 744ba15..5a3fbe1 100644 --- a/mopp.py +++ b/mopp.py @@ -5,6 +5,20 @@ class Mopp: serial = 1 + morse = { + "0" : "-----", "1" : ".----", "2" : "..---", "3" : "...--", "4" : "....-", "5" : ".....", + "6" : "-....", "7" : "--...", "8" : "---..", "9" : "----.", + "a" : ".-", "b" : "-...", "c" : "-.-.", "d" : "-..", "e" : ".", "f" : "..-.", "g" : "--.", + "h" : "....", "i" : "..", "j" : ".---", "k" : "-.-", "l" : ".-..", "m" : "--", "n" : "-.", + "o" : "---", "p" : ".--.", "q" : "--.-", "r" : ".-.", "s" : "...", "t" : "-", "u" : "..-", + "v" : "...-", "w" : ".--", "x" : "-..-", "y" : "-.--", "z" : "--..", "=" : "-...-", + "/" : "-..-.", "+" : ".-.-.", "-" : "-....-", "." : ".-.-.-", "," : "--..--", "?" : "..--..", + ":" : "---...", "!" : "-.-.--", "'" : ".----." + } + + morse_inv = {v: k for k, v in morse.items()} + + def __init__(self, speed = 20): self.speed = speed return @@ -17,29 +31,23 @@ def _str2bin(self, bytes): bincode = "".join("{:08b}".format(c) for c in bytes) return bincode - def mopp(self, speed, msg): - logging.debug("Encoding message with "+str(speed)+" wpm :"+str(msg)) - - morse = { - "0" : "-----", "1" : ".----", "2" : "..---", "3" : "...--", "4" : "....-", "5" : ".....", - "6" : "-....", "7" : "--...", "8" : "---..", "9" : "----.", - "a" : ".-", "b" : "-...", "c" : "-.-.", "d" : "-..", "e" : ".", "f" : "..-.", "g" : "--.", - "h" : "....", "i" : "..", "j" : ".---", "k" : "-.-", "l" : ".-..", "m" : "--", "n" : "-.", - "o" : "---", "p" : ".--.", "q" : "--.-", "r" : ".-.", "s" : "...", "t" : "-", "u" : "..-", - "v" : "...-", "w" : ".--", "x" : "-..-", "y" : "-.--", "z" : "--..", "=" : "-...-", - "/" : "-..-.", "+" : ".-.-.", "-" : "-....-", "." : ".-.-.-", "," : "--..--", "?" : "..--..", - ":" : "---...", "!" : "-.-.--", "'" : ".----." - } + def mopp(self, speed, msg, for_transmission = True): m = '01' # protocol version m += bin(self.serial)[2:].zfill(6) m += bin(speed)[2:].zfill(6) + _txt = '' + for c in msg: if c == " ": continue # spaces not supported by morserino! - for b in morse[c.lower()]: + if c.lower() not in self.morse: + continue # unknown character + + _txt += c.lower() + for b in self.morse[c.lower()]: if b == '.': m += '01' else: @@ -47,6 +55,10 @@ def mopp(self, speed, msg): m += '00' # EOC + if len(m) <= 14: # empty message + return bytes('','latin_1') + + m = m[0:-2] + '11' # final EOW m = m.ljust(int(8*ceil(len(m)/8.0)),'0') @@ -57,7 +69,12 @@ def mopp(self, speed, msg): #print (m[i:i+8], bytes(chr(int(m[i:i+8],2)),"latin_1"), i, " ENCODER") res += chr(int(m[i:i+8],2)) - self.serial += 1 + if for_transmission: + logging.debug("Encoding message with "+str(speed)+" wpm: "+str(_txt)) + self.serial += 1 + if self.serial >= 64: + self.serial = 0 + return bytes(res,'latin_1') # WATCH OUT: UNICODE MAKES MULTI-BYTES def _stripheader(self, msg): @@ -65,7 +82,7 @@ def _stripheader(self, msg): return res def msg_strcmp (self, data_bytes, speed, msg): - if self._stripheader(data_bytes) == self._stripheader(self.mopp(speed, msg)): + if self._stripheader(data_bytes) == self._stripheader(self.mopp(speed, msg, False)): return True else: return False @@ -104,7 +121,9 @@ def decode_message (self, data_bytes): s = n[i:i+2] msg += self._mopp2morse(s) - return {"Protocol": protocol, "Serial": serial, "Speed": speed, "Message": msg} + txt = self._morse2txt(msg) + + return {"Protocol": protocol, "Serial": serial, "Speed": speed, "Message": msg, "Text": txt} def _mopp2morse(self, sym): @@ -121,5 +140,19 @@ def _mopp2morse(self, sym): logging.debug ("This should not happen: symbol ", s) return s - def _morse2txt(self, morse): - return \ No newline at end of file + def _morse2txt(self, ditcode): + s = "" + for word in ditcode.split("EOW"): + if word == '': + continue + for letter in word.split("EOC"): + if letter == '': + continue + if letter in self.morse_inv: + s += self.morse_inv[letter] + else: + s += "<" + letter + ">" + + s += " " + + return s.strip() diff --git a/udp_chat_server.py b/udp_chat_server.py index 3004ebf..176b3ed 100644 --- a/udp_chat_server.py +++ b/udp_chat_server.py @@ -82,12 +82,11 @@ def reject(client, speed): pass # clean clients list - for c in receivers.items(): - # FIXME: RuntimeError: dictionary changed size during iteration + for c in list(receivers.items()): if c[1] + config.CLIENT_TIMEOUT < time.time(): ip,port = c[0].split(':') bye_msg = ':bye' transmit(mopp.mopp(config.CHAT_WPM, bye_msg), ip, int(port)) del receivers[c[0]] logging.debug ("Removing expired client %s" % c[0]) - \ No newline at end of file + diff --git a/udp_client_console.py b/udp_client_console.py new file mode 100755 index 0000000..076389c --- /dev/null +++ b/udp_client_console.py @@ -0,0 +1,81 @@ +#!/usr/local/bin/python3 +# The MOPP Chat Client (UDP) + +import socket +import time +import logging +from mopp import * +import config +import argparse +import sys +import select + +logging.basicConfig(level=logging.DEBUG, format='%(message)s', ) + +argparser = argparse.ArgumentParser(description='MOPP - IP/UDP console client') +argparser.add_argument('ip', help='Server IP address') +argparser.add_argument('port', help='Server UDP port (default: 7373)', nargs='?', type=int, default=7373) + +args=argparser.parse_args() + +sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) +sock.settimeout(0.2) + +speed = 20 + +mopp = Mopp() + +def transmit (data): + if len(data) > 0: + sock.sendto(data, (args.ip, args.port)) + +print("### MOPP - IP/UDP console client") +print("### Speed is set to %d wpm. To change, type: #" % speed) +print("") + +# Login with hi +transmit(mopp.mopp(speed, 'hi')) + + +while KeyboardInterrupt: + try: + data_bytes, addr = sock.recvfrom(64) + try: + if len(data_bytes) > 0: + r = mopp.decode_message(data_bytes) + print ("Received (%d wpm): %s" % (mopp.received_speed(data_bytes), r['Text'])) + except: + raise + pass + + except (KeyboardInterrupt, SystemExit): + sock.close() + break + pass + + except socket.timeout: + # time.sleep(0.2) # anti flood + pass + + _i, _o, _e = select.select([sys.stdin], [], [], 1) + if (_i): + input = sys.stdin.readline().strip() + + if input[0:1] == '#': + try: + _speed = int(input[1:]) + if (_speed >= 5 and _speed <= 60): + speed = _speed + print("Speed set to %d wpm." % speed) + else: + print("Allowed speeds from 5 to 60 wpm.") + + except: + pass + + continue + + for word in input.split(' '): + if word != '': + # print("Transmitting (%d wpm): %s" % (speed,word)) + transmit(mopp.mopp(speed, word))