Make CAP functionality more part of the framework and support message-tags and

multi-prefix
This commit is contained in:
jesopo 2018-09-03 11:14:27 +01:00
parent 61b2682c93
commit 29851d4305
3 changed files with 59 additions and 23 deletions

View file

@ -43,8 +43,16 @@ class LineHandler(object):
def handle(self, server, line): def handle(self, server, line):
original_line = line original_line = line
tags = {}
prefix = None prefix = None
command = None command = None
if line[0] == "@":
tags_prefix, line = line[1:].split(" ", 1)
for tag in tags_prefix.split(";"):
tag_split = tag.split("=", 1)
tags[tag[0]] = tag[1:]
if line[0] == ":": if line[0] == ":":
prefix, command, line = line[1:].split(" ", 2) prefix, command, line = line[1:].split(" ", 2)
else: else:
@ -66,16 +74,16 @@ class LineHandler(object):
#server, prefix, command, args, arbitrary #server, prefix, command, args, arbitrary
self.events.on("raw").on(command).call(server=server, self.events.on("raw").on(command).call(server=server,
prefix=prefix, args=args, arbitrary=arbitrary) prefix=prefix, args=args, arbitrary=arbitrary, tags=tags)
if default_event or not hooks: if default_event or not hooks:
if command.isdigit(): if command.isdigit():
self.events.on("received").on("numeric").on(command self.events.on("received").on("numeric").on(command
).call(line=original_line, server=server, ).call(line=original_line, server=server, tags=tags,
line_split=original_line.split(" "), number=command) line_split=original_line.split(" "), number=command)
else: else:
self.events.on("received").on(command).call( self.events.on("received").on(command).call(
line=original_line, line_split=original_line.split(" "), line=original_line, line_split=original_line.split(" "),
command=command, server=server) command=command, server=server, tags=tags)
# ping from the server # ping from the server
def ping(self, event): def ping(self, event):
@ -243,9 +251,22 @@ class LineHandler(object):
# the server is telling us about its capabilities! # the server is telling us about its capabilities!
def cap(self, event): def cap(self, event):
capabilities = (event["arbitrary"] or "").split(" ") capabilities = (event["arbitrary"] or "").split(" ")
self.events.on("received").on("cap").call( subcommand = event["args"][1].lower()
subcommand=event["args"][1], capabilities=capabilities,
server=event["server"]) if subcommand == "ls":
if "message-tags" in capabilities:
event["server"].queue_capability("message-tags")
if "multi-prefix" in capabilities:
event["server"].queue_capability("multi-prefix")
self.events.on("received").on("cap").on(subcommand).call(
capabilities=capabilities, server=event["server"])
if subcommand == "ls":
if event["server"].has_capability_queue():
event["server"].send_capability_queue()
else:
event["server"].send_capability_end()
# the server is asking for authentication # the server is asking for authentication
def authenticate(self, event): def authenticate(self, event):

View file

@ -26,6 +26,8 @@ class Server(object):
self.original_username = username or nickname self.original_username = username or nickname
self.original_realname = realname or nickname self.original_realname = realname or nickname
self.name = None self.name = None
self._capability_queue = set([])
self._capabilities_waiting = set([])
self.write_buffer = b"" self.write_buffer = b""
self.buffered_lines = [] self.buffered_lines = []
@ -79,7 +81,7 @@ class Server(object):
def connect(self): def connect(self):
self.socket.connect((self.target_hostname, self.port)) self.socket.connect((self.target_hostname, self.port))
self.events.on("preprocess.connect").call(server=self) self.send_capibility_ls()
if self.password: if self.password:
self.send_pass(self.password) self.send_pass(self.password)
@ -273,13 +275,31 @@ class Server(object):
def send_nick(self, nickname): def send_nick(self, nickname):
self.send("NICK %s" % nickname) self.send("NICK %s" % nickname)
def send_capability_request(self, capname): def send_capibility_ls(self):
self.send("CAP REQ :%s" % capname) self.send("CAP LS")
def queue_capability(self, capability):
self._capability_queue.add(capability)
def send_capability_queue(self):
if self.has_capability_queue():
capabilities = " ".join(self._capability_queue)
self._capability_queue.clear()
self.send_capability_request(capabilities)
def has_capability_queue(self):
return bool(len(self._capability_queue))
def send_capability_request(self, capability):
self.send("CAP REQ :%s" % capability)
def send_capability_end(self): def send_capability_end(self):
self.send("CAP END") self.send("CAP END")
def send_authenticate(self, text): def send_authenticate(self, text):
self.send("AUTHENTICATE %s" % text) self.send("AUTHENTICATE %s" % text)
def wait_for_capability(self, capability):
self._capabilities_waiting.add(capability)
def capability_done(self, capability):
self._capabilities_waiting.remove(capability)
if not self._capabilities_waiting:
self.send_capability_end()
def send_pass(self, password): def send_pass(self, password):
self.send("PASS %s" % password) self.send("PASS %s" % password)

View file

@ -4,10 +4,9 @@ class Module(object):
def __init__(self, bot, events, exports): def __init__(self, bot, events, exports):
self.bot = bot self.bot = bot
events.on("preprocess.connect").hook(self.preprocess_connect) events.on("preprocess.connect").hook(self.preprocess_connect)
events.on("received.cap").hook(self.on_cap) events.on("received.cap.ls").hook(self.on_cap)
events.on("received.cap.ack").hook(self.on_cap_ack)
events.on("received.authenticate").hook(self.on_authenticate) events.on("received.authenticate").hook(self.on_authenticate)
events.on("received.numeric").on(
"902", "903", "904", "905", "906", "907", "908").hook(self.on_90x)
def preprocess_connect(self, event): def preprocess_connect(self, event):
sasl = event["server"].get_setting("sasl") sasl = event["server"].get_setting("sasl")
@ -15,13 +14,12 @@ class Module(object):
event["server"].send_capability_request("sasl") event["server"].send_capability_request("sasl")
def on_cap(self, event): def on_cap(self, event):
if event["subcommand"] == "NAK": if "sasl" in event["capabilities"]:
event["server"].send_capability_end() event["server"].queue_capability("sasl")
elif event["subcommand"] == "ACK": def on_cap_ack(self, event):
if not "sasl" in event["capabilities"]: if "sasl" in event["capabilities"]:
event["server"].send_capability_end()
else:
event["server"].send_authenticate("PLAIN") event["server"].send_authenticate("PLAIN")
event["server"].wait_for_capability("sasl")
def on_authenticate(self, event): def on_authenticate(self, event):
if event["message"] != "+": if event["message"] != "+":
@ -33,7 +31,4 @@ class Module(object):
auth_text = base64.b64encode(auth_text.encode("utf8")) auth_text = base64.b64encode(auth_text.encode("utf8"))
auth_text = auth_text.decode("utf8") auth_text = auth_text.decode("utf8")
event["server"].send_authenticate(auth_text) event["server"].send_authenticate(auth_text)
event["server"].capability_done("sasl")
def on_90x(self, event):
event["server"].send_capability_end()