rirc 0.6.3 → 1.0.0

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.
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