Skip to content

Commit adb4f30

Browse files
authored
Fix checknetworks script
1 parent 389dd53 commit adb4f30

File tree

2 files changed

+123
-27
lines changed

2 files changed

+123
-27
lines changed

_data/checknetworks.py

Lines changed: 119 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
# <https://creativecommons.org/publicdomain/zero/1.0/>.
1313

1414
# to run this script:
15-
# pip3 install --update girc pyyaml docopt
15+
# pip3 install --upgrade girc pyyaml docopt
1616
# cd _data
17-
# python3 checknetworks.py
17+
# python3 checknetworks.py run su_networks.yml
1818

1919
"""checknetworks.py - tests IRCv3 network support file.
2020
Usage:
@@ -24,40 +24,132 @@
2424
Options:
2525
<supportfile> YAML network list [default: su_networks.yml]."""
2626
from docopt import docopt
27-
import girc
2827
import yaml
28+
import os
29+
import ssl
30+
import socket
31+
import traceback
32+
from datetime import datetime
33+
from girc.ircreactor.envelope import RFC1459Message
34+
from girc.ircreactor.events import EventManager
35+
36+
# settings
37+
nick = 'ircv3-tst'
38+
username = 'ircv3'
39+
realname = 'IRCv3 cap/isupport Tester'
40+
41+
42+
class IRCv3Connection:
43+
"""Connects to an IRC server at the given address."""
44+
def __init__(self, hostname, nick, username, realname, ipv6=False, debug=False):
45+
self.debug = debug
46+
self._data = b''
47+
48+
if ipv6:
49+
family = socket.AF_INET6
50+
else:
51+
family = socket.AF_INET
52+
53+
self.sock = socket.socket(family, socket.SOCK_STREAM)
54+
context = ssl.create_default_context()
55+
context.check_hostname = False
56+
context.verify_mode = ssl.CERT_NONE
57+
self.sock = context.wrap_socket(self.sock, server_hostname=hostname)
58+
self.sock.connect((hostname, 6697))
59+
60+
# identify
61+
self.send('CAP LS 302')
62+
self.send('NICK {}'.format(nick))
63+
self.send('USER {} 0 * :{}'.format(username, realname))
64+
self.send('CAP END')
65+
66+
# events setup
67+
self._events = EventManager()
68+
self._events.register('irc message 005', self.on_005)
69+
self._events.register('irc message cap', self.on_cap)
70+
self._events.register('irc message ping', self.on_ping)
71+
self._events.register('irc message 376', self.on_connected)
72+
self._events.register('irc message 422', self.on_connected)
73+
74+
# basic data
75+
self.caps = {}
76+
self.isupport = {}
77+
78+
def loop(self):
79+
"""Start connection loop."""
80+
try:
81+
while True:
82+
line = self.recv()
83+
if line.strip() == '':
84+
continue
85+
m = RFC1459Message.from_message(line)
86+
if m.verb == 'ERROR':
87+
break
88+
except:
89+
trace = traceback.format_exc()
90+
print(trace)
91+
92+
def recv(self, bytes=4096):
93+
"""Receive any info from the IRC server."""
94+
# recv existing lines before receiving new ones
95+
if b'\n' not in self._data:
96+
self._data += self.sock.recv(bytes)
97+
if b'\n' in self._data:
98+
raw_bytes, self._data = self._data.split(b'\n', maxsplit=1)
99+
line = raw_bytes.decode('utf-8', 'ignore').strip('\r\n')
100+
if line.strip() == '':
101+
return ''
102+
if self.debug:
103+
print('{} <- {}'.format(datetime.today().strftime('%H:%M:%S'), line))
104+
m = RFC1459Message.from_message(line)
105+
self._events.dispatch('irc message {}'.format(m.verb.lower()), m)
106+
return line
107+
return ''
108+
109+
def send(self, line):
110+
"""Send the given line to the IRC server."""
111+
self.send_raw('{}\r\n'.format(line))
112+
113+
def send_raw(self, line):
114+
"""Send the given line to the IRC server."""
115+
if self.debug:
116+
print('{} -> {}'.format(datetime.today().strftime('%H:%M:%S'), line.strip('\r\n')))
117+
self.sock.send(line.encode('utf-8', 'ignore'))
118+
119+
def on_ping(self, msg):
120+
self.send('PONG :{}'.format(msg.params[-1]))
121+
122+
def on_cap(self, msg):
123+
if msg.params[1].upper() != 'LS':
124+
return
125+
for cap in msg.params[-1].split():
126+
value = ''
127+
if '=' in cap:
128+
cap, value = cap.split('=', maxsplit=1)
129+
self.caps[cap] = value
130+
131+
def on_005(self, msg):
132+
for name in msg.params[1:-1]:
133+
value = ''
134+
if '=' in name:
135+
name, value = name.split('=', maxsplit=1)
136+
self.isupport[name] = value
137+
138+
def on_connected(self, msg):
139+
self.send('QUIT')
29140

30141

31142
def check_net(versions, info):
32143
print("Connecting to:", info['name'])
33144
hostname = info['net-address']['display']
34145

35-
reactor = girc.Reactor()
36-
37146
supported = {}
38147

39-
# register events
40-
@reactor.handler('in', 'endofmotd')
41-
@reactor.handler('in', 'nomotd')
42-
def handle_endofmotd(event):
43-
# get caps
44-
supported['caps'] = []
45-
for name in event['server'].capabilities.available:
46-
supported['caps'].append(name)
47-
48-
# get features
49-
supported['features'] = []
50-
for name in event['server'].features.available:
51-
supported['features'].append(name)
52-
53-
event['server'].quit()
54-
55-
# without TLS then with TLS
56-
server = reactor.create_server(info['name'] + ' noTLS')
57-
server.set_user_info('ircv3-tst', user='ircv3', real='IRCv3 tester')
58-
server.connect(hostname, 6667, ssl=False)
148+
irc = IRCv3Connection(hostname, nick, username, realname, debug=False)
149+
irc.loop()
59150

60-
reactor.run_forever()
151+
supported['features'] = irc.isupport.keys()
152+
supported['caps'] = irc.caps.keys()
61153

62154
# generate cap lists
63155
all_caps = []
@@ -84,7 +176,7 @@ def handle_endofmotd(event):
84176
print(' *!* + ', info['name'], 'now also supports', cap)
85177

86178
if __name__ == '__main__':
87-
arguments = docopt(__doc__, version=girc.__version__)
179+
arguments = docopt(__doc__, version='0.0.1')
88180

89181
if arguments['run']:
90182
print("NOTE: The output of this script can be incorrect due to nets only exposing certain caps when on/not on TLS, and other implementation and network-specific factors.")

_data/su_networks.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
monitor:
5858
msgid:
5959
multi-prefix:
60+
draft/multiline:
6061
setname:
6162
sts:
6263
userhost-in-names:
@@ -79,6 +80,8 @@
7980
cap-3.1:
8081
cap-3.2:
8182
cap-notify:
83+
draft/channel-rename:
84+
draft/chathistory:
8285
chghost:
8386
echo-message:
8487
extended-join:
@@ -88,6 +91,7 @@
8891
monitor:
8992
msgid:
9093
multi-prefix:
94+
draft/multiline:
9195
sasl-3.1:
9296
sasl-3.2:
9397
server-time:

0 commit comments

Comments
 (0)