aboutsummaryrefslogtreecommitdiff
path: root/src/core_modules/line_handler/ircv3.py
diff options
context:
space:
mode:
authorGravatar jesopo2019-12-10 05:27:35 +0000
committerGravatar jesopo2019-12-10 05:27:35 +0000
commit638eee0d685c06d258cb55287204ca97bca7c344 (patch)
tree33442439317ae2846f1efb7674b7a3758c8990a1 /src/core_modules/line_handler/ircv3.py
parentmove sys.exit() codes to an enum in utils.consts (diff)
signature
move core modules to src/core_modules, make them uneffected by white/black list
Diffstat (limited to 'src/core_modules/line_handler/ircv3.py')
-rw-r--r--src/core_modules/line_handler/ircv3.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/core_modules/line_handler/ircv3.py b/src/core_modules/line_handler/ircv3.py
new file mode 100644
index 00000000..a9d740ed
--- /dev/null
+++ b/src/core_modules/line_handler/ircv3.py
@@ -0,0 +1,138 @@
+from src import utils
+
+CAPABILITIES = [
+ utils.irc.Capability("multi-prefix"),
+ utils.irc.Capability("chghost"),
+ utils.irc.Capability("invite-notify"),
+ utils.irc.Capability("account-tag"),
+ utils.irc.Capability("account-notify"),
+ utils.irc.Capability("extended-join"),
+ utils.irc.Capability("away-notify"),
+ utils.irc.Capability("userhost-in-names"),
+ utils.irc.Capability("message-tags", "draft/message-tags-0.2"),
+ utils.irc.Capability("cap-notify"),
+ utils.irc.Capability("batch"),
+ utils.irc.Capability(None, "draft/rename", alias="rename"),
+ utils.irc.Capability(None, "draft/setname", alias="setname")
+]
+
+def _cap_depend_sort(caps, server_caps):
+ sorted_caps = []
+
+ caps_copy = {alias: cap.copy() for alias, cap in caps.items()}
+
+ for cap in caps.values():
+ if not cap.available(server_caps):
+ del caps_copy[cap.alias]
+
+ while True:
+ remove = []
+ for alias, cap in caps_copy.items():
+ for depend_alias in cap.depends_on:
+ if not depend_alias in caps_copy:
+ remove.append(alias)
+ if remove:
+ for alias in remove:
+ del caps_copy[alias]
+ else:
+ break
+
+ while caps_copy:
+ fulfilled = []
+ for cap in caps_copy.values():
+ remove = []
+ for depend_alias in cap.depends_on:
+ if depend_alias in sorted_caps:
+ remove.append(depend_alias)
+ for remove_cap in remove:
+ cap.depends_on.remove(remove_cap)
+
+ if not cap.depends_on:
+ fulfilled.append(cap.alias)
+ for fulfilled_cap in fulfilled:
+ del caps_copy[fulfilled_cap]
+ sorted_caps.append(fulfilled_cap)
+ return [caps[alias] for alias in sorted_caps]
+
+def _cap_match(server, caps):
+ matched_caps = {}
+ blacklist = server.get_setting("blacklisted-caps", [])
+
+ cap_aliases = {}
+ for cap in caps:
+ if not cap.alias in blacklist:
+ cap_aliases[cap.alias] = cap
+
+ sorted_caps = _cap_depend_sort(cap_aliases, server.server_capabilities)
+
+ for cap in sorted_caps:
+ available = cap.available(server.server_capabilities)
+ if available and not server.has_capability(cap):
+ matched_caps[available] = cap
+ return matched_caps
+
+def cap(exports, events, event):
+ capabilities = utils.parse.keyvalue(event["line"].args[-1])
+ subcommand = event["line"].args[1].upper()
+ is_multiline = len(event["line"].args) > 3 and event["line"].args[2] == "*"
+
+ if subcommand == "DEL":
+ for capability in capabilities.keys():
+ event["server"].agreed_capabilities.discard(capability)
+ if capability in event["server"].server_capabilities:
+ del event["server"].server_capabilities[capability]
+
+ events.on("received.cap.del").call(server=event["server"],
+ capabilities=capabilities)
+ elif subcommand == "ACK":
+ for cap_name, cap_args in capabilities.items():
+ if cap_name[0] == "-":
+ event["server"].agreed_capabilities.discard(cap_name[1:])
+ else:
+ event["server"].agreed_capabilities.add(cap_name)
+
+ events.on("received.cap.ack").call(capabilities=capabilities,
+ server=event["server"])
+
+ if subcommand == "LS" or subcommand == "NEW":
+ event["server"].server_capabilities.update(capabilities)
+ if not is_multiline:
+ server_caps = list(event["server"].server_capabilities.keys())
+ all_caps = CAPABILITIES[:]
+
+ export_caps = [cap.copy() for cap in exports.get_all("cap")]
+ all_caps.extend(export_caps)
+
+ module_caps = events.on("received.cap.ls").call(
+ capabilities=event["server"].server_capabilities,
+ server=event["server"])
+ module_caps = list(filter(None, module_caps))
+ all_caps.extend(module_caps)
+
+ matched_caps = _cap_match(event["server"], all_caps)
+ event["server"].capability_queue.update(matched_caps)
+
+ if event["server"].capability_queue:
+ event["server"].send_capability_queue()
+ else:
+ event["server"].send_capability_end()
+
+
+ if subcommand == "ACK" or subcommand == "NAK":
+ ack = subcommand == "ACK"
+ for capability in capabilities:
+ if capability in event["server"].capabilities_requested:
+ cap_obj = event["server"].capabilities_requested[capability]
+ del event["server"].capabilities_requested[capability]
+ if ack:
+ cap_obj.ack()
+ else:
+ cap_obj.nak()
+
+ if (not event["server"].capabilities_requested and
+ not event["server"].waiting_for_capabilities()):
+ event["server"].send_capability_end()
+
+def authenticate(events, event):
+ events.on("received.authenticate").call(message=event["line"].args[0],
+ server=event["server"])