Refactoring messages
This commit is contained in:
parent
073f34af26
commit
bd26db6cca
25
IRCServer.py
25
IRCServer.py
@ -122,18 +122,43 @@ class IRCServer(server.Server):
|
|||||||
if msg.channel in self.channels:
|
if msg.channel in self.channels:
|
||||||
self.channels[msg.channel].treat(msg.cmd, msg)
|
self.channels[msg.channel].treat(msg.cmd, msg)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_receivers(self, receivers, sender=None):
|
||||||
|
"""Return a filtered list of authorized channels and users"""
|
||||||
|
if self.allow_all:
|
||||||
|
return receivers
|
||||||
|
|
||||||
|
filtered = list()
|
||||||
|
for chan in receivers:
|
||||||
|
if (
|
||||||
|
# Is the channel authorized?
|
||||||
|
(chan in self.channels and
|
||||||
|
# Is the sender on the channel?
|
||||||
|
(
|
||||||
|
sender is None or
|
||||||
|
sender in self.channels[chan].people
|
||||||
|
)) or
|
||||||
|
# Accept private messages?
|
||||||
|
(self.listen_nick and chan == self.nick)
|
||||||
|
):
|
||||||
|
filtered.append(chan)
|
||||||
|
|
||||||
|
|
||||||
def accepted_channel(self, chan, sender=None):
|
def accepted_channel(self, chan, sender=None):
|
||||||
"""Return True if the channel (or the user) is authorized"""
|
"""Return True if the channel (or the user) is authorized"""
|
||||||
if self.allow_all:
|
if self.allow_all:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
elif self.listen_nick:
|
elif self.listen_nick:
|
||||||
return (chan in self.channels and (sender is None or sender in
|
return (chan in self.channels and (sender is None or sender in
|
||||||
self.channels[chan].people)
|
self.channels[chan].people)
|
||||||
) or chan == self.nick
|
) or chan == self.nick
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return chan in self.channels and (sender is None or sender
|
return chan in self.channels and (sender is None or sender
|
||||||
in self.channels[chan].people)
|
in self.channels[chan].people)
|
||||||
|
|
||||||
|
|
||||||
def join(self, chan, password=None, force=False):
|
def join(self, chan, password=None, force=False):
|
||||||
"""Join a channel"""
|
"""Join a channel"""
|
||||||
if force or (chan is not None and
|
if force or (chan is not None and
|
||||||
|
@ -41,10 +41,12 @@ class MessageConsumer:
|
|||||||
def treat_in(self, context, msg):
|
def treat_in(self, context, msg):
|
||||||
"""Treat the input message"""
|
"""Treat the input message"""
|
||||||
if msg.cmd == "PING":
|
if msg.cmd == "PING":
|
||||||
self.srv.send_pong(msg.content)
|
self.srv.send_pong(msg.params[0])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# TODO: Manage credits
|
# TODO: Manage credits
|
||||||
if msg.channel is None or self.srv.accepted_channel(msg.channel):
|
msg.receivers = self.srv.filter_receivers(msg.receivers)
|
||||||
|
if len(msg.receivers) == 0:
|
||||||
# All messages
|
# All messages
|
||||||
context.treat_pre(msg, self.srv)
|
context.treat_pre(msg, self.srv)
|
||||||
|
|
||||||
|
156
message.py
156
message.py
@ -31,7 +31,7 @@ filename = ""
|
|||||||
|
|
||||||
def load(config_file):
|
def load(config_file):
|
||||||
global CREDITS, filename
|
global CREDITS, filename
|
||||||
CREDITS = dict ()
|
CREDITS = dict()
|
||||||
filename = config_file
|
filename = config_file
|
||||||
credits.BANLIST = xmlparser.parse_file(filename)
|
credits.BANLIST = xmlparser.parse_file(filename)
|
||||||
|
|
||||||
@ -39,99 +39,107 @@ def save():
|
|||||||
global filename
|
global filename
|
||||||
credits.BANLIST.save(filename)
|
credits.BANLIST.save(filename)
|
||||||
|
|
||||||
|
mgx = re.compile(b'''^(?:@(?P<tags>[^ ]+)\ )?
|
||||||
|
(?::(?P<prefix>
|
||||||
|
(?P<nick>[a-zA-Z][^!@ ]*)
|
||||||
|
(?: !(?P<user>[^@ ]+))?
|
||||||
|
(?:@(?P<host>[^ ]+))?
|
||||||
|
)\ )?
|
||||||
|
(?P<command>(?:[a-zA-Z]+|[0-9]{3}))
|
||||||
|
(?P<params>(?:\ [^:][^ ]*)*)(?:\ :(?P<trailing>.*))?
|
||||||
|
$''', re.X)
|
||||||
|
|
||||||
class Message:
|
class Message:
|
||||||
def __init__ (self, line, timestamp, private = False):
|
def __init__(self, raw_line, timestamp, private = False):
|
||||||
self.raw = line
|
self.raw = raw_line.rstrip() # remove trailing crlf
|
||||||
self.time = timestamp
|
self.tags = { 'time': timestamp }
|
||||||
self.channel = None
|
self.params = list()
|
||||||
self.content = b''
|
|
||||||
self.ctcp = False
|
|
||||||
line = line.rstrip() #remove trailing 'rn'
|
|
||||||
|
|
||||||
words = line.split(b' ')
|
p = mgx.match(raw_line.rstrip())
|
||||||
if words[0][0] == 58: #58 is : in ASCII table
|
|
||||||
self.sender = words[0][1:].decode()
|
|
||||||
self.cmd = words[1].decode()
|
|
||||||
else:
|
|
||||||
self.cmd = words[0].decode()
|
|
||||||
self.sender = None
|
|
||||||
|
|
||||||
if self.cmd == 'PING':
|
# Parse tags if exists: @aaa=bbb;ccc;example.com/ddd=eee
|
||||||
self.content = words[1]
|
if p.group("tags"):
|
||||||
elif self.sender is not None:
|
for tgs in p.group("tags").decode().split(';'):
|
||||||
self.nick = (self.sender.split('!'))[0]
|
tag = tgs.split('=')
|
||||||
if self.nick != self.sender:
|
if len(tag) > 1:
|
||||||
self.realname = (self.sender.split('!'))[1]
|
self.add_tag(tag[0], tag[1])
|
||||||
else:
|
else:
|
||||||
self.realname = self.nick
|
self.add_tag(tag[0])
|
||||||
self.sender = self.nick + "!" + self.realname
|
|
||||||
|
|
||||||
if len(words) > 2:
|
# Parse prefix if exists: :nick!user@host.com
|
||||||
self.channel = self.pickWords(words[2:]).decode()
|
self.prefix = self.decode(p.group("prefix"))
|
||||||
|
self.nick = self.decode(p.group("nick"))
|
||||||
|
self.user = self.decode(p.group("user"))
|
||||||
|
self.host = self.decode(p.group("host"))
|
||||||
|
|
||||||
if self.cmd == 'PRIVMSG':
|
# Parse command
|
||||||
# Check for CTCP request
|
self.cmd = p.group("command").decode()
|
||||||
self.ctcp = len(words[3]) > 1 and (words[3][0] == 0x01 or words[3][1] == 0x01)
|
|
||||||
self.content = self.pickWords(words[3:])
|
# Parse params
|
||||||
elif self.cmd == '353' and len(words) > 3:
|
if p.group("params"):
|
||||||
for i in range(2, len(words)):
|
for param in p.group("params").strip().split(b' '):
|
||||||
if words[i][0] == 58:
|
self.params.append(param)
|
||||||
self.content = words[i:]
|
|
||||||
#Remove the first :
|
if p.group("trailing"):
|
||||||
self.content[0] = self.content[0][1:]
|
self.params.append(p.group("trailing"))
|
||||||
self.channel = words[i-1].decode()
|
|
||||||
break
|
# Special commands
|
||||||
elif self.cmd == 'NICK':
|
|
||||||
self.content = self.pickWords(words[2:])
|
|
||||||
elif self.cmd == 'MODE':
|
|
||||||
self.content = words[3:]
|
|
||||||
elif self.cmd == '332':
|
|
||||||
self.channel = words[3]
|
|
||||||
self.content = self.pickWords(words[4:])
|
|
||||||
else:
|
|
||||||
#print (line)
|
|
||||||
self.content = self.pickWords(words[3:])
|
|
||||||
else:
|
|
||||||
print (line)
|
|
||||||
if self.cmd == 'PRIVMSG':
|
|
||||||
self.channel = words[2].decode()
|
|
||||||
self.content = b' '.join(words[3:])
|
|
||||||
self.decode()
|
|
||||||
if self.cmd == 'PRIVMSG':
|
if self.cmd == 'PRIVMSG':
|
||||||
self.parse_content()
|
self.receivers = self.params[0].decode().split(',')
|
||||||
self.private = private
|
|
||||||
|
|
||||||
def parse_content(self):
|
|
||||||
"""Parse or reparse the message content"""
|
|
||||||
# If CTCP, remove 0x01
|
# If CTCP, remove 0x01
|
||||||
if self.ctcp:
|
if len(self.params[1]) > 1 and (self.params[1][0] == 0x01 or self.params[1][1] == 0x01):
|
||||||
self.content = self.content[1:len(self.content)-1]
|
self.is_ctcp = True
|
||||||
|
self.text = self.decode(self.params[1][1:len(self.params[1])-1])
|
||||||
|
else:
|
||||||
|
self.is_ctcp = False
|
||||||
|
self.text = self.decode(self.params[1])
|
||||||
|
|
||||||
# Split content by words
|
# Split content by words
|
||||||
try:
|
try:
|
||||||
self.cmds = shlex.split(self.content)
|
self.cmds = shlex.split(self.text)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.cmds = self.content.split(' ')
|
self.cmds = self.text.split(' ')
|
||||||
|
|
||||||
|
elif self.cmd == '353': # RPL_NAMREPLY
|
||||||
|
self.receivers = [ self.params[0].decode() ]
|
||||||
|
self.nicks = self.params[1].decode().split(" ")
|
||||||
|
|
||||||
|
elif self.cmd == '332':
|
||||||
|
self.receivers = [ self.params[0].decode() ]
|
||||||
|
self.topic = self.params[1].decode().split(" ")
|
||||||
|
|
||||||
def pickWords(self, words):
|
|
||||||
"""Parse last argument of a line: can be a single word or a sentence starting with :"""
|
|
||||||
if len(words) > 0 and len(words[0]) > 0:
|
|
||||||
if words[0][0] == 58:
|
|
||||||
return b' '.join(words[0:])[1:]
|
|
||||||
else:
|
|
||||||
return words[0]
|
|
||||||
else:
|
else:
|
||||||
return b''
|
for i in range(0, len(self.params)-1):
|
||||||
|
self.params[i] = self.decode(self.params[i])
|
||||||
|
|
||||||
def decode(self):
|
print(self)
|
||||||
|
|
||||||
|
|
||||||
|
def add_tag(self, key, value=None):
|
||||||
|
"""Add an IRCv3.2 Message Tags"""
|
||||||
|
# Treat special tags
|
||||||
|
if key == "time":
|
||||||
|
value = datetime.strptime(value, "%Y-%m-%dT%H:%M:%S")
|
||||||
|
|
||||||
|
# Store tag
|
||||||
|
self.tags[key] = value
|
||||||
|
|
||||||
|
|
||||||
|
def decode(self, s):
|
||||||
"""Decode the content string usign a specific encoding"""
|
"""Decode the content string usign a specific encoding"""
|
||||||
if isinstance(self.content, bytes):
|
if isinstance(s, bytes):
|
||||||
try:
|
try:
|
||||||
self.content = self.content.decode()
|
s = s.decode()
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
#TODO: use encoding from config file
|
#TODO: use encoding from config file
|
||||||
self.content = self.content.decode('utf-8', 'replace')
|
s = s.decode('utf-8', 'replace')
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Message " + str(self.__dict__)
|
||||||
|
|
||||||
|
|
||||||
def authorize_DEPRECATED(self):
|
def authorize_DEPRECATED(self):
|
||||||
"""Is nemubot listening for the sender on this channel?"""
|
"""Is nemubot listening for the sender on this channel?"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user