mod_spox 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/CHANGELOG +16 -0
  2. data/INSTALL +4 -1
  3. data/bin/mod_spox +3 -1
  4. data/data/mod_spox/extras/AOLSpeak.rb +2 -2
  5. data/data/mod_spox/extras/AutoKick.rb +3 -8
  6. data/data/mod_spox/extras/AutoMode.rb +135 -0
  7. data/data/mod_spox/extras/EightBall.rb +1 -0
  8. data/data/mod_spox/extras/Headers.rb +4 -3
  9. data/data/mod_spox/extras/PhpFuncLookup.rb +14 -11
  10. data/data/mod_spox/extras/Roulette.rb +3 -3
  11. data/data/mod_spox/extras/Search.rb +3 -2
  12. data/data/mod_spox/extras/Talk.rb +1 -9
  13. data/data/mod_spox/extras/Translate.rb +3 -3
  14. data/data/mod_spox/extras/UrbanDictionary.rb +5 -3
  15. data/data/mod_spox/extras/Weather.rb +5 -4
  16. data/data/mod_spox/plugins/Authenticator.rb +2 -2
  17. data/data/mod_spox/plugins/Banner.rb +207 -2
  18. data/data/mod_spox/plugins/Helper.rb +1 -1
  19. data/data/mod_spox/plugins/PluginLoader.rb +22 -6
  20. data/data/mod_spox/plugins/Triggers.rb +6 -4
  21. data/lib/mod_spox/Action.rb +2 -0
  22. data/lib/mod_spox/BaseConfig.rb +2 -0
  23. data/lib/mod_spox/Bot.rb +32 -6
  24. data/lib/mod_spox/BotConfig.rb +3 -0
  25. data/lib/mod_spox/Cache.rb +57 -0
  26. data/lib/mod_spox/ConfigurationWizard.rb +6 -2
  27. data/lib/mod_spox/Helpers.rb +36 -18
  28. data/lib/mod_spox/Loader.rb +5 -54
  29. data/lib/mod_spox/Logger.rb +49 -3
  30. data/lib/mod_spox/MessageFactory.rb +5 -0
  31. data/lib/mod_spox/Monitors.rb +14 -12
  32. data/lib/mod_spox/Pipeline.rb +38 -6
  33. data/lib/mod_spox/Plugin.rb +3 -0
  34. data/lib/mod_spox/PluginHolder.rb +22 -0
  35. data/lib/mod_spox/PluginManager.rb +123 -25
  36. data/lib/mod_spox/Pool.rb +52 -23
  37. data/lib/mod_spox/Socket.rb +21 -10
  38. data/lib/mod_spox/Timer.rb +32 -6
  39. data/lib/mod_spox/handlers/BadNick.rb +2 -0
  40. data/lib/mod_spox/handlers/Bounce.rb +3 -0
  41. data/lib/mod_spox/handlers/Created.rb +2 -0
  42. data/lib/mod_spox/handlers/Handler.rb +5 -0
  43. data/lib/mod_spox/handlers/Invite.rb +2 -0
  44. data/lib/mod_spox/handlers/Join.rb +21 -5
  45. data/lib/mod_spox/handlers/Kick.rb +2 -0
  46. data/lib/mod_spox/handlers/LuserChannels.rb +2 -0
  47. data/lib/mod_spox/handlers/LuserClient.rb +1 -0
  48. data/lib/mod_spox/handlers/LuserMe.rb +1 -0
  49. data/lib/mod_spox/handlers/LuserOp.rb +2 -0
  50. data/lib/mod_spox/handlers/LuserUnknown.rb +2 -0
  51. data/lib/mod_spox/handlers/Mode.rb +2 -0
  52. data/lib/mod_spox/handlers/Motd.rb +5 -2
  53. data/lib/mod_spox/handlers/MyInfo.rb +2 -0
  54. data/lib/mod_spox/handlers/Names.rb +5 -1
  55. data/lib/mod_spox/handlers/Nick.rb +2 -0
  56. data/lib/mod_spox/handlers/NickInUse.rb +2 -0
  57. data/lib/mod_spox/handlers/Notice.rb +16 -4
  58. data/lib/mod_spox/handlers/Part.rb +2 -0
  59. data/lib/mod_spox/handlers/Ping.rb +2 -0
  60. data/lib/mod_spox/handlers/Pong.rb +2 -0
  61. data/lib/mod_spox/handlers/Privmsg.rb +16 -4
  62. data/lib/mod_spox/handlers/Quit.rb +2 -0
  63. data/lib/mod_spox/handlers/Topic.rb +2 -0
  64. data/lib/mod_spox/handlers/Welcome.rb +3 -0
  65. data/lib/mod_spox/handlers/Who.rb +3 -1
  66. data/lib/mod_spox/handlers/Whois.rb +8 -0
  67. data/lib/mod_spox/handlers/YourHost.rb +2 -0
  68. data/lib/mod_spox/messages/Messages.rb +6 -0
  69. data/lib/mod_spox/messages/incoming/BadNick.rb +1 -0
  70. data/lib/mod_spox/messages/incoming/Bounce.rb +1 -0
  71. data/lib/mod_spox/messages/incoming/Created.rb +1 -0
  72. data/lib/mod_spox/messages/incoming/Invite.rb +1 -0
  73. data/lib/mod_spox/messages/incoming/Join.rb +1 -0
  74. data/lib/mod_spox/messages/incoming/Kick.rb +1 -0
  75. data/lib/mod_spox/messages/incoming/LuserChannels.rb +1 -0
  76. data/lib/mod_spox/messages/incoming/LuserClient.rb +1 -0
  77. data/lib/mod_spox/messages/incoming/LuserMe.rb +1 -0
  78. data/lib/mod_spox/messages/incoming/LuserOp.rb +1 -0
  79. data/lib/mod_spox/messages/incoming/LuserUnknown.rb +1 -0
  80. data/lib/mod_spox/messages/incoming/Mode.rb +1 -0
  81. data/lib/mod_spox/messages/incoming/Motd.rb +1 -0
  82. data/lib/mod_spox/messages/incoming/MyInfo.rb +1 -0
  83. data/lib/mod_spox/messages/incoming/Names.rb +1 -0
  84. data/lib/mod_spox/messages/incoming/Nick.rb +1 -0
  85. data/lib/mod_spox/messages/incoming/NickInUse.rb +1 -0
  86. data/lib/mod_spox/messages/incoming/Notice.rb +1 -0
  87. data/lib/mod_spox/messages/incoming/Part.rb +1 -0
  88. data/lib/mod_spox/messages/incoming/Ping.rb +1 -0
  89. data/lib/mod_spox/messages/incoming/Pong.rb +1 -0
  90. data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -0
  91. data/lib/mod_spox/messages/incoming/Quit.rb +1 -0
  92. data/lib/mod_spox/messages/incoming/Topic.rb +1 -0
  93. data/lib/mod_spox/messages/incoming/TopicInfo.rb +1 -0
  94. data/lib/mod_spox/messages/incoming/Welcome.rb +1 -0
  95. data/lib/mod_spox/messages/incoming/Who.rb +1 -0
  96. data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
  97. data/lib/mod_spox/messages/incoming/YourHost.rb +1 -0
  98. data/lib/mod_spox/messages/internal/NickRequest.rb +1 -0
  99. data/lib/mod_spox/messages/internal/NickResponse.rb +1 -0
  100. data/lib/mod_spox/messages/internal/PluginLoadRequest.rb +1 -0
  101. data/lib/mod_spox/messages/internal/PluginLoadResponse.rb +1 -0
  102. data/lib/mod_spox/messages/internal/PluginModuleRequest.rb +1 -0
  103. data/lib/mod_spox/messages/internal/PluginModuleResponse.rb +1 -0
  104. data/lib/mod_spox/messages/internal/PluginReload.rb +10 -0
  105. data/lib/mod_spox/messages/internal/PluginRequest.rb +1 -0
  106. data/lib/mod_spox/messages/internal/PluginResponse.rb +1 -0
  107. data/lib/mod_spox/messages/internal/PluginUnloadRequest.rb +1 -0
  108. data/lib/mod_spox/messages/internal/PluginUnloadResponse.rb +1 -0
  109. data/lib/mod_spox/messages/internal/StatusResponse.rb +1 -0
  110. data/lib/mod_spox/messages/internal/TimerAdd.rb +1 -0
  111. data/lib/mod_spox/messages/internal/TimerClear.rb +8 -0
  112. data/lib/mod_spox/messages/internal/TimerResponse.rb +1 -0
  113. data/lib/mod_spox/messages/outgoing/Away.rb +1 -0
  114. data/lib/mod_spox/messages/outgoing/Notice.rb +1 -0
  115. data/lib/mod_spox/messages/outgoing/Ping.rb +1 -0
  116. data/lib/mod_spox/messages/outgoing/Quit.rb +1 -0
  117. data/lib/mod_spox/messages/outgoing/Raw.rb +16 -0
  118. data/lib/mod_spox/models/Models.rb +4 -0
  119. data/lib/mod_spox/models/Nick.rb +9 -0
  120. data/lib/mod_spox/models/Setting.rb +3 -5
  121. data/lib/mod_spox/models/Signature.rb +2 -3
  122. metadata +8 -2
@@ -23,12 +23,25 @@ class Banner < ModSpox::Plugin
23
23
  :description => 'List all currently active bans generated from the bot')
24
24
  Signature.find_or_create(:signature => 'banlist remove (\d+)', :plugin => name, :method => 'ban_remove', :group_id => admin.pk,
25
25
  :description => 'Remove a current ban').params = [:id]
26
+ Signature.find_or_create(:signature => 'exempt mode ([ov]) ?(\S+)?', :plugin => name, :method => 'exempt_mode', :group_id => admin.pk,
27
+ :description => 'Exempt given modes from kick. Apply to all channels if one is not provided').params = [:mode, :channel]
28
+ Signature.find_or_create(:signature => 'exempt nick (\S+) ?(\S+)?', :plugin => name, :method => 'exempt_nick', :group_id => admin.pk,
29
+ :description => 'Exempt a nick from kicks globally or per channel').params = [:nick, :channel]
30
+ Signature.find_or_create(:signature => 'exempt source (\S+)', :plugin => name, :method => 'exempt_source', :group_id => admin.pk,
31
+ :description => 'Exempt a source from kicks globally or per channel').params = [:source, :channel]
32
+ Signature.find_or_create(:signature => 'exempt list (nick|mode|source)', :plugin => name, :method => 'exempt_list', :group_id => admin.pk,
33
+ :description => 'List current exemptions of given type').params = [:type]
34
+ Signature.find_or_create(:signature => 'exempt remove (nick|mode|source) (\d+)', :plugin => name, :method => 'exempt_remove', :group_id => admin.pk,
35
+ :description => 'Remove exemption from given type').params = [:type, :id]
26
36
  @pipeline.hook(self, :mode_check, :Incoming_Mode)
27
37
  @pipeline.hook(self, :join_check, :Incoming_Join)
28
38
  @pipeline.hook(self, :who_check, :Incoming_Who)
29
39
  @pipeline.hook(self, :get_action, :Internal_TimerResponse)
30
40
  BanRecord.create_table unless BanRecord.table_exists?
31
41
  BanMask.create_table unless BanMask.table_exists?
42
+ BanNickExempt.create_table unless BanNickExempt.table_exists?
43
+ BanModeExempt.create_table unless BanModeExempt.table_exists?
44
+ BanSourceExempt.create_table unless BanSourceExempt.table_exists?
32
45
  @actions = []
33
46
  @up_sync = Mutex.new
34
47
  @timer_sync = Mutex.new
@@ -60,7 +73,7 @@ class Banner < ModSpox::Plugin
60
73
  # params:: parameters
61
74
  # Ban nick in given channel for given time providing given message
62
75
  def full_ban(message, params)
63
- nick = Models::Nick.filter(:nick => params[:nick]).first
76
+ nick = Helpers.find_model(params[:nick], false)
64
77
  channel = Channel.filter(:name => params[:channel]).first
65
78
  if(!me.is_op?(message.target))
66
79
  reply(message.replyto, "Error: I'm not a channel operator")
@@ -86,6 +99,8 @@ class Banner < ModSpox::Plugin
86
99
  raise NotOperator.new("I am not an operator in #{channel.name}")
87
100
  elsif(!nick.channels.include?(channel))
88
101
  raise NotInChannel.new("#{nick.nick} is not in channel: #{channel.name}")
102
+ elsif(check_exempt(nick, channel))
103
+ raise BanExemption.new("This nick is exempt from bans: #{nick.nick}")
89
104
  else
90
105
  mask = nick.source.nil? || nick.source.empty? ? "#{nick.nick}!*@*" : "*!*@#{nick.address}"
91
106
  BanRecord.new(:nick_id => nick.pk, :bantime => time.to_i, :remaining => time.to_i,
@@ -332,6 +347,144 @@ class Banner < ModSpox::Plugin
332
347
  end
333
348
  end
334
349
 
350
+ # message:: ModSpox::Messages::Incoming::Privmsg
351
+ # params:: parameters
352
+ # Add ban exemption for a given mode
353
+ def exempt_mode(message, params)
354
+ response = nil
355
+ if(params[:channel])
356
+ channel = Helpers.find_model(params[:channel])
357
+ if(channel.is_a?(Models::Channel))
358
+ BanModeExempt.find_or_create(:channel_id => channel.pk, :mode => params[:mode])
359
+ response = 'Mode exemption has been added'
360
+ else
361
+ response = "Failed to find given channel: #{params[:channel]}"
362
+ end
363
+ else
364
+ BanModeExempt.find_or_create(:channel_id => nil, :mode => params[:mode])
365
+ response = 'Mode exemption has been added'
366
+ end
367
+ reply message.replyto, response
368
+ end
369
+
370
+ # message:: ModSpox::Messages::Incoming::Privmsg
371
+ # params:: parameters
372
+ # Add ban exemption for a given nick
373
+ def exempt_nick(message, params)
374
+ response = ''
375
+ nick = Helpers.find_model(params[:nick])
376
+ unless(nick.is_a?(Models::Nick))
377
+ reply message.replyto, "\2Error:\2 Failed to find record of: #{params[:nick]}"
378
+ return
379
+ end
380
+ channel = params[:channel] ? Helpers.find_model(params[:channel]) : nil
381
+ if(channel)
382
+ if(channel.is_a?(Models::Channel))
383
+ BanNickExempt.find_or_create(:channel_id => channel.pk, :nick_id => nick.pk)
384
+ response = "Nick exemption for \2#{params[:nick]}\2 has been added to channel: \2#{params[:channel]}\2"
385
+ else
386
+ response = "Failed to find given channel: #{params[:channel]}"
387
+ end
388
+ else
389
+ BanNickExempt.find_or_create(:nick_id => nick.pk)
390
+ response = "Nick exemption for \2#{params[:nick]}\2 has been added for all channels"
391
+ end
392
+ reply message.replyto, response
393
+ end
394
+
395
+ # message:: ModSpox::Messages::Incoming::Privmsg
396
+ # params:: parameters
397
+ # Add ban exemption for sources matching a given mask
398
+ def exempt_source(message, params)
399
+ channel = params[:channel] ? Helpers.find_model(params[:channel]) : nil
400
+ response = ''
401
+ if(channel)
402
+ if(channel.is_a?(Models::Channel))
403
+ BanSourceExempt.find_or_create(:channel_id => channel.pk, :source => params[:source])
404
+ reponse = "Added exempt source: #{params[:source]} to channel: #{params[:channel]}"
405
+ else
406
+ response = "Failed to find given channel: #{params[:channel]}"
407
+ end
408
+ else
409
+ BanSourceExempt.find_or_create(:channel_id => nil, :source => params[:source])
410
+ response = "Added global exemption for source: #{params[:source]}"
411
+ end
412
+ reply message.replyto, response
413
+ end
414
+
415
+ # message:: ModSpox::Messages::Incoming::Privmsg
416
+ # params:: parameters
417
+ # List given type of current ban exemptions
418
+ def exempt_list(message, params)
419
+ output = []
420
+ if(params[:type] == 'nick')
421
+ output << 'Current nick exemptions:'
422
+ BanNickExempt.all.each do |record|
423
+ if(record.channel)
424
+ output << "\2#{record.pk}:\2 \2#{record.nick.nick}\2 is exempt in \2#{record.channel.name}\2"
425
+ else
426
+ output << "\2#{record.pk}:\2 \2#{record.nick.nick}\2 is exempt in \2all\2 channels"
427
+ end
428
+ end
429
+ elsif(params[:type] == 'mode')
430
+ output << 'Current mode exemptions:'
431
+ BanModeExempt.all.each do |record|
432
+ mode = record.mode == 'o' ? 'operator' : 'voice'
433
+ if(record.channel)
434
+ output << "\2#{record.pk}:\2 mode: \2#{mode}\2 is exempt in \2#{record.channel.name}\2"
435
+ else
436
+ output << "\2#{record.pk}:\2 mode: \2#{mode}\2 is exempt in \2all\2 channels"
437
+ end
438
+ end
439
+ elsif(params[:type] == 'source')
440
+ output << 'Current source exemptions:'
441
+ BanSourceExempt.all.each do |record|
442
+ if(record.channel)
443
+ output << "\2#{record.pk}:\2 sources matching: #{record.source} are exempt in \2#{record.channel.name}\2"
444
+ else
445
+ output << "\2#{record.pk}:\2 sources matching: #{record.source} are exempt in \2all\2 channels"
446
+ end
447
+ end
448
+ end
449
+ reply message.replyto, output
450
+ end
451
+
452
+ # message:: ModSpox::Messages::Incoming::Privmsg
453
+ # params:: parameters
454
+ # Remove given exemption from given list
455
+ def exempt_remove(message, params)
456
+ response = 'Exemption has been removed'
457
+ record = nil
458
+ case params[:type]
459
+ when 'nick'
460
+ record = BanNickExempt[params[:id].to_i]
461
+ when 'mode'
462
+ record = BanModeExempt[params[:id].to_i]
463
+ when 'source'
464
+ record = BanSourceExempt[params[:id].to_i]
465
+ end
466
+ if(record)
467
+ record.destroy
468
+ else
469
+ response = "Failed to find exemption of type: #{params[:type]} with ID: #{params[:id]}"
470
+ end
471
+ reply message.replyto, response
472
+ end
473
+
474
+ # nick:: ModSpox::Models::Nick
475
+ # channel:: ModSpox::Models::Channel
476
+ # Check if nick is currently exempt from bans
477
+ def check_exempt(nick, channel)
478
+ return true unless BanNickExempt.filter('nick_id = ? AND (channel_id = ? OR channel_id is null)', nick.pk, channel.pk).first.nil?
479
+ return true if !BanModeExempt.filter("mode = 'o' AND (channel_id = ? OR channel_id is null)", channel.pk).first.nil? && nick.is_op?(channel)
480
+ return true if !BanModeExempt.filter("mode = 'v' AND (channel_id = ? OR channel_id is null)", channel.pk).first.nil? && nick.is_voice?(channel)
481
+ BanSourceExempt.filter('channel_id = ? OR channel_id is null', channel.pk).each do |record|
482
+ regex = Regexp.new(record.source)
483
+ return true unless regex.match(nick.source).nil?
484
+ end
485
+ return false
486
+ end
487
+
335
488
  class BanRecord < Sequel::Model
336
489
  set_schema do
337
490
  primary_key :id
@@ -346,7 +499,7 @@ class Banner < ModSpox::Plugin
346
499
  end
347
500
 
348
501
  before_create do
349
- set :stamp => Time.now
502
+ update_values(:stamp => Time.now)
350
503
  end
351
504
 
352
505
  def channel
@@ -383,10 +536,62 @@ class Banner < ModSpox::Plugin
383
536
  end
384
537
  end
385
538
 
539
+ class BanNickExempt < Sequel::Model
540
+ set_schema do
541
+ primary_key :id
542
+ foreign_key :nick_id, :table => :nicks, :null => false
543
+ foreign_key :channel_id, :table => :channels
544
+ end
545
+
546
+ def nick
547
+ return Models::Nick[nick_id]
548
+ end
549
+
550
+ def channel
551
+ return Models::Channel[channel_id]
552
+ end
553
+ end
554
+
555
+ class BanSourceExempt < Sequel::Model
556
+ set_schema do
557
+ primary_key :id
558
+ varchar :source, :null => false
559
+ foreign_key :channel_id, :table => :channels
560
+ end
561
+
562
+ def channel
563
+ return Models::Channel[channel_id]
564
+ end
565
+
566
+ def mask
567
+ return values[:source] ? Marshal.load(values[:source].unpack('m')[0]) : nil
568
+ end
569
+
570
+ def mask=(val)
571
+ update_values(:source => [Marshal.dump(val)].pack('m'))
572
+ end
573
+
574
+ end
575
+
576
+ class BanModeExempt < Sequel::Model
577
+ set_schema do
578
+ primary_key :id
579
+ varchar :mode, :null => false
580
+ foreign_key :channel_id, :table => :channels, :unique => true
581
+ end
582
+
583
+ def channel
584
+ return Models::Channel[channel_id]
585
+ end
586
+ end
587
+
386
588
  class NotOperator < Exceptions::BotException
387
589
  end
388
590
 
389
591
  class NotInChannel < Exceptions::BotException
390
592
  end
593
+
594
+ class BanExemption < Exceptions::BotException
595
+ end
391
596
 
392
597
  end
@@ -11,7 +11,7 @@ class Helper < ModSpox::Plugin
11
11
  end
12
12
 
13
13
  def default_help(message, params)
14
- plugins = Signature.map(:plugin)
14
+ plugins = Signature.select(:plugin).map(:plugin)
15
15
  plugins.uniq!
16
16
  reply message.replyto, "Plugins currently available for help: #{plugins.join(', ')}"
17
17
  reply message.replyto, "Request help on a plugin: !help Plugin"
@@ -11,8 +11,8 @@ class PluginLoader < ModSpox::Plugin
11
11
  :group_id => admin.pk, :description => 'Load the given plugin').params = [:plugin]
12
12
  Models::Signature.find_or_create(:signature => 'plugins unload (\S+)', :plugin => name, :method => 'unload_plugin',
13
13
  :group_id => admin.pk, :description => 'Unload given plugin').params = [:plugin]
14
- Models::Signature.find_or_create(:signature => 'plugins reload', :plugin => name, :method => 'reload_plugin',
15
- :group_id => admin.pk, :description => 'Reload plugins')
14
+ Models::Signature.find_or_create(:signature => 'plugins reload ?(\S+)?', :plugin => name, :method => 'reload_plugin',
15
+ :group_id => admin.pk, :description => 'Reload single plugin or all plugins if names not provided').params = [:plugin]
16
16
  @pipeline.hook(self, :get_module, :Internal_PluginModuleResponse)
17
17
  @plugins_mod = nil
18
18
  end
@@ -21,10 +21,11 @@ class PluginLoader < ModSpox::Plugin
21
21
  # params:: matching signature params
22
22
  # Output currently available plugins for loading
23
23
  def available_plugins(message, params)
24
- @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "\2Currently available plugins:\2")
24
+ output = ["\2Currently available plugins:\2"]
25
25
  find_plugins.each_pair do | plugin, path |
26
- @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "\2#{plugin}:\2 #{path}")
26
+ output << "\2#{plugin}:\2 #{path}"
27
27
  end
28
+ reply message.replyto, output
28
29
  end
29
30
 
30
31
  # message:: ModSpox::Messages::Incoming::Privmsg
@@ -65,8 +66,23 @@ class PluginLoader < ModSpox::Plugin
65
66
  # params:: matching signature params
66
67
  # Reloads plugins
67
68
  def reload_plugin(message, params)
68
- @pipeline << Messages::Internal::PluginReload.new
69
- @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'Okay')
69
+ if(params[:plugin])
70
+ users = plugin_discovery(BotConfig[:userpluginpath])
71
+ extras = plugin_discovery(BotConfig[:pluginextraspath])
72
+ fresh = nil
73
+ stale = nil
74
+ users.each_pair{|name, path| stale = path if name == params[:plugin]}
75
+ extras.each_pair{|name, path| fresh = path if name == params[:plugin]}
76
+ if(fresh && stale)
77
+ @pipeline << Messages::Internal::PluginReload.new(fresh, stale)
78
+ reply message.replyto, "Reloading #{params[:plugin]}"
79
+ else
80
+ reply message.replyto, "\2Error:\2 Failed to find new and stale versions of: #{params[:plugin]}"
81
+ end
82
+ else
83
+ @pipeline << Messages::Internal::PluginReload.new
84
+ @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'Full plugin reload requested')
85
+ end
70
86
  end
71
87
 
72
88
  # message:: ModSpox::Messages::Internal::PluginModuleResponse
@@ -16,10 +16,11 @@ include Messages::Outgoing
16
16
  def active(message, params)
17
17
  triggers = Models::Trigger.filter(:active => true)
18
18
  if(triggers)
19
- @pipeline << Privmsg.new(message.replyto, "\2Currently active triggers:\2")
19
+ output = ["\2Currently active triggers:\2"]
20
20
  triggers.each do |t|
21
- @pipeline << Privmsg.new(message.replyto, "#{t.pk}: #{t.trigger}")
21
+ output << "#{t.pk}: #{t.trigger}"
22
22
  end
23
+ reply message.replyto, output
23
24
  else
24
25
  @pipeline << Privmsg.new(message.replyto, 'No triggers are currently active')
25
26
  end
@@ -28,10 +29,11 @@ include Messages::Outgoing
28
29
  def list(message, params)
29
30
  triggers = Models::Trigger.all
30
31
  if(triggers)
31
- @pipeline << Privmsg.new(message.replyto, "\2Trigger listing:\2")
32
+ output = ["\2Trigger listing:\2"]
32
33
  triggers.each do |t|
33
- @pipeline << Privmsg.new(message.replyto, "#{t.pk}: #{t.trigger} -> \2#{t.active ? "activated" : "not activated"}\2")
34
+ output << "#{t.pk}: #{t.trigger} -> \2#{t.active ? "activated" : "not activated"}\2"
34
35
  end
36
+ reply message.replyto, output
35
37
  else
36
38
  @pipeline << Privmsg.new(message.replyto, 'No triggers found')
37
39
  end
@@ -1,3 +1,5 @@
1
+ require 'mod_spox/Logger'
2
+
1
3
  module ModSpox
2
4
 
3
5
  class Action
@@ -1,3 +1,5 @@
1
+ require 'mod_spox/Exceptions'
2
+
1
3
  module ModSpox
2
4
 
3
5
  class BaseConfig
data/lib/mod_spox/Bot.rb CHANGED
@@ -1,3 +1,14 @@
1
+ ['mod_spox/Logger',
2
+ 'mod_spox/Socket',
3
+ 'mod_spox/Pipeline',
4
+ 'mod_spox/PluginManager',
5
+ 'mod_spox/MessageFactory',
6
+ 'mod_spox/BaseConfig',
7
+ 'mod_spox/Timer',
8
+ 'mod_spox/messages/Messages',
9
+ 'mod_spox/models/Models',
10
+ 'mod_spox/Monitors',
11
+ 'mod_spox/Helpers'].each{|f|require f}
1
12
  module ModSpox
2
13
 
3
14
  class Bot
@@ -36,10 +47,10 @@ module ModSpox
36
47
 
37
48
  # Run the bot
38
49
  def run
39
- trap('SIGTERM'){ Logger.log("Caught SIGTERM"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
40
- trap('SIGKILL'){ Logger.log("Caught SIGKILL"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
41
- trap('SIGINT'){ Logger.log("Caught SIGINT"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
42
- trap('SIGQUIT'){ Logger.log("Caught SIGQUIT"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit }
50
+ trap('SIGTERM'){ Logger.log("Caught SIGTERM"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit; Logger.kill; }
51
+ trap('SIGKILL'){ Logger.log("Caught SIGKILL"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit; Logger.kill; }
52
+ trap('SIGINT'){ Logger.log("Caught SIGINT"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit; Logger.kill; }
53
+ trap('SIGQUIT'){ Logger.log("Caught SIGQUIT"); @shutdown = true; @waiter.wakeup; sleep(0.1); Thread.current.exit; Logger.kill; }
43
54
  until @shutdown do
44
55
  @timer.start
45
56
  @pipeline << Messages::Internal::BotInitialized.new
@@ -126,7 +137,8 @@ module ModSpox
126
137
  :Outgoing_Whois => :whois, :Internal_EstablishConnection => :bot_connect,
127
138
  :Internal_StatusRequest => :status, :Internal_ChangeNick => :set_nick,
128
139
  :Internal_NickRequest => :get_nick, :Internal_HaltBot => :halt,
129
- :Internal_Disconnected => :disconnected, :Internal_TimerClear => :clear_timer
140
+ :Internal_Disconnected => :disconnected, :Internal_TimerClear => :clear_timer,
141
+ :Outgoing_Raw => :raw
130
142
  }.each_pair{ |type,method| @pipeline.hook(self, method, type) }
131
143
  end
132
144
 
@@ -273,7 +285,15 @@ module ModSpox
273
285
  target = message.target.name if message.target.is_a?(Models::Channel)
274
286
  target = message.target.nick if message.target.is_a?(Models::Nick)
275
287
  target = message.target unless target
276
- @socket << "PRIVMSG #{target} :#{message.is_action? ? "\cAACTION #{message.message}\cA" : message.message}"
288
+ messages = message.message.is_a?(Array) ? message.message : [message.message]
289
+ messages.each do |content|
290
+ while(content.size > 450)
291
+ output = content[0..449]
292
+ content.slice!(0, 449) #(450, content.size)
293
+ @socket << "PRIVMSG #{target} :#{message.is_action? ? "\cAACTION #{output}\cA" : output}"
294
+ end
295
+ @socket << "PRIVMSG #{target} :#{message.is_action? ? "\cAACTION #{content}\cA" : content}"
296
+ end
277
297
  end
278
298
 
279
299
  # message:: Messages::Outgoing::Notice message
@@ -458,6 +478,12 @@ module ModSpox
458
478
  @socket << "ISON #{nick}"
459
479
  end
460
480
 
481
+ # message:: Messages::Outoing::Raw message
482
+ # Send raw message to server
483
+ def raw(message)
484
+ @socket << message.message
485
+ end
486
+
461
487
  private
462
488
 
463
489
  # Cleans information from models to avoid
@@ -1,3 +1,6 @@
1
+ require 'etc'
2
+ require 'mod_spox/Exceptions'
3
+
1
4
  module ModSpox
2
5
 
3
6
  class BotConfig
@@ -0,0 +1,57 @@
1
+ module ModSpox
2
+ class Cache
3
+ def initialize(size)
4
+ @size = size
5
+ @cache = Hash.new
6
+ @times = Hash.new
7
+ @store_lock = Mutex.new
8
+ @read_lock = Mutex.new
9
+ end
10
+
11
+ def [](key)
12
+ if(@cache.has_key?(key.to_sym))
13
+ @times[key.to_sym] = Time.now
14
+ return @cache[key.to_sym]
15
+ else
16
+ return nil
17
+ end
18
+ end
19
+
20
+ def has_key?(key)
21
+ @read_lock.synchronize do
22
+ return @cache.has_key?(key.to_sym)
23
+ end
24
+ end
25
+
26
+ def []=(key, value)
27
+ @store_lock.synchronize do
28
+ if(@cache.size > @size)
29
+ del_key = oldest_key
30
+ unless(key.nil?)
31
+ @cache.delete(del_key)
32
+ @times.delete(del_key)
33
+ end
34
+ end
35
+ @cache[key.to_sym] = value
36
+ @times[key.to_sym] = Time.now
37
+ end
38
+ end
39
+
40
+ def delete(key)
41
+ @read_lock.synchronize do
42
+ @cache.delete(key.to_sym) if @cache.has_key?(key.to_sym)
43
+ @times.delete(key.to_sym) if @times.has_key?(key.to_sym)
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def oldest_key
50
+ result = nil
51
+ @read_lock.synchronize do
52
+ result = @times.sort{|a,b| a[1] <=> b[1]}[0][0]
53
+ end
54
+ return result
55
+ end
56
+ end
57
+ end
@@ -1,5 +1,9 @@
1
- ['etc', 'mod_spox/Loader',
2
- 'mod_spox/BotConfig', 'mod_spox/BaseConfig'].each{|f|require f}
1
+ ['etc',
2
+ 'mod_spox/Database',
3
+ 'mod_spox/BotConfig',
4
+ 'mod_spox/BaseConfig'
5
+ 'mod_spox/models/Models',
6
+ 'mod_spox/Helpers'].each{|f|require f}
3
7
 
4
8
 
5
9
  module ModSpox
@@ -1,5 +1,11 @@
1
- require 'timeout'
2
- require 'net/http'
1
+ ['timeout',
2
+ 'net/http',
3
+ 'mod_spox/models/Nick',
4
+ 'mod_spox/models/Channel',
5
+ 'mod_spox/models/Server',
6
+ 'mod_spox/Cache',
7
+ 'mod_spox/Logger'].each{|f|require f}
8
+
3
9
  module ModSpox
4
10
  module Helpers
5
11
  # secs:: number of seconds
@@ -60,48 +66,60 @@ module ModSpox
60
66
  # or channel name. If the string given does not match the required
61
67
  # pattern for a channel or nick, the string is returned.
62
68
  def Helpers.find_model(string, create=true)
63
- @@channel_cache = {} unless Helpers.class_variable_defined?(:@@channel_cache)
64
- @@nick_cache = {} unless Helpers.class_variable_defined?(:@@nick_cache)
69
+ Helpers.initialize_caches
65
70
  if(string =~ /^[A-Za-z\|\\\{\}\[\]\^\`~\_\-]+[A-Za-z0-9\|\\\{\}\[\]\^\`~\_\-]*$/)
66
- Logger.log("Model: #{string} -> Nick")
71
+ Logger.log("Model: #{string} -> Nick", 30)
67
72
  nick = nil
68
- if(@@nick_cache.has_key?(string.to_sym))
73
+ if(@@nick_cache.has_key?(string.downcase.to_sym))
69
74
  begin
70
- nick = Models::Nick[@@nick_cache[string.to_sym]]
75
+ nick = Models::Nick[@@nick_cache[string.downcase.to_sym]]
71
76
  Logger.log("Handler cache hit for nick: #{string}", 30)
77
+ if(nick.nick.downcase != string.downcase)
78
+ Logger.log("Nick returned from cache invalid. Expecting #{string} but got #{nick.nick}", 30)
79
+ nick = nil
80
+ end
72
81
  rescue Object => boom
73
- Logger.log("Failed to grab cached nick: #{boom}")
82
+ Logger.log("Failed to grab cached nick: #{boom}", 30)
74
83
  end
75
84
  end
76
85
  unless(nick)
77
86
  nick = Models::Nick.locate(string, create)
78
- @@nick_cache[string.to_sym] = nick.pk if nick.is_a?(Models::Nick)
79
- Logger.log("Nick was retrieved from database")
87
+ @@nick_cache[string.downcase.to_sym] = nick.pk if nick.is_a?(Models::Nick)
88
+ Logger.log("Nick was retrieved from database", 30)
80
89
  end
81
90
  return nick
82
91
  elsif(string =~ /^[&#+!]/)
83
- Logger.log("Model: #{string} -> Channel")
84
- if(@@channel_cache.has_key?(string.to_sym))
92
+ Logger.log("Model: #{string} -> Channel", 30)
93
+ if(@@channel_cache.has_key?(string.downcase.to_sym))
85
94
  begin
86
- channel = Models::Channel[@@channel_cache[string.to_sym]]
95
+ channel = Models::Channel[@@channel_cache[string.downcase.to_sym]]
87
96
  Logger.log("Handler cache hit for channel: #{string}", 30)
97
+ if(string.downcase != channel.name.downcase)
98
+ Logger.log("Channel returned from cache invalid. Expecting #{string} but got #{channel.name}", 30)
99
+ channel = nil
100
+ end
88
101
  rescue Object => boom
89
- Logger.log("Failed to grab cached channel: #{boom}")
102
+ Logger.log("Failed to grab cached channel: #{boom}", 30)
90
103
  end
91
104
  end
92
105
  unless(channel)
93
106
  channel = Models::Channel.locate(string, create)
94
- @@channel_cache[string.to_sym] = channel.pk if channel.is_a?(Models::Channel)
95
- Logger.log("Channel was retrieved from database")
107
+ @@channel_cache[string.downcase.to_sym] = channel.pk if channel.is_a?(Models::Channel)
108
+ Logger.log("Channel was retrieved from database", 30)
96
109
  end
97
110
  return channel
98
111
  elsif(model = Models::Server.filter(:host => string, :connected => true).first)
99
- Logger.log("Model: #{string} -> Server")
112
+ Logger.log("Model: #{string} -> Server", 30)
100
113
  return model
101
114
  else
102
- Logger.log("FAIL Model: #{string} -> No match")
115
+ Logger.log("FAIL Model: #{string} -> No match", 30)
103
116
  return string
104
117
  end
105
118
  end
119
+
120
+ def Helpers.initialize_caches
121
+ @@nick_cache = Cache.new(20) unless Helpers.class_variable_defined?(:@@nick_cache)
122
+ @@channel_cache = Cache.new(5) unless Helpers.class_variable_defined?(:@@channel_cache)
123
+ end
106
124
  end
107
125
  end
@@ -1,66 +1,17 @@
1
- module ModSpox
1
+ ['mod_spox/Exceptions',
2
+ 'mod_spox/BotConfig',
3
+ 'mod_spox/BaseConfig',
4
+ 'mod_spox/Database'].each{|f|require f}
2
5
 
3
- # directory:: path to directory
4
- # Requires all .rb files found within the given directory
5
- # and all its subdirectories
6
- def load_directory(directory='')
7
- base = File.dirname(__FILE__)
8
- Dir.new("#{base}/#{directory}").each{|item|
9
- next if ['.', '..'].include?(item)
10
- if(File.directory?("#{base}/#{directory}/#{item}"))
11
- load_directory("#{directory}/#{item}")
12
- elsif(item =~ /\.rb$/)
13
- item = "#{directory}/#{item}" if directory.length > 0
14
- begin
15
- require "mod_spox/#{item}"
16
- rescue Object => boom
17
- @@failed << item
18
- end
19
- end
20
- }
21
- @@failed.each{|f|
22
- begin
23
- require "mod_spox/#{f}"
24
- @@failed.delete(f)
25
- rescue Object => boom
26
- # do nothing #
27
- end
28
- }
29
- end
6
+ module ModSpox
30
7
 
31
8
  # Loads all files needed by the bot
32
9
  def initialize_bot
33
10
  setup_adapter
34
- @@failed = Array.new
35
- load_directory
36
- tries = 0
37
- message = nil
38
- until @@failed.empty? || tries > 5 do
39
- @@failed.each{|f|
40
- begin
41
- require "mod_spox/#{f}"
42
- @@failed.delete(f)
43
- rescue Object => boom
44
- message = boom
45
- end
46
- }
47
- tries += 1
48
- end
49
- if(tries > 5)
50
- puts 'Failed'
51
- puts "ERROR: Failed to load required libraries"
52
- puts "Reason: #{message}"
53
- puts "#{message.backtrace.join("\n")}"
54
- exit
55
- end
56
11
  end
57
12
 
58
13
  # Setup the DataMapper adapter
59
14
  def setup_adapter
60
- require 'mod_spox/Exceptions'
61
- require 'mod_spox/BotConfig'
62
- require 'mod_spox/BaseConfig'
63
- require 'mod_spox/Database'
64
15
  memcache = false
65
16
  config = BaseConfig.new(BotConfig[:userconfigpath])
66
17
  if(config[:memcache] == 'on')