rirc 0.6.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rirc.rb +849 -827
  3. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0439855d19cb4f0b49ab4746b19d30dc9a4dea02
4
- data.tar.gz: 7b83de5afb207da4e02a5c0ec7b87326cd2c769b
3
+ metadata.gz: f612424ea118c08c809f22b6bc05e9e36d448099
4
+ data.tar.gz: be613bf902720ba2ec42b549c3a112b4895a8980
5
5
  SHA512:
6
- metadata.gz: 99bd8b6632cbc7cab8cd144f312e8803cf8efb3ef597b58d58f4392113ef42134539619c86e6e4e277f206b33a64908eb7a39e71f52c823452fb5fcd782b4685
7
- data.tar.gz: a7080e0d540d0feee76ccdf2ec2b91d0c8a98e5ee43717e6a1a18945fe3bc0f6cb552c8d6f6a32b52e9523af33e7fdf6f5f96b97518474c96d4261047d644010
6
+ metadata.gz: 04ce09e39a43338e101cafd406b82dbd06b2bb66b0849d890389914fd03e4ad04b5a905e677bbe38e6246f688eae9e16d97611ec9d391b8616334a14a1d601aa
7
+ data.tar.gz: abb6525486fa15c33b3fa7f7c27c1c7165a73668893616451502483a422430e0673d42c7fa7781f86b46baa8d7b54468b7f3b677ae0d5d58e64e5db846998bcf
@@ -1,827 +1,849 @@
1
- #! /bin/env ruby
2
- #
3
- ############################################################
4
- # Author: Alice "Duchess" Archer
5
- # Copyright (c) 2015 under the MIT License
6
- # see COPYING.md for full copyright
7
- # Name: rirc
8
- # Description: IRC framework for IRC bots written in ruby
9
- ############################################################
10
-
11
- require 'socket'
12
- require 'openssl'
13
-
14
- class IRC_message
15
- def initialize(command, nick, channel, message, ircmsg)
16
- @command = command
17
- @nick = nick
18
- @channel = channel
19
- @message = message
20
- @ircmsg = ircmsg
21
- end
22
-
23
- def ircmsg
24
- return @ircmsg
25
- end
26
-
27
- def message
28
- return @message
29
- end
30
-
31
- def nick
32
- return @nick
33
- end
34
-
35
- def command
36
- return @command
37
- end
38
-
39
- def channel
40
- return @channel
41
- end
42
-
43
- def check_regex(type, regex)
44
-
45
- if type == "command"
46
- if @command.match(regex) then return true end
47
- elsif type == "nick"
48
- if @nick.match(regex) then return true end
49
- elsif type == "channel"
50
- if @channel.match(regex) then return true end
51
- elsif type == "message"
52
- if @message.match(regex) then return true end
53
- else
54
- if @message.match(regex) then return true end
55
- end
56
-
57
- return false
58
- end
59
-
60
- def message_regex(regex)
61
- if @message.match(regex) then return true end
62
-
63
- return false
64
- end
65
- end
66
-
67
- class Pluginf
68
-
69
- def initialize(regex, name, file_name, help)
70
- @regexp = Regexp.new(regex.to_s)
71
- @name = name.to_s
72
- @file_name = file_name.to_s
73
- @help = help
74
- @chan_list = []
75
- @chan_list.push("any")
76
- end
77
-
78
- def initialize(regex, name, file_name, help, chan_list)
79
- @regexp = Regexp.new(regex.to_s)
80
- @name = name.to_s
81
- @file_name = file_name.to_s
82
- @help = help
83
- @chan_list = chan_list.map(&:to_s)
84
- end
85
-
86
- # default function
87
- def script(message, nick, chan)
88
-
89
- end
90
-
91
- def regex
92
- return @regexp
93
- end
94
-
95
- def chans
96
- return @chan_list
97
- end
98
-
99
- def name
100
- return @name
101
- end
102
-
103
- def file_name
104
- return @file_name
105
- end
106
-
107
- def help
108
- return @help
109
- end
110
-
111
- def cleanup
112
- return ""
113
- end
114
-
115
- def rm_chan(channel)
116
- @chan_list.delete_if { |a| channel == a }
117
- end
118
-
119
- def add_chan(channel)
120
- if !@chan_list.include? channel then @chan_list.push(channel) end
121
- end
122
- end
123
-
124
- class Plugin_manager
125
- def initialize(plugin_folder)
126
- @plugins = []
127
- @plugin_folder = plugin_folder
128
- @err_path = "./.errlog"
129
- end
130
- =begin
131
- def initialize(plugin_folder, err_path)
132
- @plugins = []
133
- @plugin_folder = plugin_folder
134
- @err_path = err_path.to_s
135
- end
136
- =end
137
- # returns all the plugins
138
- def plugins
139
-
140
- if @plugins.length == 0
141
- return []
142
- end
143
-
144
- return @plugins
145
- end
146
-
147
- # search functions
148
- def get_names
149
-
150
- if @plugins.length == 0
151
- return []
152
- end
153
-
154
- names = []
155
-
156
- @plugins.each { |a| names.push(a.name) }
157
-
158
- return names
159
- end
160
-
161
- def get_helps
162
-
163
- if @plugins.length == 0
164
- return []
165
- end
166
-
167
- names = []
168
-
169
- @plugins.each { |a| names.push(a.help) }
170
-
171
- return names
172
- end
173
-
174
- def get_files
175
-
176
- if @plugins.length == 0
177
- return []
178
- end
179
-
180
- names = []
181
-
182
- @plugins.each { |a| names.push(a.file_name) }
183
-
184
- return names
185
- end
186
-
187
- def get_chans
188
-
189
- if @plugins.length == 0
190
- return []
191
- end
192
-
193
- names = []
194
-
195
- @plugins.each { |a| names.push(a.chans) }
196
-
197
- return names
198
- end
199
-
200
- def get_chans(name)
201
-
202
- if !plugin_loaded(name)
203
- return nil
204
- end
205
-
206
- return get_plugin(name).chans
207
- end
208
-
209
- def add_chan(plugin_name, channel)
210
- if !plugin_loaded(name)
211
- return "#{plugin_name} is not loaded"
212
- end
213
-
214
- get_plugin(name).add_chan(channel)
215
-
216
- return "#{channel} added to #{plugin_name}"
217
- end
218
-
219
- def add_chan_clear_any(plugin_name, channel)
220
- if !plugin_loaded(name)
221
- return "#{plugin_name} is not loaded"
222
- end
223
-
224
- rm_chan(plugin_name, "any")
225
- add_chan(plugin_name, channel)
226
-
227
- return "#{channel} added to #{plugin_name}"
228
- end
229
-
230
- def rm_chan(plugin_name, channel)
231
- if !plugin_loaded(name)
232
- return "#{plugin_name} is not loaded"
233
- end
234
-
235
- get_plugin(name).rm_chan(channel)
236
-
237
- return "#{channel} removed from #{plugin_name}"
238
- end
239
-
240
- def get_regexps
241
-
242
- if @plugins.length == 0
243
- return []
244
- end
245
-
246
- names = []
247
-
248
- @plugins.each { |a| names.push(a.regex) }
249
-
250
- return names
251
- end
252
-
253
- def get_plugin(name) # gets a plugin by name or nil if it is not loaded
254
-
255
- if @plugins.length == 0
256
- return nil
257
- end
258
-
259
- @plugins.each { |a| if a.name == name then return a end }
260
-
261
- return nil
262
- end
263
-
264
- def plugin_help(name) # gets the help for a plugin
265
-
266
- if @plugins.length == 0
267
- return nil
268
- end
269
-
270
- @plugins.each { |a| if a.name == name then return a.help end }
271
-
272
- return nil
273
- end
274
-
275
- def plugin_file_name(name) # gets the file name for a plugin
276
-
277
- if @plugins.length == 0
278
- return nil
279
- end
280
-
281
- @plugins.each { |a| if a.name == name then return a.file_name end }
282
-
283
- return nil
284
- end
285
-
286
- def plugin_chans(name) # gets the array of channels for a plugin
287
-
288
- if @plugins.length == 0
289
- return nil
290
- end
291
-
292
- @plugins.each { |a| if a.name == name then return a.chans end }
293
-
294
- return nil
295
- end
296
-
297
- def plugin_regex(name) # gets the regex for a plugin
298
-
299
- if @plugins.length == 0
300
- return nil
301
- end
302
-
303
- @plugins.each { |a| if a.name == name then return a.regex end }
304
-
305
- return nil
306
- end
307
-
308
- # check if a plugin is loaded
309
- def plugin_loaded(name)
310
-
311
- if @plugins.length == 0
312
- return false
313
- end
314
-
315
- @plugins.each do |a|
316
- if a.name == name
317
- return true
318
- end
319
- end
320
-
321
- return false
322
- end
323
-
324
- # regex check function
325
- # this function uses the IRC_message object for message input
326
- # inputs:
327
- # - name
328
- # - IRC_message object
329
- # - array of admins [can be an empty array]
330
- # - backlog array [can be an empty array]
331
- # output: string
332
- def check_plugin(name, message, admins, backlog) #checks an individual plugin's (by name) regex against message
333
-
334
- if @plugins.length == 0
335
- return ""
336
- end
337
-
338
- if !plugin_loaded(name)
339
- return ""
340
- else
341
- if message.message.match(get_plugin(name).regex) and (get_plugin(name).chans.include? "any" or get_plugin(name).chans.include? message.channel)
342
- begin
343
- return get_plugin(name).script(message, admins, backlog) # plugins use the IRC_message object
344
- rescue => e
345
- if File.exist?(@err_path)
346
- File.write(@err_path, "PLUGIN #{name} FAILED TO RUN", File.size(@err_path), mode: 'a')
347
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
348
- File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
349
- File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
350
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
351
- end
352
- return "an error occured for plugin: #{name}"
353
- end
354
- end
355
- end
356
-
357
- return ""
358
- end
359
-
360
- # regex check function that returns responses for all plugins in an array
361
- # inputs:
362
- # - IRC_message object
363
- # - array of admins [can be an empty array]
364
- # - backlog array [can be an empty array]
365
- # output: array of strings
366
- def check_all(message, admins, backlog)
367
-
368
- if @plugins.length == 0
369
- return []
370
- end
371
-
372
- response = []
373
-
374
- # this is incredibly inneficient but it makes check_plugin flexible
375
- @plugins.each { |a| response.push(check_plugin(a.name, message, admins, backlog)) }
376
-
377
- return response
378
- end
379
-
380
- # load
381
- def plugin_load(name)
382
-
383
- $LOAD_PATH << "#{@plugin_folder}"
384
- response = ""
385
- temp_plugin = nil
386
- if name.match(/.rb$/)
387
- begin
388
- load "#{name}"
389
- plugin_loader = Loader.new
390
- temp_plugin = plugin_loader.get_plugin
391
- if plugin_loaded(temp_plugin.name)
392
- temp_plugin = nil
393
- return "Plugin #{name} is already loaded"
394
- end
395
- @plugins.push(temp_plugin)
396
- temp_plugin = nil
397
- response = "#{name[0..-4]} loaded"
398
- rescue => e
399
- response = "cannot load plugin"
400
- if File.exist?(@err_path)
401
- File.write(@err_path, "PLUGIN #{name} FAILED TO LOAD", File.size(@err_path), mode: 'a')
402
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
403
- File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
404
- File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
405
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
406
- end
407
- end
408
- else
409
- begin
410
- load "#{name}.rb"
411
- plugin_loader = Loader.new
412
- temp_plugin = plugin_loader.get_plugin
413
- if plugin_loaded(temp_plugin.name)
414
- temp_plugin = nil
415
- return "Plugin #{name} is already loaded"
416
- end
417
- @plugins.push(temp_plugin)
418
- temp_plugin = nil
419
- response = "#{name} loaded"
420
- rescue => e
421
- response = "cannot load plugin"
422
- if File.exist?(@err_path)
423
- File.write(@err_path, "PLUGIN #{name} FAILED TO LOAD", File.size(@err_path), mode: 'a')
424
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
425
- File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
426
- File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
427
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
428
- end
429
- end
430
- end
431
- $LOAD_PATH << './'
432
- return response
433
- end
434
-
435
- # unload
436
- def unload(name)
437
-
438
- if !plugin_loaded(name)
439
- return "plugin is not loaded"
440
- end
441
-
442
- get_plugin(name).cleanup
443
- @plugins.delete_if { |a| a.name == name }
444
-
445
- return "plugin #{name} unloaded"
446
- end
447
-
448
- # reload
449
- def reload(name)
450
-
451
- if !plugin_loaded(name)
452
- return "plugin is not loaded"
453
- end
454
-
455
- temp_file_name = get_plugin(name).file_name
456
-
457
- unload(name)
458
- plugin_load(temp_file_name)
459
-
460
- return "plugin #{name} reloaded"
461
- end
462
- end
463
-
464
- class IRCBot
465
- def initialize(network, port, nick, user_name, real_name)
466
- @network = network
467
- @port = port
468
- @nick = nick
469
- @user_name = user_name
470
- @real_name = real_name
471
- @socket = nil
472
- @channels = []
473
- @admins = []
474
- @ignore = []
475
- @hooks = {}
476
- @backlog = []
477
- @log_path = "./.log"
478
- @err_path = "./.errlog"
479
- end
480
- =begin
481
- def initialize(network, port, nick, user_name, real_name, log_path, err_path)
482
- @network = network
483
- @port = port
484
- @nick = nick
485
- @user_name = user_name
486
- @real_name = real_name
487
- @socket = nil
488
- @channels = []
489
- @admins = []
490
- @log_path = log_path
491
- @err_path = err_path
492
- @ignore = []
493
- @hooks = {}
494
- @backlog = []
495
- end
496
- =end
497
- def backlog
498
- return @backlog
499
- end
500
-
501
- def ignore
502
- return @ignore
503
- end
504
-
505
- def channels
506
- return @channels
507
- end
508
-
509
- def admins
510
- return @admins
511
- end
512
-
513
- def network
514
-
515
- return @network
516
- end
517
-
518
- def port
519
-
520
- return @port
521
- end
522
-
523
- def nick_name
524
-
525
- return @nick
526
- end
527
-
528
- def user_name
529
-
530
- return @user_name
531
- end
532
-
533
- def real_name
534
-
535
- return @real_name
536
- end
537
-
538
- def socket
539
-
540
- return @socket
541
- end
542
-
543
- def say(message)
544
-
545
- @socket.puts message
546
- end
547
-
548
- def join(channel)
549
-
550
- say "JOIN #{channel}"
551
- if !@channels.include? channel then @channels.push(channel) end
552
- end
553
-
554
- def connect
555
-
556
- @socket = TCPSocket.open(@network, @port)
557
- end
558
-
559
- def connect_ssl
560
- ssl_context = OpenSSL::SSL::SSLContext.new
561
- ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
562
- @socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context)
563
- @socket.sync = true
564
- @socket.connect
565
- end
566
-
567
- def connect_pass(pass)
568
-
569
- say "PASS #{pass}"
570
- end
571
-
572
- def nick(nick)
573
-
574
- @nick = nick
575
- say "NICK #{nick}"
576
- end
577
-
578
- def privmsg(dest, message)
579
-
580
- say "PRIVMSG #{dest} :#{message}"
581
- end
582
-
583
- def action(dest, message)
584
-
585
- privmsg(dest, "\01ACTION #{message}\07\01")
586
- end
587
-
588
- def notice(dest, message)
589
-
590
- say "NOTICE #{dest} :#{message}"
591
- end
592
-
593
- def ctcp(dest, message)
594
-
595
- privmsg(dest, "\01VERSION #{message}\07\01")
596
- end
597
-
598
- def part(dest, message)
599
-
600
- @channels.delete_if { |a| dest == a }
601
- say "PART #{dest} :#{message}"
602
- end
603
-
604
- def rm_chan(channel)
605
- @channels.delete_if { |a| channel == a }
606
- end
607
-
608
- def add_chan(channel)
609
- if !@channels.include? channel then @channels.push(channel) end
610
- end
611
-
612
- def quit(message)
613
-
614
- say "QUIT :#{message}"
615
- end
616
-
617
- def names(dest)
618
-
619
- say "NAMES #{dest}"
620
- end
621
-
622
- def identify(nickserv_pass)
623
- say "PRIVMSG nickserv :identify #{nickserv_pass}"
624
- end
625
-
626
- def auth(nickserv_pass)
627
- say "VERSION"
628
- say "USER #{@user_name} * * :#{@real_name}"
629
- nick(@nick)
630
- if nickserv_pass != "" and nickserv_pass != nil
631
- identify(nickserv_pass)
632
- end
633
- end
634
-
635
- def read
636
- if !@socket.eof
637
-
638
- msg = @socket.gets
639
-
640
- if msg.match(/^PING :(.*)$/)
641
- say "PONG #{$~[1]}"
642
- return "PING"
643
- end
644
-
645
- return msg
646
- else
647
- return nil
648
- end
649
- end
650
-
651
- def parse(msg)
652
- message_reg = msg.match(/^(:(?<prefix>\S+) )?(?<command>\S+)( (?!:)(?<params>.+?))?( :(?<trail>.+))?$/)
653
- nick_n = message_reg[:prefix].to_s.split("!")[0]
654
- command = message_reg[:command].to_s
655
- chan = message_reg[:params].to_s
656
- message = message_reg[:trail].to_s
657
-
658
- message = message.chomp
659
-
660
- if chan == @nick then chan = nick_n end
661
-
662
- ircmsg = IRC_message.new(command, nick_n, chan, message, msg)
663
-
664
- return ircmsg
665
- end
666
-
667
- def add_admin(nick)
668
- if !@admins.include? nick then @admins.push(nick) end
669
- end
670
-
671
- def remove_admin(nick)
672
- @admins.delete_if { |a| a == nick }
673
- end
674
-
675
- def add_ignore(nick)
676
- @ignore.push(nick)
677
- end
678
-
679
- def remove_ignore(nick)
680
- @ignore.delete_if { |a| a == nick }
681
- end
682
-
683
- def on(type, &block)
684
- type = type.to_s
685
- @hooks[type] ||= []
686
- @hooks[type] << block
687
- end
688
-
689
- def set_admins(admins_s)
690
- admins_s.each { |a| self.add_admin(a) }
691
- end
692
-
693
- def join_channels(channels_s)
694
- channels_s.each { |a| self.join(a) }
695
- end
696
-
697
- def create_log
698
- if !File.exist?(@log_path)
699
- File.open(@log_path, "w+") { |fw| fw.write("Command and Privmsg LOGS") }
700
- end
701
-
702
- if !File.exist?(@err_path)
703
- File.open(@err_path, "w+") { |fw| fw.write("Error LOGS") }
704
- end
705
- end
706
-
707
- def setup(use_ssl, use_pass, pass, nickserv_pass, channels_s)
708
- self.connect
709
- if use_ssl then self.connect_ssl end
710
- if use_pass then self.connect_pass(pass) end
711
- self.auth(nickserv_pass)
712
-
713
- self.create_log
714
-
715
- self.join_channels(channels_s)
716
-
717
- self.on :message do |msg|
718
- if msg.nick == msg.channel
719
- File.write(@log_path, msg.ircmsg, File.size(@log_path), mode: 'a')
720
- end
721
-
722
- if !self.nick_name == msg.nick and !self.ignore.include? msg.nick
723
- @backlog.push(msg)
724
- end
725
- end
726
- end
727
-
728
- def start!
729
-
730
- until self.socket.eof? do
731
- ircmsg = self.read
732
- msg = self.parse(ircmsg)
733
-
734
- if ircmsg == "PING" or self.ignore.include?(msg.nick) then next end
735
-
736
- begin
737
- hooks = @hooks['command']
738
- if hooks != nil
739
- hooks.each { |h| h.call(msg.channel, msg.command) }
740
- end
741
- rescue => e
742
- # do not do anything
743
- end
744
-
745
- begin
746
- hooks = @hooks['message']
747
- if hooks != nil
748
- hooks.each { |h| h.call(msg) }
749
- end
750
- rescue => e
751
- # do not do anything
752
- end
753
-
754
- begin
755
- hooks = @hooks['ircmsg']
756
- if hooks != nil
757
- hooks.each { |h| h.call(msg.nick, msg.command, msg.channel, msg.message) }
758
- end
759
- rescue => e
760
- # do not do anything
761
- end
762
- end
763
- end
764
- end
765
-
766
- class Commands_manager
767
-
768
- def initialize
769
- @reg_s = []
770
- @hook_s = []
771
- @size = 0
772
- @log_path = "./.log"
773
- @err_path = "./.errlog"
774
- end
775
-
776
- =begin
777
- def initialize(log_path, err_path)
778
- @reg_s = []
779
- @hook_s = []
780
- @size = 0
781
- @log_path = log_path
782
- @err_path = err_path
783
- end
784
- =end
785
- def on(reg, &block)
786
- reg = Regexp.new(reg.to_s)
787
- @reg_s.push(reg)
788
- @hook_s << block
789
- @size += 1
790
- end
791
-
792
- def check_cmds(ircbot, msg, pluginmgr)
793
-
794
- if @size == 0
795
- return
796
- end
797
-
798
- 0.upto(@size - 1) do |i|
799
- if msg.message_regex(@reg_s[i])
800
- File.write(@log_path, msg, File.size(@log_path), mode: 'a')
801
- begin
802
- @hook_s[i].call(ircbot, msg, pluginmgr)
803
- rescue => e
804
- if File.exist?(@err_path)
805
- File.write(@err_path, "COMMAND FAILED TO EXECUTE", File.size(@err_path), mode: 'a')
806
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
807
- File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
808
- File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
809
- File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
810
- end
811
- end
812
- end
813
- end
814
- end
815
-
816
- def hooks
817
- return @hook_s
818
- end
819
-
820
- def regs
821
- return @reg_s
822
- end
823
-
824
- def size
825
- return @size
826
- end
827
- end
1
+ #! /bin/env ruby
2
+ #
3
+ ############################################################
4
+ # Author: Alice "Duchess" Archer
5
+ # Copyright (c) 2015 under the MIT License
6
+ # see COPYING.md for full copyright
7
+ # Name: rirc
8
+ # Description: IRC framework for IRC bots written in ruby
9
+ ############################################################
10
+
11
+ require 'socket'
12
+ require 'openssl'
13
+
14
+ class IRC_message
15
+ def initialize(command, nick, channel, message, ircmsg)
16
+ @command = command
17
+ @nick = nick
18
+ @channel = channel
19
+ @message = message
20
+ @ircmsg = ircmsg
21
+ end
22
+
23
+ def ircmsg
24
+ return @ircmsg
25
+ end
26
+
27
+ def message
28
+ return @message
29
+ end
30
+
31
+ def nick
32
+ return @nick
33
+ end
34
+
35
+ def command
36
+ return @command
37
+ end
38
+
39
+ def channel
40
+ return @channel
41
+ end
42
+
43
+ def check_regex(type, regex)
44
+
45
+ if type == "command"
46
+ if @command.match(regex) then return true end
47
+ elsif type == "nick"
48
+ if @nick.match(regex) then return true end
49
+ elsif type == "channel"
50
+ if @channel.match(regex) then return true end
51
+ elsif type == "message"
52
+ if @message.match(regex) then return true end
53
+ else
54
+ if @message.match(regex) then return true end
55
+ end
56
+
57
+ return false
58
+ end
59
+
60
+ def message_regex(regex)
61
+ if @message.match(regex) then return true end
62
+
63
+ return false
64
+ end
65
+ end
66
+
67
+ class Pluginf
68
+
69
+ def initialize(regex, name, file_name, help)
70
+ @regexp = Regexp.new(regex.to_s)
71
+ @name = name.to_s
72
+ @file_name = file_name.to_s
73
+ @help = help
74
+ @chan_list = []
75
+ @chan_list.push("any")
76
+ end
77
+
78
+ def initialize(regex, name, file_name, help, chan_list)
79
+ @regexp = Regexp.new(regex.to_s)
80
+ @name = name.to_s
81
+ @file_name = file_name.to_s
82
+ @help = help
83
+ @chan_list = chan_list.map(&:to_s)
84
+ end
85
+
86
+ # default function
87
+ def script(message, nick, chan)
88
+
89
+ end
90
+
91
+ def regex
92
+ return @regexp
93
+ end
94
+
95
+ def chans
96
+ return @chan_list
97
+ end
98
+
99
+ def name
100
+ return @name
101
+ end
102
+
103
+ def file_name
104
+ return @file_name
105
+ end
106
+
107
+ def help
108
+ return @help
109
+ end
110
+
111
+ def cleanup
112
+ return ""
113
+ end
114
+
115
+ def rm_chan(channel)
116
+ @chan_list.delete_if { |a| channel == a }
117
+ end
118
+
119
+ def add_chan(channel)
120
+ if !@chan_list.include? channel then @chan_list.push(channel) end
121
+ end
122
+ end
123
+
124
+ class Plugin_manager
125
+ def initialize(plugin_folder)
126
+ @plugins = []
127
+ @plugin_folder = plugin_folder
128
+ @err_path = "./.errlog"
129
+ end
130
+ =begin
131
+ def initialize(plugin_folder, err_path)
132
+ @plugins = []
133
+ @plugin_folder = plugin_folder
134
+ @err_path = err_path.to_s
135
+ end
136
+ =end
137
+ # returns all the plugins
138
+ def plugins
139
+
140
+ if @plugins.length == 0
141
+ return []
142
+ end
143
+
144
+ return @plugins
145
+ end
146
+
147
+ # search functions
148
+ def get_names
149
+
150
+ if @plugins.length == 0
151
+ return []
152
+ end
153
+
154
+ names = []
155
+
156
+ @plugins.each { |a| names.push(a.name) }
157
+
158
+ return names
159
+ end
160
+
161
+ def get_helps
162
+
163
+ if @plugins.length == 0
164
+ return []
165
+ end
166
+
167
+ names = []
168
+
169
+ @plugins.each { |a| names.push(a.help) }
170
+
171
+ return names
172
+ end
173
+
174
+ def get_files
175
+
176
+ if @plugins.length == 0
177
+ return []
178
+ end
179
+
180
+ names = []
181
+
182
+ @plugins.each { |a| names.push(a.file_name) }
183
+
184
+ return names
185
+ end
186
+
187
+ def get_chans
188
+
189
+ if @plugins.length == 0
190
+ return []
191
+ end
192
+
193
+ names = []
194
+
195
+ @plugins.each { |a| names.push(a.chans) }
196
+
197
+ return names
198
+ end
199
+
200
+ def get_chans(name)
201
+
202
+ if !plugin_loaded(name)
203
+ return nil
204
+ end
205
+
206
+ return get_plugin(name).chans
207
+ end
208
+
209
+ def add_chan(plugin_name, channel)
210
+ if !plugin_loaded(name)
211
+ return "#{plugin_name} is not loaded"
212
+ end
213
+
214
+ get_plugin(name).add_chan(channel)
215
+
216
+ return "#{channel} added to #{plugin_name}"
217
+ end
218
+
219
+ def add_chan_clear_any(plugin_name, channel)
220
+ if !plugin_loaded(name)
221
+ return "#{plugin_name} is not loaded"
222
+ end
223
+
224
+ rm_chan(plugin_name, "any")
225
+ add_chan(plugin_name, channel)
226
+
227
+ return "#{channel} added to #{plugin_name}"
228
+ end
229
+
230
+ def rm_chan(plugin_name, channel)
231
+ if !plugin_loaded(name)
232
+ return "#{plugin_name} is not loaded"
233
+ end
234
+
235
+ get_plugin(name).rm_chan(channel)
236
+
237
+ return "#{channel} removed from #{plugin_name}"
238
+ end
239
+
240
+ def get_regexps
241
+
242
+ if @plugins.length == 0
243
+ return []
244
+ end
245
+
246
+ names = []
247
+
248
+ @plugins.each { |a| names.push(a.regex) }
249
+
250
+ return names
251
+ end
252
+
253
+ def get_plugin(name) # gets a plugin by name or nil if it is not loaded
254
+
255
+ if @plugins.length == 0
256
+ return nil
257
+ end
258
+
259
+ @plugins.each { |a| if a.name == name then return a end }
260
+
261
+ return nil
262
+ end
263
+
264
+ def plugin_help(name) # gets the help for a plugin
265
+
266
+ if @plugins.length == 0
267
+ return nil
268
+ end
269
+
270
+ @plugins.each { |a| if a.name == name then return a.help end }
271
+
272
+ return nil
273
+ end
274
+
275
+ def plugin_file_name(name) # gets the file name for a plugin
276
+
277
+ if @plugins.length == 0
278
+ return nil
279
+ end
280
+
281
+ @plugins.each { |a| if a.name == name then return a.file_name end }
282
+
283
+ return nil
284
+ end
285
+
286
+ def plugin_chans(name) # gets the array of channels for a plugin
287
+
288
+ if @plugins.length == 0
289
+ return nil
290
+ end
291
+
292
+ @plugins.each { |a| if a.name == name then return a.chans end }
293
+
294
+ return nil
295
+ end
296
+
297
+ def plugin_regex(name) # gets the regex for a plugin
298
+
299
+ if @plugins.length == 0
300
+ return nil
301
+ end
302
+
303
+ @plugins.each { |a| if a.name == name then return a.regex end }
304
+
305
+ return nil
306
+ end
307
+
308
+ # check if a plugin is loaded
309
+ def plugin_loaded(name)
310
+
311
+ if @plugins.length == 0
312
+ return false
313
+ end
314
+
315
+ @plugins.each do |a|
316
+ if a.name == name
317
+ return true
318
+ end
319
+ end
320
+
321
+ return false
322
+ end
323
+
324
+ # regex check function
325
+ # this function uses the IRC_message object for message input
326
+ # inputs:
327
+ # - name
328
+ # - IRC_message object
329
+ # - array of admins [can be an empty array]
330
+ # - backlog array [can be an empty array]
331
+ # output: string
332
+ def check_plugin(name, message, admins, backlog) #checks an individual plugin's (by name) regex against message
333
+
334
+ if @plugins.length == 0
335
+ return ""
336
+ end
337
+
338
+ if !plugin_loaded(name)
339
+ return ""
340
+ else
341
+ if message.message.match(get_plugin(name).regex) and (get_plugin(name).chans.include? "any" or get_plugin(name).chans.include? message.channel)
342
+ begin
343
+ return get_plugin(name).script(message, admins, backlog) # plugins use the IRC_message object
344
+ rescue => e
345
+ if File.exist?(@err_path)
346
+ File.write(@err_path, "PLUGIN #{name} FAILED TO RUN", File.size(@err_path), mode: 'a')
347
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
348
+ File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
349
+ File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
350
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
351
+ end
352
+ return "an error occured for plugin: #{name}"
353
+ end
354
+ end
355
+ end
356
+
357
+ return ""
358
+ end
359
+
360
+ # regex check function that returns responses for all plugins in an array
361
+ # inputs:
362
+ # - IRC_message object
363
+ # - array of admins [can be an empty array]
364
+ # - backlog array [can be an empty array]
365
+ # output: array of strings
366
+ def check_all(message, admins, backlog)
367
+
368
+ if @plugins.length == 0
369
+ return []
370
+ end
371
+
372
+ response = []
373
+
374
+ # this is incredibly inneficient but it makes check_plugin flexible
375
+ @plugins.each { |a| response.push(check_plugin(a.name, message, admins, backlog)) }
376
+
377
+ return response
378
+ end
379
+
380
+ # load
381
+ def plugin_load(name)
382
+
383
+ $LOAD_PATH << "#{@plugin_folder}"
384
+ response = ""
385
+ temp_plugin = nil
386
+ if name.match(/.rb$/)
387
+ begin
388
+ load "#{name}"
389
+ plugin_loader = Loader.new
390
+ temp_plugin = plugin_loader.get_plugin
391
+ if plugin_loaded(temp_plugin.name)
392
+ temp_plugin = nil
393
+ return "Plugin #{name} is already loaded"
394
+ end
395
+ @plugins.push(temp_plugin)
396
+ temp_plugin = nil
397
+ response = "#{name[0..-4]} loaded"
398
+ rescue => e
399
+ response = "cannot load plugin"
400
+ if File.exist?(@err_path)
401
+ File.write(@err_path, "PLUGIN #{name} FAILED TO LOAD", File.size(@err_path), mode: 'a')
402
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
403
+ File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
404
+ File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
405
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
406
+ end
407
+ end
408
+ else
409
+ begin
410
+ load "#{name}.rb"
411
+ plugin_loader = Loader.new
412
+ temp_plugin = plugin_loader.get_plugin
413
+ if plugin_loaded(temp_plugin.name)
414
+ temp_plugin = nil
415
+ return "Plugin #{name} is already loaded"
416
+ end
417
+ @plugins.push(temp_plugin)
418
+ temp_plugin = nil
419
+ response = "#{name} loaded"
420
+ rescue => e
421
+ response = "cannot load plugin"
422
+ if File.exist?(@err_path)
423
+ File.write(@err_path, "PLUGIN #{name} FAILED TO LOAD", File.size(@err_path), mode: 'a')
424
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
425
+ File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
426
+ File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
427
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
428
+ end
429
+ end
430
+ end
431
+ $LOAD_PATH << './'
432
+ return response
433
+ end
434
+
435
+ # unload
436
+ def unload(name)
437
+
438
+ if !plugin_loaded(name)
439
+ return "plugin is not loaded"
440
+ end
441
+
442
+ get_plugin(name).cleanup
443
+ @plugins.delete_if { |a| a.name == name }
444
+
445
+ return "plugin #{name} unloaded"
446
+ end
447
+
448
+ # reload
449
+ def reload(name)
450
+
451
+ if !plugin_loaded(name)
452
+ return "plugin is not loaded"
453
+ end
454
+
455
+ temp_file_name = get_plugin(name).file_name
456
+
457
+ unload(name)
458
+ plugin_load(temp_file_name)
459
+
460
+ return "plugin #{name} reloaded"
461
+ end
462
+ end
463
+
464
+ class IRCBot
465
+ def initialize(network, port, nick, user_name, real_name)
466
+ @network = network
467
+ @port = port
468
+ @nick = nick
469
+ @user_name = user_name
470
+ @real_name = real_name
471
+ @socket = nil
472
+ @channels = []
473
+ @admins = []
474
+ @ignore = []
475
+ @hooks = {}
476
+ @backlog = []
477
+ @log_path = "./.log"
478
+ @err_path = "./.errlog"
479
+ @stop_hooks = []
480
+ @stop_regs = []
481
+ end
482
+ =begin
483
+ def initialize(network, port, nick, user_name, real_name, log_path, err_path)
484
+ @network = network
485
+ @port = port
486
+ @nick = nick
487
+ @user_name = user_name
488
+ @real_name = real_name
489
+ @socket = nil
490
+ @channels = []
491
+ @admins = []
492
+ @log_path = log_path
493
+ @err_path = err_path
494
+ @ignore = []
495
+ @hooks = {}
496
+ @backlog = []
497
+ end
498
+ =end
499
+ def backlog
500
+ return @backlog
501
+ end
502
+
503
+ def ignore
504
+ return @ignore
505
+ end
506
+
507
+ def channels
508
+ return @channels
509
+ end
510
+
511
+ def admins
512
+ return @admins
513
+ end
514
+
515
+ def network
516
+
517
+ return @network
518
+ end
519
+
520
+ def port
521
+
522
+ return @port
523
+ end
524
+
525
+ def nick_name
526
+
527
+ return @nick
528
+ end
529
+
530
+ def user_name
531
+
532
+ return @user_name
533
+ end
534
+
535
+ def real_name
536
+
537
+ return @real_name
538
+ end
539
+
540
+ def socket
541
+
542
+ return @socket
543
+ end
544
+
545
+ def say(message)
546
+
547
+ @socket.puts message
548
+ end
549
+
550
+ def join(channel)
551
+
552
+ say "JOIN #{channel}"
553
+ if !@channels.include? channel then @channels.push(channel) end
554
+ end
555
+
556
+ def connect
557
+
558
+ @socket = TCPSocket.open(@network, @port)
559
+ end
560
+
561
+ def connect_ssl
562
+ ssl_context = OpenSSL::SSL::SSLContext.new
563
+ ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
564
+ @socket = OpenSSL::SSL::SSLSocket.new(@socket, ssl_context)
565
+ @socket.sync = true
566
+ @socket.connect
567
+ end
568
+
569
+ def connect_pass(pass)
570
+
571
+ say "PASS #{pass}"
572
+ end
573
+
574
+ def nick(nick)
575
+
576
+ @nick = nick
577
+ say "NICK #{nick}"
578
+ end
579
+
580
+ def privmsg(dest, message)
581
+
582
+ say "PRIVMSG #{dest} :#{message}"
583
+ end
584
+
585
+ def action(dest, message)
586
+
587
+ privmsg(dest, "\01ACTION #{message}\07\01")
588
+ end
589
+
590
+ def notice(dest, message)
591
+
592
+ say "NOTICE #{dest} :#{message}"
593
+ end
594
+
595
+ def ctcp(dest, message)
596
+
597
+ privmsg(dest, "\01VERSION #{message}\07\01")
598
+ end
599
+
600
+ def part(dest, message)
601
+
602
+ @channels.delete_if { |a| dest == a }
603
+ say "PART #{dest} :#{message}"
604
+ end
605
+
606
+ def rm_chan(channel)
607
+ @channels.delete_if { |a| channel == a }
608
+ end
609
+
610
+ def add_chan(channel)
611
+ if !@channels.include? channel then @channels.push(channel) end
612
+ end
613
+
614
+ def quit(message)
615
+
616
+ say "QUIT :#{message}"
617
+ end
618
+
619
+ def names(dest)
620
+
621
+ say "NAMES #{dest}"
622
+ end
623
+
624
+ def identify(nickserv_pass)
625
+ say "PRIVMSG nickserv :identify #{nickserv_pass}"
626
+ end
627
+
628
+ def auth(nickserv_pass)
629
+ say "VERSION"
630
+ say "USER #{@user_name} * * :#{@real_name}"
631
+ nick(@nick)
632
+ if nickserv_pass != "" and nickserv_pass != nil
633
+ identify(nickserv_pass)
634
+ end
635
+ end
636
+
637
+ def read
638
+ if !@socket.eof
639
+
640
+ msg = @socket.gets
641
+
642
+ if msg.match(/^PING :(.*)$/)
643
+ say "PONG #{$~[1]}"
644
+ return "PING"
645
+ end
646
+
647
+ return msg
648
+ else
649
+ return nil
650
+ end
651
+ end
652
+
653
+ def parse(msg)
654
+ message_reg = msg.match(/^(:(?<prefix>\S+) )?(?<command>\S+)( (?!:)(?<params>.+?))?( :(?<trail>.+))?$/)
655
+ nick_n = message_reg[:prefix].to_s.split("!")[0]
656
+ command = message_reg[:command].to_s
657
+ chan = message_reg[:params].to_s
658
+ message = message_reg[:trail].to_s
659
+
660
+ message = message.chomp
661
+
662
+ if chan == @nick then chan = nick_n end
663
+
664
+ ircmsg = IRC_message.new(command, nick_n, chan, message, msg)
665
+
666
+ return ircmsg
667
+ end
668
+
669
+ def add_admin(nick)
670
+ if !@admins.include? nick then @admins.push(nick) end
671
+ end
672
+
673
+ def remove_admin(nick)
674
+ @admins.delete_if { |a| a == nick }
675
+ end
676
+
677
+ def add_ignore(nick)
678
+ @ignore.push(nick)
679
+ end
680
+
681
+ def remove_ignore(nick)
682
+ @ignore.delete_if { |a| a == nick }
683
+ end
684
+
685
+ def on(type, &block)
686
+ type = type.to_s
687
+ @hooks[type] ||= []
688
+ @hooks[type] << block
689
+ end
690
+
691
+ def stop!(reg, &block)
692
+ reg = Regexp.new(reg.to_s)
693
+ @stop_regs.push(reg)
694
+ @stop_hooks << block
695
+ end
696
+
697
+ def set_admins(admins_s)
698
+ admins_s.each { |a| self.add_admin(a) }
699
+ end
700
+
701
+ def join_channels(channels_s)
702
+ channels_s.each { |a| self.join(a) }
703
+ end
704
+
705
+ def create_log
706
+ if !File.exist?(@log_path)
707
+ File.open(@log_path, "w+") { |fw| fw.write("Command and Privmsg LOGS") }
708
+ end
709
+
710
+ if !File.exist?(@err_path)
711
+ File.open(@err_path, "w+") { |fw| fw.write("Error LOGS") }
712
+ end
713
+ end
714
+
715
+ def setup(use_ssl, use_pass, pass, nickserv_pass, channels_s)
716
+ self.connect
717
+ if use_ssl then self.connect_ssl end
718
+ if use_pass then self.connect_pass(pass) end
719
+ self.auth(nickserv_pass)
720
+
721
+ self.create_log
722
+
723
+ self.join_channels(channels_s)
724
+
725
+ self.on :message do |msg|
726
+ if msg.nick == msg.channel
727
+ File.write(@log_path, msg.ircmsg, File.size(@log_path), mode: 'a')
728
+ end
729
+
730
+ if !self.nick_name == msg.nick and !self.ignore.include? msg.nick
731
+ @backlog.push(msg)
732
+ end
733
+ end
734
+ end
735
+
736
+ def start!
737
+
738
+ until self.socket.eof? do
739
+ ircmsg = self.read
740
+ msg = self.parse(ircmsg)
741
+
742
+ if ircmsg == "PING" or self.ignore.include?(msg.nick) then next end
743
+
744
+ begin
745
+ hooks = @hooks['command']
746
+ if hooks != nil
747
+ hooks.each { |h| h.call(msg.channel, msg.command) }
748
+ end
749
+ rescue => e
750
+ # do not do anything
751
+ end
752
+
753
+ begin
754
+ hooks = @hooks['message']
755
+ if hooks != nil
756
+ hooks.each { |h| h.call(msg) }
757
+ end
758
+ rescue => e
759
+ # do not do anything
760
+ end
761
+
762
+ begin
763
+ hooks = @hooks['ircmsg']
764
+ if hooks != nil
765
+ hooks.each { |h| h.call(msg.nick, msg.command, msg.channel, msg.message) }
766
+ end
767
+ rescue => e
768
+ # do not do anything
769
+ end
770
+
771
+ begin
772
+ hooks = @stop_hooks
773
+ i = 0
774
+ @stop_regs.each do |j|
775
+ if msg.message =~ j and @admins.include? msg.nick
776
+ hooks[i].call(msg)
777
+ return
778
+ end
779
+ i += 1
780
+ end
781
+ rescue => e
782
+ # do not do anything
783
+ end
784
+ end
785
+ end
786
+ end
787
+
788
+ class Commands_manager
789
+
790
+ def initialize
791
+ @reg_s = []
792
+ @hook_s = []
793
+ @size = 0
794
+ @log_path = "./.log"
795
+ @err_path = "./.errlog"
796
+ end
797
+
798
+ =begin
799
+ def initialize(log_path, err_path)
800
+ @reg_s = []
801
+ @hook_s = []
802
+ @size = 0
803
+ @log_path = log_path
804
+ @err_path = err_path
805
+ end
806
+ =end
807
+ def on(reg, &block)
808
+ reg = Regexp.new(reg.to_s)
809
+ @reg_s.push(reg)
810
+ @hook_s << block
811
+ @size += 1
812
+ end
813
+
814
+ def check_cmds(ircbot, msg, pluginmgr)
815
+
816
+ if @size == 0
817
+ return
818
+ end
819
+
820
+ 0.upto(@size - 1) do |i|
821
+ if msg.message_regex(@reg_s[i])
822
+ File.write(@log_path, msg, File.size(@log_path), mode: 'a')
823
+ begin
824
+ @hook_s[i].call(ircbot, msg, pluginmgr)
825
+ rescue => e
826
+ if File.exist?(@err_path)
827
+ File.write(@err_path, "COMMAND FAILED TO EXECUTE", File.size(@err_path), mode: 'a')
828
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
829
+ File.write(@err_path, e.to_s, File.size(@err_path), mode: 'a')
830
+ File.write(@err_path, e.backtrace.to_s, File.size(@err_path), mode: 'a')
831
+ File.write(@err_path, "======================================================", File.size(@err_path), mode: 'a')
832
+ end
833
+ end
834
+ end
835
+ end
836
+ end
837
+
838
+ def hooks
839
+ return @hook_s
840
+ end
841
+
842
+ def regs
843
+ return @reg_s
844
+ end
845
+
846
+ def size
847
+ return @size
848
+ end
849
+ end