blur 1.8.6 → 2.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +10 -24
- data/executables/blur +63 -0
- data/library/blur/callbacks.rb +53 -0
- data/library/blur/channel.rb +78 -0
- data/library/blur/client.rb +165 -107
- data/library/blur/handling.rb +259 -179
- data/library/blur/network/connection.rb +26 -30
- data/library/blur/network/isupport.rb +38 -32
- data/library/blur/network.rb +193 -55
- data/library/blur/script.rb +132 -116
- data/library/blur/script_cache.rb +45 -0
- data/library/blur/user.rb +122 -0
- data/library/blur/version.rb +3 -3
- data/library/blur.rb +46 -19
- metadata +35 -28
- data/library/blur/encryption/base64.rb +0 -71
- data/library/blur/encryption/fish.rb +0 -80
- data/library/blur/encryption.rb +0 -17
- data/library/blur/enhancements.rb +0 -41
- data/library/blur/evaluable.rb +0 -13
- data/library/blur/extension.rb +0 -42
- data/library/blur/network/channel.rb +0 -91
- data/library/blur/network/command.rb +0 -83
- data/library/blur/network/user.rb +0 -106
- data/library/blur/script/cache.rb +0 -77
- data/library/blur/script/commands.rb +0 -77
- data/library/blur/script/dsl.rb +0 -52
data/library/blur/handling.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Blur
|
4
4
|
class Client
|
5
5
|
# The +Handling+ module is the very core of the IRC-part in Blur.
|
6
6
|
#
|
7
|
-
# When the client receives a parsed
|
8
|
-
# looking for a got_(the
|
7
|
+
# When the client receives a parsed message instance, it immediately starts
|
8
|
+
# looking for a got_(the message name) method inside the client, which
|
9
9
|
# is implemented in this module.
|
10
10
|
#
|
11
11
|
# == Implementing a handler
|
12
12
|
# Implementing a handler is very, very easy.
|
13
13
|
#
|
14
|
-
# All you need to do is define a method named got_(
|
15
|
-
# implement) that accepts 2 parameters, +network+ and +
|
14
|
+
# All you need to do is define a method named got_(message you want to
|
15
|
+
# implement) that accepts 2 parameters, +network+ and +message+.
|
16
16
|
#
|
17
|
-
# You can then do whatever you need to do with the
|
18
|
-
# you can access the parameters of it through {Network::
|
17
|
+
# You can then do whatever you need to do with the message instance,
|
18
|
+
# you can access the parameters of it through {Network::message#[]}.
|
19
19
|
#
|
20
20
|
# Don't forget that this module is inside the clients scope, so you can
|
21
21
|
# access all instance-variables and methods.
|
@@ -23,87 +23,99 @@ module Blur
|
|
23
23
|
# @example
|
24
24
|
# # RPL_WHOISUSER
|
25
25
|
# # <nick> <user> <host> * :<real name>
|
26
|
-
# def got_whois_user network,
|
27
|
-
# puts "nick: #{
|
26
|
+
# def got_whois_user network, message
|
27
|
+
# puts "nick: #{message.parameters[0]} user: #{message.parameters[1]} host: #{message.parameters[2]} ..."
|
28
28
|
# end
|
29
|
-
#
|
29
|
+
#
|
30
30
|
# @see http://www.irchelp.org/irchelp/rfc/chapter6.html
|
31
31
|
module Handling
|
32
|
-
|
33
32
|
# Called when the MOTD was received, which also means it is ready.
|
34
33
|
#
|
35
34
|
# == Callbacks:
|
36
35
|
# Emits +:connection_ready+ with the parameter +network+.
|
37
36
|
#
|
38
37
|
# Automatically joins the channels specified in +:channels+.
|
39
|
-
def got_end_of_motd network,
|
38
|
+
def got_end_of_motd network, _message
|
40
39
|
emit :connection_ready, network
|
41
|
-
|
42
|
-
network.options[
|
43
|
-
network.
|
40
|
+
|
41
|
+
network.options['channels'].each do |channel|
|
42
|
+
network.join channel
|
44
43
|
end
|
45
44
|
end
|
46
|
-
|
45
|
+
|
47
46
|
# Called when the namelist of a channel was received.
|
48
|
-
def got_name_reply network,
|
49
|
-
name =
|
50
|
-
|
47
|
+
def got_name_reply network, message
|
48
|
+
name = message.parameters[2] # Channel name.
|
49
|
+
nicks = message.parameters[3].split.map do |nick|
|
51
50
|
# Slice the nick if the first character is a user mode prefix.
|
52
|
-
if network.user_prefixes.include? nick.chr
|
53
|
-
nick.slice! 0
|
54
|
-
end
|
51
|
+
nick.slice! 0 if network.user_prefixes.include? nick.chr
|
55
52
|
|
56
|
-
|
53
|
+
nick
|
57
54
|
end
|
58
|
-
|
59
|
-
if channel = find_or_create_channel(name, network)
|
60
|
-
users.each do |user|
|
61
|
-
user.channel = channel
|
62
|
-
user.network = network
|
63
55
|
|
64
|
-
|
65
|
-
end
|
56
|
+
return unless (channel = find_or_create_channel(name, network))
|
66
57
|
|
67
|
-
|
58
|
+
users = nicks.map { |nick| find_or_create_user nick, network }
|
59
|
+
users.each do |user|
|
60
|
+
user.channels << channel
|
61
|
+
channel.users << user unless channel.users.include? user
|
68
62
|
end
|
63
|
+
|
64
|
+
emit :channel_who_reply, channel
|
69
65
|
end
|
70
|
-
|
66
|
+
|
71
67
|
# Called when a channel topic was changed.
|
72
68
|
#
|
73
69
|
# == Callbacks:
|
74
70
|
# Emits :topic_change with the parameters +channel+ and +topic+.
|
75
|
-
def got_channel_topic network,
|
76
|
-
|
77
|
-
|
78
|
-
if channel = find_or_create_channel(name, network)
|
79
|
-
emit :topic_change, channel, topic
|
71
|
+
def got_channel_topic network, message
|
72
|
+
_, channel_name, topic = message.parameters
|
80
73
|
|
81
|
-
|
82
|
-
|
74
|
+
return unless (channel = find_or_create_channel(channel_name, network))
|
75
|
+
|
76
|
+
emit :channel_topic, channel, topic
|
77
|
+
|
78
|
+
channel.topic = topic
|
83
79
|
end
|
84
|
-
|
80
|
+
|
85
81
|
# Called when the server needs to verify that we're alive.
|
86
|
-
def got_ping network,
|
87
|
-
network.
|
82
|
+
def got_ping network, message
|
83
|
+
network.last_pong_time = Time.now
|
84
|
+
network.transmit :PONG, message.parameters[0]
|
85
|
+
|
86
|
+
emit :network_ping, network, message.parameters[0]
|
88
87
|
end
|
89
|
-
|
88
|
+
|
89
|
+
# Called when the server reponds to our periodic PINGs.
|
90
|
+
def got_pong network, message
|
91
|
+
network.last_pong_time = Time.now
|
92
|
+
|
93
|
+
emit :network_pong, network, message.parameters[0]
|
94
|
+
end
|
95
|
+
|
90
96
|
# Called when a user changed nickname.
|
91
97
|
#
|
92
98
|
# == Callbacks:
|
93
|
-
# Emits :user_rename with the parameters +channel+, +user
|
94
|
-
def got_nick network,
|
95
|
-
|
96
|
-
|
97
|
-
if
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
99
|
+
# Emits :user_rename with the parameters +channel+, +user+ and +new_nick+
|
100
|
+
def got_nick network, message
|
101
|
+
old_nick = message.prefix.nick
|
102
|
+
|
103
|
+
# Update or own nickname if has been changed by the server
|
104
|
+
if network.nickname == old_nick
|
105
|
+
new_nick = message.parameters[0]
|
106
|
+
|
107
|
+
emit :nick, new_nick
|
108
|
+
network.nickname = new_nick
|
104
109
|
end
|
110
|
+
|
111
|
+
return unless (user = network.users.delete(old_nick))
|
112
|
+
|
113
|
+
new_nick = message.parameters[0]
|
114
|
+
emit :user_rename, user, new_nick
|
115
|
+
user.nick = new_nick
|
116
|
+
network.users[new_nick] = user
|
105
117
|
end
|
106
|
-
|
118
|
+
|
107
119
|
# Called when a message was received (both channel and private messages).
|
108
120
|
#
|
109
121
|
# == Callbacks:
|
@@ -113,95 +125,82 @@ module Blur
|
|
113
125
|
# Emits +:private_message+ with the parameters +user+ and +message+.
|
114
126
|
#
|
115
127
|
# @note Messages are contained as strings.
|
116
|
-
def got_privmsg network,
|
117
|
-
return
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
user
|
124
|
-
|
125
|
-
begin
|
126
|
-
if message[0..3] == "+OK " and channel.encrypted?
|
127
|
-
message = channel.encryption.decrypt message[4..-1]
|
128
|
-
end
|
129
|
-
rescue Encryption::BadInputError
|
130
|
-
puts "-!- FiSH: #{$!.message}"
|
131
|
-
rescue => exception
|
132
|
-
puts "-!- There was a problem with the FiSH encryption, disabling"
|
133
|
-
|
134
|
-
channel.encryption = nil
|
135
|
-
end
|
136
|
-
|
137
|
-
emit :message, user, channel, message
|
138
|
-
else
|
139
|
-
# Odd… this shouldn't happen
|
128
|
+
def got_privmsg network, message
|
129
|
+
return unless message.prefix.nick # Ignore all server privmsgs
|
130
|
+
|
131
|
+
name, msg = message.parameters
|
132
|
+
|
133
|
+
if (channel = network.channels[name])
|
134
|
+
unless (user = network.users[message.prefix.nick])
|
135
|
+
user = User.new message.prefix.nick, network
|
140
136
|
end
|
137
|
+
|
138
|
+
user.name = message.prefix.user
|
139
|
+
user.host = message.prefix.host
|
140
|
+
|
141
|
+
emit :message, user, channel, msg
|
141
142
|
else # This is a private message
|
142
|
-
user =
|
143
|
-
|
144
|
-
|
145
|
-
|
143
|
+
unless (user = network.users[message.prefix.nick])
|
144
|
+
user = User.new message.prefix.nick, network
|
145
|
+
user.name = message.prefix.user
|
146
|
+
user.host = message.prefix.host
|
147
|
+
end
|
146
148
|
|
147
|
-
emit :private_message, user,
|
149
|
+
emit :private_message, user, msg
|
148
150
|
end
|
149
151
|
end
|
150
|
-
|
152
|
+
|
151
153
|
# Called when a user joined a channel.
|
152
154
|
#
|
153
155
|
# == Callbacks:
|
154
156
|
# Emits +:user_entered+ with the parameters +channel+ and +user+.
|
155
|
-
def got_join network,
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
emit :user_entered, channel, user
|
168
|
-
end
|
157
|
+
def got_join network, message
|
158
|
+
channel_name = message.parameters[0]
|
159
|
+
|
160
|
+
user = find_or_create_user message.prefix.nick, network
|
161
|
+
user.name = message.prefix.user
|
162
|
+
user.host = message.prefix.host
|
163
|
+
|
164
|
+
return unless (channel = find_or_create_channel(channel_name, network))
|
165
|
+
|
166
|
+
_user_join_channel user, channel
|
167
|
+
|
168
|
+
emit :user_entered, channel, user
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
# Called when a user left a channel.
|
172
172
|
#
|
173
173
|
# == Callbacks:
|
174
174
|
# Emits +:user_left+ with the parameters +channel+ and +user+.
|
175
|
-
def got_part network,
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
175
|
+
def got_part network, message
|
176
|
+
channel_name = message.parameters[0]
|
177
|
+
|
178
|
+
return unless (channel = network.channels[channel_name])
|
179
|
+
return unless (user = network.users[message.prefix.nick])
|
180
|
+
|
181
|
+
_user_part_channel user, channel
|
182
|
+
|
183
|
+
emit :user_left, channel, user
|
185
184
|
end
|
186
|
-
|
185
|
+
|
187
186
|
# Called when a user disconnected from a network.
|
188
187
|
#
|
189
188
|
# == Callbacks:
|
190
189
|
# Emits +:user_quit+ with the parameters +channel+ and +user+.
|
191
|
-
def got_quit network,
|
192
|
-
nick =
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
emit :user_quit, channel, user
|
200
|
-
end
|
201
|
-
end
|
190
|
+
def got_quit network, message
|
191
|
+
nick = message.prefix.nick
|
192
|
+
reason = message.parameters[2]
|
193
|
+
|
194
|
+
return unless (user = network.users[nick])
|
195
|
+
|
196
|
+
user.channels.each do |channel|
|
197
|
+
channel.users.delete user
|
202
198
|
end
|
199
|
+
|
200
|
+
emit :user_quit, user, reason
|
201
|
+
network.users.delete nick
|
203
202
|
end
|
204
|
-
|
203
|
+
|
205
204
|
# Called when a user was kicked from a channel.
|
206
205
|
#
|
207
206
|
# == Callbacks:
|
@@ -209,34 +208,32 @@ module Blur
|
|
209
208
|
# and +reason+.
|
210
209
|
#
|
211
210
|
# +kicker+ is the user that kicked +kickee+.
|
212
|
-
def got_kick network,
|
213
|
-
name, target, reason =
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
end
|
223
|
-
end
|
211
|
+
def got_kick network, message
|
212
|
+
name, target, reason = message.parameters
|
213
|
+
|
214
|
+
return unless (channel = network.channels[name])
|
215
|
+
return unless (kicker = network.users[message.prefix.nick])
|
216
|
+
return unless (kickee = network.users[target])
|
217
|
+
|
218
|
+
_user_part_channel kickee, channel
|
219
|
+
|
220
|
+
emit :user_kicked, kicker, channel, kickee, reason
|
224
221
|
end
|
225
|
-
|
222
|
+
|
226
223
|
# Called when a topic was changed for a channel.
|
227
224
|
#
|
228
225
|
# == Callbacks:
|
229
226
|
# Emits :topic with the parameters +user+, +channel+ and +topic+.
|
230
|
-
def got_topic network,
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
channel.topic = topic
|
227
|
+
def got_topic network, message
|
228
|
+
_channel_name, topic = message.parameters
|
229
|
+
|
230
|
+
return unless (channel = network.channels[channel.name])
|
231
|
+
|
232
|
+
if (user = network.users[message.prefix.nick])
|
233
|
+
emit :topic, user, channel, topic
|
239
234
|
end
|
235
|
+
|
236
|
+
channel.topic = topic
|
240
237
|
end
|
241
238
|
|
242
239
|
# Called when a channel or a users flags was altered.
|
@@ -246,52 +243,135 @@ module Blur
|
|
246
243
|
# Emits +:channel_mode+ with the parameters +channel+ and +modes+.
|
247
244
|
# === When it's user modes:
|
248
245
|
# Emits +:user_mode+ with the parameters +user+ and +modes+.
|
249
|
-
def got_mode network,
|
250
|
-
name,
|
251
|
-
|
252
|
-
|
253
|
-
if limit
|
254
|
-
unless limit.numeric?
|
255
|
-
nick = limit
|
256
|
-
end
|
257
|
-
|
258
|
-
if user = channel.user_by_nick(nick)
|
259
|
-
user.merge_modes modes
|
260
|
-
emit :user_mode, user, modes
|
261
|
-
end
|
262
|
-
else
|
263
|
-
channel.merge_modes modes
|
264
|
-
emit :channel_mode, channel, modes
|
265
|
-
end
|
266
|
-
end
|
246
|
+
def got_mode network, message
|
247
|
+
name, _modes, _limit, _nick, _mask = message.parameters
|
248
|
+
|
249
|
+
return unless (_channel = network.channels[name])
|
267
250
|
end
|
268
251
|
|
269
252
|
# Called when the network announces its ISUPPORT parameters.
|
270
|
-
def got_005 network,
|
271
|
-
params =
|
253
|
+
def got_005 network, message
|
254
|
+
params = message.parameters[1..-2]
|
272
255
|
|
273
|
-
network.isupport.parse
|
256
|
+
network.isupport.parse(*params)
|
274
257
|
end
|
275
258
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
259
|
+
# Received when the server supports capability negotiation.
|
260
|
+
#
|
261
|
+
# CAP * LS :multi-prefix sasl
|
262
|
+
def got_cap network, message
|
263
|
+
_id, command = message.parameters[0..1]
|
264
|
+
|
265
|
+
case command
|
266
|
+
when 'LS'
|
267
|
+
capabilities = message.parameters[2]&.split
|
268
|
+
req = []
|
280
269
|
|
281
|
-
|
270
|
+
req << 'sasl' if network.sasl? && capabilities.include?('sasl')
|
271
|
+
req << 'account-tag' if capabilities.include?('account-tag')
|
282
272
|
|
283
|
-
|
284
|
-
channel = network.channel_by_name name
|
273
|
+
network.transmit :CAP, 'REQ', req.join(' ') if req.any?
|
285
274
|
|
286
|
-
|
287
|
-
channel = Network::Channel.new name, network, users
|
288
|
-
network.channels << channel
|
275
|
+
capabilities.each { |name| network.capabilities.push name }
|
289
276
|
|
290
|
-
|
291
|
-
|
292
|
-
|
277
|
+
emit :network_capabilities, network, capabilities
|
278
|
+
|
279
|
+
when 'ACK'
|
280
|
+
capabilities = message.parameters[2]&.split
|
281
|
+
|
282
|
+
network.transmit :AUTHENTICATE, 'PLAIN' if capabilities&.include?('sasl') && network.sasl?
|
283
|
+
|
284
|
+
network.cap_end if network.waiting_for_cap
|
285
|
+
when 'NAK'
|
286
|
+
capabilities = message.parameters[2]&.split
|
287
|
+
|
288
|
+
if capabilities&.include?('sasl') && network.sasl?
|
289
|
+
puts "The server does not support SASL, but you've configured it " \
|
290
|
+
'as such! Disconnecting!'
|
291
|
+
|
292
|
+
network.disconnect
|
293
293
|
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def got_001 network, message
|
298
|
+
network.abort_cap_neg if network.waiting_for_cap
|
299
|
+
|
300
|
+
# Get our nickname from the server
|
301
|
+
nickname = message.parameters[0]
|
302
|
+
network.nickname = nickname
|
303
|
+
end
|
304
|
+
|
305
|
+
def got_authenticate network, message
|
306
|
+
case message.parameters[0]
|
307
|
+
when '+'
|
308
|
+
return unless network.sasl?
|
309
|
+
|
310
|
+
sasl = network.options['sasl']
|
311
|
+
|
312
|
+
response = "#{sasl['username']}\x00#{sasl['username']}\x00#{sasl['password']}"
|
313
|
+
network.transmit :AUTHENTICATE, Base64.encode64(response).strip
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# :server 900 <nick> <nick>!<ident>@<host> <account> :You are now logged in as <user>
|
318
|
+
# RPL_LOGGEDIN SASL
|
319
|
+
def got_900 network, _message
|
320
|
+
network.cap_end if network.waiting_for_cap
|
321
|
+
end
|
322
|
+
|
323
|
+
# :server 904 <nick> :SASL authentication failed
|
324
|
+
# ERR_SASLFAIL
|
325
|
+
def got_904 network, message
|
326
|
+
_nick, _message = message.parameters
|
327
|
+
|
328
|
+
puts 'SASL authentication failed! Disconnecting!'
|
329
|
+
|
330
|
+
network.disconnect
|
331
|
+
end
|
332
|
+
|
333
|
+
def got_nickname_in_use network, message
|
334
|
+
nickname = network.options['nickname']
|
335
|
+
network.transmit :NICK, "#{nickname}_"
|
336
|
+
end
|
337
|
+
|
338
|
+
alias got_353 got_name_reply
|
339
|
+
alias got_422 got_end_of_motd
|
340
|
+
alias got_376 got_end_of_motd
|
341
|
+
alias got_332 got_channel_topic
|
342
|
+
alias got_433 got_nickname_in_use
|
343
|
+
|
344
|
+
private
|
345
|
+
|
346
|
+
def _user_part_channel user, channel
|
347
|
+
user.channels.delete channel
|
348
|
+
channel.users.delete user
|
349
|
+
|
350
|
+
# Forget the user if we no longer share any channels.
|
351
|
+
return unless user.channels.empty?
|
352
|
+
|
353
|
+
user.network.users.delete user.nick
|
354
|
+
end
|
355
|
+
|
356
|
+
def _user_join_channel user, channel
|
357
|
+
channel.users << user
|
358
|
+
user.channels << channel
|
359
|
+
end
|
360
|
+
|
361
|
+
def find_or_create_user nick, network
|
362
|
+
unless (user = network.users[nick])
|
363
|
+
user = User.new nick, network
|
364
|
+
network.users[nick] = user
|
365
|
+
emit :user_created, user
|
366
|
+
end
|
367
|
+
|
368
|
+
user
|
369
|
+
end
|
294
370
|
|
371
|
+
def find_or_create_channel name, network
|
372
|
+
unless (channel = network.channels[name])
|
373
|
+
channel = Channel.new name, network
|
374
|
+
network.channels[name] = channel
|
295
375
|
emit :channel_created, channel
|
296
376
|
end
|
297
377
|
|