1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
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["args"][-1])
subcommand = event["args"][1].upper()
is_multiline = len(event["args"]) > 3 and event["args"][2] == "*"
if subcommand == "DEL":
for capability in capabilities.keys():
event["server"].agreed_capabilities.discard(capability)
del event["server"].server_capabilities[capability]
events.on("received.cap.del").call(server=event["server"],
capabilities=capabilities)
elif subcommand == "ACK":
event["server"].agreed_capabilities.update(capabilities)
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:
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["args"][0],
server=event["server"])
|