2019-02-22 11:23:36 +00:00
|
|
|
from src import utils
|
|
|
|
|
2019-05-11 14:11:09 +00:00
|
|
|
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"),
|
2019-06-21 16:15:46 +00:00
|
|
|
utils.irc.Capability(None, "draft/rename", alias="rename"),
|
|
|
|
utils.irc.Capability(None, "draft/setname", alias="setname")
|
2019-05-11 14:11:09 +00:00
|
|
|
]
|
2019-02-22 11:23:36 +00:00
|
|
|
|
2019-06-21 17:05:11 +00:00
|
|
|
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]
|
|
|
|
|
2019-06-16 14:33:20 +00:00
|
|
|
def _cap_match(server, caps):
|
|
|
|
matched_caps = {}
|
2019-05-11 17:22:40 +00:00
|
|
|
blacklist = server.get_setting("blacklisted-caps", [])
|
2019-06-21 17:05:11 +00:00
|
|
|
|
|
|
|
cap_aliases = {}
|
2019-06-16 14:33:20 +00:00
|
|
|
for cap in caps:
|
2019-06-21 17:05:11 +00:00
|
|
|
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:
|
2019-06-16 14:33:20 +00:00
|
|
|
available = cap.available(server.server_capabilities)
|
2019-06-21 17:05:11 +00:00
|
|
|
if available and not server.has_capability(cap):
|
2019-06-16 14:33:20 +00:00
|
|
|
matched_caps[available] = cap
|
|
|
|
return matched_caps
|
2019-05-11 17:22:40 +00:00
|
|
|
|
2019-06-20 15:52:23 +00:00
|
|
|
def cap(exports, events, event):
|
2019-06-22 11:17:45 +00:00
|
|
|
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] == "*"
|
2019-02-22 11:23:36 +00:00
|
|
|
|
2019-06-16 14:33:20 +00:00
|
|
|
if subcommand == "DEL":
|
|
|
|
for capability in capabilities.keys():
|
|
|
|
event["server"].agreed_capabilities.discard(capability)
|
2019-07-28 19:55:34 +00:00
|
|
|
if capability and event["server"].server_capabilities:
|
|
|
|
del event["server"].server_capabilities[capability]
|
2019-06-16 14:33:20 +00:00
|
|
|
|
|
|
|
events.on("received.cap.del").call(server=event["server"],
|
|
|
|
capabilities=capabilities)
|
|
|
|
elif subcommand == "ACK":
|
2019-06-23 10:23:52 +00:00
|
|
|
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)
|
|
|
|
|
2019-06-16 14:33:20 +00:00
|
|
|
events.on("received.cap.ack").call(capabilities=capabilities,
|
|
|
|
server=event["server"])
|
|
|
|
|
|
|
|
if subcommand == "LS" or subcommand == "NEW":
|
2019-02-22 11:23:36 +00:00
|
|
|
event["server"].server_capabilities.update(capabilities)
|
|
|
|
if not is_multiline:
|
2019-05-11 17:22:40 +00:00
|
|
|
server_caps = list(event["server"].server_capabilities.keys())
|
2019-06-16 14:33:20 +00:00
|
|
|
all_caps = CAPABILITIES[:]
|
2019-02-22 11:23:36 +00:00
|
|
|
|
2019-06-20 15:52:23 +00:00
|
|
|
export_caps = [cap.copy() for cap in exports.get_all("cap")]
|
|
|
|
all_caps.extend(export_caps)
|
|
|
|
|
2019-05-11 17:22:40 +00:00
|
|
|
module_caps = events.on("received.cap.ls").call(
|
2019-02-22 11:23:36 +00:00
|
|
|
capabilities=event["server"].server_capabilities,
|
|
|
|
server=event["server"])
|
2019-05-11 17:22:40 +00:00
|
|
|
module_caps = list(filter(None, module_caps))
|
2019-06-16 14:33:20 +00:00
|
|
|
all_caps.extend(module_caps)
|
2019-05-11 17:22:40 +00:00
|
|
|
|
2019-06-16 14:33:20 +00:00
|
|
|
matched_caps = _cap_match(event["server"], all_caps)
|
|
|
|
event["server"].capability_queue.update(matched_caps)
|
2019-02-22 11:23:36 +00:00
|
|
|
|
2019-05-11 17:22:40 +00:00
|
|
|
if event["server"].capability_queue:
|
2019-02-22 11:23:36 +00:00
|
|
|
event["server"].send_capability_queue()
|
|
|
|
else:
|
|
|
|
event["server"].send_capability_end()
|
|
|
|
|
|
|
|
|
2019-05-18 13:57:09 +00:00
|
|
|
if subcommand == "ACK" or subcommand == "NAK":
|
|
|
|
ack = subcommand == "ACK"
|
2019-02-22 11:23:36 +00:00
|
|
|
for capability in capabilities:
|
2019-06-23 10:23:52 +00:00
|
|
|
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()
|
2019-02-22 11:23:36 +00:00
|
|
|
|
2019-06-16 14:33:20 +00:00
|
|
|
if (not event["server"].capabilities_requested and
|
2019-02-22 11:23:36 +00:00
|
|
|
not event["server"].waiting_for_capabilities()):
|
|
|
|
event["server"].send_capability_end()
|
|
|
|
|
|
|
|
def authenticate(events, event):
|
2019-06-22 11:17:45 +00:00
|
|
|
events.on("received.authenticate").call(message=event["line"].args[0],
|
2019-02-22 11:23:36 +00:00
|
|
|
server=event["server"])
|