grinch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -0
  3. data/LICENSE +22 -0
  4. data/README.md +180 -0
  5. data/docs/bot_options.md +454 -0
  6. data/docs/changes.md +541 -0
  7. data/docs/common_mistakes.md +60 -0
  8. data/docs/common_tasks.md +57 -0
  9. data/docs/encodings.md +69 -0
  10. data/docs/events.md +273 -0
  11. data/docs/getting_started.md +184 -0
  12. data/docs/logging.md +90 -0
  13. data/docs/migrating.md +267 -0
  14. data/docs/plugins.md +4 -0
  15. data/docs/readme.md +20 -0
  16. data/examples/basic/autovoice.rb +32 -0
  17. data/examples/basic/google.rb +35 -0
  18. data/examples/basic/hello.rb +15 -0
  19. data/examples/basic/join_part.rb +34 -0
  20. data/examples/basic/memo.rb +39 -0
  21. data/examples/basic/msg.rb +16 -0
  22. data/examples/basic/seen.rb +36 -0
  23. data/examples/basic/urban_dict.rb +35 -0
  24. data/examples/basic/url_shorten.rb +35 -0
  25. data/examples/plugins/autovoice.rb +37 -0
  26. data/examples/plugins/custom_prefix.rb +23 -0
  27. data/examples/plugins/dice_roll.rb +38 -0
  28. data/examples/plugins/google.rb +36 -0
  29. data/examples/plugins/hello.rb +22 -0
  30. data/examples/plugins/hooks.rb +36 -0
  31. data/examples/plugins/join_part.rb +42 -0
  32. data/examples/plugins/lambdas.rb +35 -0
  33. data/examples/plugins/last_nick.rb +24 -0
  34. data/examples/plugins/msg.rb +22 -0
  35. data/examples/plugins/multiple_matches.rb +32 -0
  36. data/examples/plugins/own_events.rb +37 -0
  37. data/examples/plugins/seen.rb +45 -0
  38. data/examples/plugins/timer.rb +22 -0
  39. data/examples/plugins/url_shorten.rb +33 -0
  40. data/lib/cinch.rb +5 -0
  41. data/lib/cinch/ban.rb +50 -0
  42. data/lib/cinch/bot.rb +479 -0
  43. data/lib/cinch/cached_list.rb +19 -0
  44. data/lib/cinch/callback.rb +20 -0
  45. data/lib/cinch/channel.rb +463 -0
  46. data/lib/cinch/channel_list.rb +29 -0
  47. data/lib/cinch/configuration.rb +73 -0
  48. data/lib/cinch/configuration/bot.rb +48 -0
  49. data/lib/cinch/configuration/dcc.rb +16 -0
  50. data/lib/cinch/configuration/plugins.rb +41 -0
  51. data/lib/cinch/configuration/sasl.rb +19 -0
  52. data/lib/cinch/configuration/ssl.rb +19 -0
  53. data/lib/cinch/configuration/timeouts.rb +14 -0
  54. data/lib/cinch/constants.rb +533 -0
  55. data/lib/cinch/dcc.rb +12 -0
  56. data/lib/cinch/dcc/dccable_object.rb +37 -0
  57. data/lib/cinch/dcc/incoming.rb +1 -0
  58. data/lib/cinch/dcc/incoming/send.rb +147 -0
  59. data/lib/cinch/dcc/outgoing.rb +1 -0
  60. data/lib/cinch/dcc/outgoing/send.rb +122 -0
  61. data/lib/cinch/exceptions.rb +46 -0
  62. data/lib/cinch/formatting.rb +125 -0
  63. data/lib/cinch/handler.rb +118 -0
  64. data/lib/cinch/handler_list.rb +90 -0
  65. data/lib/cinch/helpers.rb +231 -0
  66. data/lib/cinch/irc.rb +924 -0
  67. data/lib/cinch/isupport.rb +98 -0
  68. data/lib/cinch/log_filter.rb +21 -0
  69. data/lib/cinch/logger.rb +168 -0
  70. data/lib/cinch/logger/formatted_logger.rb +97 -0
  71. data/lib/cinch/logger/zcbot_logger.rb +22 -0
  72. data/lib/cinch/logger_list.rb +85 -0
  73. data/lib/cinch/mask.rb +69 -0
  74. data/lib/cinch/message.rb +392 -0
  75. data/lib/cinch/message_queue.rb +107 -0
  76. data/lib/cinch/mode_parser.rb +76 -0
  77. data/lib/cinch/network.rb +104 -0
  78. data/lib/cinch/open_ended_queue.rb +26 -0
  79. data/lib/cinch/pattern.rb +65 -0
  80. data/lib/cinch/plugin.rb +515 -0
  81. data/lib/cinch/plugin_list.rb +38 -0
  82. data/lib/cinch/rubyext/float.rb +3 -0
  83. data/lib/cinch/rubyext/module.rb +26 -0
  84. data/lib/cinch/rubyext/string.rb +33 -0
  85. data/lib/cinch/sasl.rb +34 -0
  86. data/lib/cinch/sasl/dh_blowfish.rb +71 -0
  87. data/lib/cinch/sasl/diffie_hellman.rb +47 -0
  88. data/lib/cinch/sasl/mechanism.rb +6 -0
  89. data/lib/cinch/sasl/plain.rb +26 -0
  90. data/lib/cinch/syncable.rb +83 -0
  91. data/lib/cinch/target.rb +199 -0
  92. data/lib/cinch/timer.rb +145 -0
  93. data/lib/cinch/user.rb +488 -0
  94. data/lib/cinch/user_list.rb +87 -0
  95. data/lib/cinch/utilities/deprecation.rb +16 -0
  96. data/lib/cinch/utilities/encoding.rb +37 -0
  97. data/lib/cinch/utilities/kernel.rb +13 -0
  98. data/lib/cinch/version.rb +4 -0
  99. metadata +140 -0
@@ -0,0 +1,145 @@
1
+ require "cinch/helpers"
2
+
3
+ module Cinch
4
+ # Timers are used for executing code in the future, either
5
+ # repeatedly or only once.
6
+ #
7
+ # In Cinch, two ways for creating timers are available:
8
+ #
9
+ # - The first way is by declaring them for a plugin, in which case
10
+ # they will start as soon as the bot connects to a server.
11
+ #
12
+ # - The second way is to dynamically create new timers in response
13
+ # to user input. A common example for this is an alarm clock
14
+ # plugin, which has to execute at a specific time.
15
+ #
16
+ # @see Helpers#Timer For dynamically creating timers
17
+ # @see Plugin::ClassMethods#timer For declaring timers in plugins
18
+ # @note It is possible to directly create instances of this class,
19
+ # but the referenced methods should suffice.
20
+ # @since 2.0.0
21
+ class Timer
22
+ include Helpers
23
+
24
+ # @return [Bot]
25
+ attr_reader :bot
26
+
27
+ # @return [Numeric] The interval (in seconds) of the timer
28
+ attr_accessor :interval
29
+
30
+ # @return [Boolean] If true, each invocation will be
31
+ # executed in a thread of its own.
32
+ attr_accessor :threaded
33
+
34
+ # @return [Proc]
35
+ attr_reader :block
36
+
37
+ # @return [Boolean]
38
+ attr_reader :started
39
+
40
+ # @return [Integer] The remaining number of shots before this timer
41
+ # will stop. This value will automatically reset after
42
+ # restarting the timer.
43
+ attr_accessor :shots
44
+ alias_method :threaded?, :threaded
45
+ alias_method :started?, :started
46
+
47
+ # @return [ThreadGroup]
48
+ # @api private
49
+ attr_reader :thread_group
50
+
51
+ # @param [Bot] bot The instance of {Bot} the timer is associated
52
+ # with
53
+ # @option options [Numeric] :interval The interval (in seconds) of
54
+ # the timer
55
+ # @option options [Integer] :shots (Float::INFINITY) How often should the
56
+ # timer fire?
57
+ # @option options [Boolean] :threaded (true) If true, each invocation will be
58
+ # executed in a thread of its own.
59
+ # @option options [Boolean] :start_automatically (true) If true,
60
+ # the timer will automatically start after the bot finished
61
+ # connecting.
62
+ # @option options [Boolean] :stop_automaticall (true) If true, the
63
+ # timer will automatically stop when the bot disconnects.
64
+ def initialize(bot, options, &block)
65
+ options = {:threaded => true, :shots => Float::INFINITY, :start_automatically => true, :stop_automatically => true}.merge(options)
66
+
67
+ @bot = bot
68
+ @interval = options[:interval].to_f
69
+ @threaded = options[:threaded]
70
+ @orig_shots = options[:shots]
71
+ # Setting @shots here so the attr_reader won't return nil
72
+ @shots = @orig_shots
73
+ @block = block
74
+
75
+ @started = false
76
+ @thread_group = ThreadGroup.new
77
+
78
+ if options[:start_automatically]
79
+ @bot.on :connect, //, self do |m, timer|
80
+ timer.start
81
+ end
82
+ end
83
+
84
+ if options[:stop_automatically]
85
+ @bot.on :disconnect, //, self do |m, timer|
86
+ timer.stop
87
+ end
88
+ end
89
+ end
90
+
91
+ # @return [Boolean]
92
+ def stopped?
93
+ !@started
94
+ end
95
+
96
+ # Start the timer
97
+ #
98
+ # @return [void]
99
+ def start
100
+ return if @started
101
+
102
+ @bot.loggers.debug "[timer] Starting timer #{self}"
103
+
104
+ @shots = @orig_shots
105
+
106
+ @thread_group.add Thread.new {
107
+ while @shots > 0 do
108
+ sleep @interval
109
+ if threaded?
110
+ Thread.new do
111
+ rescue_exception do
112
+ @block.call
113
+ end
114
+ end
115
+ else
116
+ rescue_exception do
117
+ @block.call
118
+ end
119
+ end
120
+
121
+ @shots -= 1
122
+ end
123
+ }
124
+
125
+ @started = true
126
+ end
127
+
128
+ # Stop the timer
129
+ #
130
+ # @return [void]
131
+ def stop
132
+ return unless @started
133
+
134
+ @bot.loggers.debug "[timer] Stopping timer #{self}"
135
+
136
+ @thread_group.list.each { |thread| thread.kill }
137
+ @started = false
138
+ end
139
+
140
+ # @return [String]
141
+ def to_s
142
+ "<Cinch::Timer %s/%s shots, %ds interval, %sthreaded, %sstarted, block: %s>" % [@orig_shots - @shots, @orig_shots, @interval, @threaded ? "" : "not ", @started ? "" : "not ", @block]
143
+ end
144
+ end
145
+ end
data/lib/cinch/user.rb ADDED
@@ -0,0 +1,488 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "cinch/target"
3
+ require "timeout"
4
+
5
+ module Cinch
6
+ # @attr_reader [String] authname
7
+ # @attr_reader [String, nil] away The user's away message, or
8
+ # `nil` if not away.
9
+ # @attr_reader [Array<Channel>] channels All channels the user is
10
+ # in.
11
+ # @attr_reader [String] host
12
+ # @attr_reader [Integer] idle How long this user has been idle, in seconds.
13
+ # This is a snapshot of the last WHOIS.
14
+ # @attr_reader [String] nick The user's nickname
15
+ # @attr_reader [Boolean] online True if the user is online.
16
+ # @attr_reader [Boolean] oper True if the user is an IRC operator.
17
+ # @attr_reader [String] realname
18
+ # @attr_reader [Boolean] secure True if the user is using a secure
19
+ # connection, i.e. SSL.
20
+ # @attr_reader [Time] signed_on_at
21
+ # @attr_reader [Boolean] unknown True if the instance references an user who
22
+ # cannot be found on the server.
23
+ # @attr_reader [String] user
24
+ #
25
+ # @version 2.0.0
26
+ class User < Target
27
+ include Syncable
28
+
29
+ def nick
30
+ name
31
+ end
32
+
33
+ # @return [String]
34
+ # @since 1.1.0
35
+ attr_reader :last_nick
36
+
37
+ # @return [Boolean]
38
+ attr_reader :synced
39
+ # @since 2.1.0
40
+ alias_method :synced?, :synced
41
+
42
+ # @return [Boolean]
43
+ # @api private
44
+ attr_accessor :in_whois
45
+
46
+ def user
47
+ attr(:user, true, false)
48
+ end
49
+
50
+ def host
51
+ attr(:host, true, false)
52
+ end
53
+
54
+ def realname
55
+ attr(:realname, true, false)
56
+ end
57
+
58
+ def authname
59
+ attr(:authname, true, false)
60
+ end
61
+
62
+ def away
63
+ attr(:away, true, false)
64
+ end
65
+
66
+ def idle
67
+ attr(:idle, true, false)
68
+ end
69
+
70
+ def signed_on_at
71
+ attr(:signed_on_at, true, false)
72
+ end
73
+
74
+ def unknown
75
+ attr(:unknown?, true, false)
76
+ end
77
+ alias_method :unknown?, :unknown
78
+
79
+ # @note This attribute will be updated by various events, but
80
+ # unless {#monitor} is being used, this information cannot be
81
+ # ensured to be always correct.
82
+ def online
83
+ attr(:online?, true, false)
84
+ end
85
+ alias_method :online?, :online
86
+
87
+ def channels
88
+ attr(:channels, true, false)
89
+ end
90
+
91
+ def secure
92
+ attr(:secure?, true, false)
93
+ end
94
+ alias_method :secure?, :secure
95
+
96
+ # @since 2.1.0
97
+ def oper
98
+ attr(:oper?, true, false)
99
+ end
100
+ alias_method :oper?, :oper
101
+
102
+ # @private
103
+ def user_unsynced
104
+ attr(:user, true, true)
105
+ end
106
+
107
+ # @private
108
+ def host_unsynced
109
+ attr(:host, true, true)
110
+ end
111
+
112
+ # @private
113
+ def realname_unsynced
114
+ attr(:realname, true, true)
115
+ end
116
+
117
+ # @private
118
+ def authname_unsynced
119
+ attr(:authname, true, true)
120
+ end
121
+
122
+ # @private
123
+ def idle_unsynced
124
+ attr(:idle, true, true)
125
+ end
126
+
127
+ # @private
128
+ def signed_on_at_unsynced
129
+ attr(:signed_on_at, true, true)
130
+ end
131
+
132
+ # @private
133
+ def unknown_unsynced
134
+ attr(:unknown?, true, true)
135
+ end
136
+ alias_method "unknown?_unsynced", "unknown_unsynced"
137
+
138
+ # @private
139
+ def online_unsynced
140
+ attr(:online?, true, true)
141
+ end
142
+ alias_method "online?_unsynced", "online_unsynced"
143
+
144
+ # @private
145
+ def channels_unsynced
146
+ attr(:channels, true, true)
147
+ end
148
+
149
+ # @private
150
+ def secure_unsynced
151
+ attr(:secure?, true, true)
152
+ end
153
+ alias_method "secure?_unsynced", "secure_unsynced"
154
+
155
+ # @private
156
+ # @since 2.1.0
157
+ def oper_unsynced
158
+ attr(:oper?, true, true)
159
+ end
160
+ alias_method "oper?_unsynced", "oper_unsynced"
161
+
162
+ # By default, you can use methods like {#user}, {#host} and
163
+ # alike – If you however fear that another thread might change
164
+ # data while you're using it and if this means a critical issue to
165
+ # your code, you can store a clone of the result of this method
166
+ # and work with that instead.
167
+ #
168
+ # @example
169
+ # on :channel do |m|
170
+ # data = m.user.data.dup
171
+ # do_something_with(data.user)
172
+ # do_something_with(data.host)
173
+ # end
174
+ # @return [Hash]
175
+ attr_reader :data
176
+
177
+ # @return [Boolean] True if the user is being monitored
178
+ # @see #monitor
179
+ # @see #unmonitor
180
+ # @note The attribute writer is in fact part of the private API
181
+ attr_reader :monitored
182
+ # @since 2.1.0
183
+ alias_method :monitored?, :monitored
184
+
185
+ # @api private
186
+ attr_writer :monitored
187
+
188
+ # @note Generally, you shouldn't initialize new instances of this
189
+ # class. Use {UserList#find_ensured} instead.
190
+ def initialize(*args)
191
+ @data = {
192
+ :user => nil,
193
+ :host => nil,
194
+ :realname => nil,
195
+ :authname => nil,
196
+ :idle => 0,
197
+ :signed_on_at => nil,
198
+ :unknown? => false,
199
+ :online? => false,
200
+ :channels => [],
201
+ :secure? => false,
202
+ :away => nil,
203
+ :oper? => false,
204
+ }
205
+ case args.size
206
+ when 2
207
+ @name, @bot = args
208
+ when 4
209
+ @data[:user], @name, @data[:host], @bot = args
210
+ else
211
+ raise ArgumentError
212
+ end
213
+
214
+ @synced_attributes = Set.new
215
+
216
+ @when_requesting_synced_attribute = lambda {|attr|
217
+ unless attribute_synced?(attr)
218
+ @data[:unknown?] = false
219
+ unsync :unknown?
220
+
221
+ refresh
222
+ end
223
+ }
224
+
225
+ @monitored = false
226
+ end
227
+
228
+ # Checks if the user is identified. Currently officially supports
229
+ # Quakenet and Freenode.
230
+ #
231
+ # @return [Boolean] true if the user is identified
232
+ # @version 1.1.0
233
+ def authed?
234
+ !attr(:authname).nil?
235
+ end
236
+
237
+ # @see Syncable#attr
238
+ def attr(attribute, data = true, unsync = false)
239
+ super
240
+ end
241
+
242
+ # Queries the IRC server for information on the user. This will
243
+ # set the User's state to not synced. After all information are
244
+ # received, the object will be set back to synced.
245
+ #
246
+ # @return [void]
247
+ # @note The alias `whois` is deprecated and will be removed in a
248
+ # future version.
249
+ def refresh
250
+ return if @in_whois
251
+ @data.keys.each do |attr|
252
+ unsync attr
253
+ end
254
+
255
+ @in_whois = true
256
+ if @bot.irc.network.whois_only_one_argument?
257
+ @bot.irc.send "WHOIS #@name"
258
+ else
259
+ @bot.irc.send "WHOIS #@name #@name"
260
+ end
261
+ end
262
+ alias_method :whois, :refresh # deprecated
263
+ undef_method(:whois) # yardoc hack
264
+
265
+ # @deprecated
266
+ def whois
267
+ Cinch::Utilities::Deprecation.print_deprecation("2.2.0", "User#whois", "User#refresh")
268
+ refresh
269
+ end
270
+
271
+ # @param [Hash, nil] values A hash of values gathered from WHOIS,
272
+ # or `nil` if no data was returned
273
+ # @return [void]
274
+ # @api private
275
+ # @since 1.0.1
276
+ def end_of_whois(values)
277
+ @in_whois = false
278
+ if values.nil?
279
+ # for some reason, we did not receive user information. one
280
+ # reason is freenode throttling WHOIS
281
+ Thread.new do
282
+ sleep 2
283
+ refresh
284
+ end
285
+ return
286
+ end
287
+
288
+ if values[:unknown?]
289
+ sync(:unknown?, true, true)
290
+ self.online = false
291
+ sync(:idle, 0, true)
292
+ sync(:channels, [], true)
293
+
294
+ fields = @data.keys
295
+ fields.delete(:unknown?)
296
+ fields.delete(:idle)
297
+ fields.delete(:channels)
298
+ fields.each do |field|
299
+ sync(field, nil, true)
300
+ end
301
+
302
+ return
303
+ end
304
+
305
+ if values[:registered]
306
+ values[:authname] ||= self.nick
307
+ values.delete(:registered)
308
+ end
309
+ {
310
+ :authname => nil,
311
+ :idle => 0,
312
+ :secure? => false,
313
+ :oper? => false,
314
+ :away => nil,
315
+ :channels => [],
316
+ }.merge(values).each do |attr, value|
317
+ sync(attr, value, true)
318
+ end
319
+
320
+ sync(:unknown?, false, true)
321
+ self.online = true
322
+ end
323
+
324
+ # @return [void]
325
+ # @since 1.0.1
326
+ # @api private
327
+ # @see Syncable#unsync_all
328
+ def unsync_all
329
+ super
330
+ end
331
+
332
+ # @return [String]
333
+ def to_s
334
+ @name
335
+ end
336
+
337
+ # @return [String]
338
+ def inspect
339
+ "#<User nick=#{@name.inspect}>"
340
+ end
341
+
342
+ # Generates a mask for the user.
343
+ #
344
+ # @param [String] s a pattern for generating the mask.
345
+ #
346
+ # - %n = nickname
347
+ # - %u = username
348
+ # - %h = host
349
+ # - %r = realname
350
+ # - %a = authname
351
+ #
352
+ # @return [Mask]
353
+ def mask(s = "%n!%u@%h")
354
+ s = s.gsub(/%(.)/) {
355
+ case $1
356
+ when "n"
357
+ @name
358
+ when "u"
359
+ self.user
360
+ when "h"
361
+ self.host
362
+ when "r"
363
+ self.realname
364
+ when "a"
365
+ self.authname
366
+ end
367
+ }
368
+
369
+ Mask.new(s)
370
+ end
371
+
372
+ # Check if the user matches a mask.
373
+ #
374
+ # @param [Ban, Mask, User, String] other The user or mask to match against
375
+ # @return [Boolean]
376
+ def match(other)
377
+ Mask.from(other) =~ Mask.from(self)
378
+ end
379
+ alias_method :=~, :match
380
+
381
+ # Starts monitoring a user's online state by either using MONITOR
382
+ # or periodically running WHOIS.
383
+ #
384
+ # @since 2.0.0
385
+ # @return [void]
386
+ # @see #unmonitor
387
+ def monitor
388
+ if @bot.irc.isupport["MONITOR"] > 0
389
+ @bot.irc.send "MONITOR + #@name"
390
+ else
391
+ refresh
392
+ @monitored_timer = Timer.new(@bot, interval: 30) {
393
+ refresh
394
+ }
395
+ @monitored_timer.start
396
+ end
397
+
398
+ @monitored = true
399
+ end
400
+
401
+ # Stops monitoring a user's online state.
402
+ #
403
+ # @since 2.0.0
404
+ # @return [void]
405
+ # @see #monitor
406
+ def unmonitor
407
+ if @bot.irc.isupport["MONITOR"] > 0
408
+ @bot.irc.send "MONITOR - #@name"
409
+ else
410
+ @monitored_timer.stop if @monitored_timer
411
+ end
412
+
413
+ @monitored = false
414
+ end
415
+
416
+ # Send data via DCC SEND to a user.
417
+ #
418
+ # @param [DCC::DCCableObject] io
419
+ # @param [String] filename
420
+ # @since 2.0.0
421
+ # @return [void]
422
+ # @note This method blocks.
423
+ def dcc_send(io, filename = File.basename(io.path))
424
+ own_ip = bot.config.dcc.own_ip || @bot.irc.socket.addr[2]
425
+ dcc = DCC::Outgoing::Send.new(receiver: self,
426
+ filename: filename,
427
+ io: io,
428
+ own_ip: own_ip
429
+ )
430
+
431
+ dcc.start_server
432
+
433
+ handler = Handler.new(@bot, :message,
434
+ Pattern.new(/^/,
435
+ /\001DCC RESUME #{filename} #{dcc.port} (\d+)\001/,
436
+ /$/)) do |m, position|
437
+ next unless m.user == self
438
+ dcc.seek(position.to_i)
439
+ m.user.send "\001DCC ACCEPT #{filename} #{dcc.port} #{position}\001"
440
+
441
+ handler.unregister
442
+ end
443
+ @bot.handlers.register(handler)
444
+
445
+ @bot.loggers.info "DCC: Outgoing DCC SEND: File name: %s - Size: %dB - IP: %s - Port: %d - Status: waiting" % [filename, io.size, own_ip, dcc.port]
446
+ dcc.send_handshake
447
+ begin
448
+ dcc.listen
449
+ @bot.loggers.info "DCC: Outgoing DCC SEND: File name: %s - Size: %dB - IP: %s - Port: %d - Status: done" % [filename, io.size, own_ip, dcc.port]
450
+ rescue Timeout::Error
451
+ @bot.loggers.info "DCC: Outgoing DCC SEND: File name: %s - Size: %dB - IP: %s - Port: %d - Status: failed (timeout)" % [filename, io.size, own_ip, dcc.port]
452
+ ensure
453
+ handler.unregister
454
+ end
455
+ end
456
+
457
+ # Updates the user's online state and dispatch the correct event.
458
+ #
459
+ # @since 2.0.0
460
+ # @return [void]
461
+ # @api private
462
+ def online=(bool)
463
+ notify = self.__send__("online?_unsynced") != bool && @monitored
464
+ sync(:online?, bool, true)
465
+
466
+ return unless notify
467
+ if bool
468
+ @bot.handlers.dispatch(:online, nil, self)
469
+ else
470
+ @bot.handlers.dispatch(:offline, nil, self)
471
+ end
472
+ end
473
+
474
+ # Used to update the user's nick on nickchange events.
475
+ #
476
+ # @param [String] new_nick The user's new nick
477
+ # @api private
478
+ # @return [void]
479
+ def update_nick(new_nick)
480
+ @last_nick, @name = @name, new_nick
481
+ # Unsync authname because some networks tie authentication to
482
+ # the nick, so the user might not be authenticated anymore after
483
+ # changing their nick
484
+ unsync(:authname)
485
+ @bot.user_list.update_nick(self)
486
+ end
487
+ end
488
+ end