mod_spox 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. data/CHANGELOG +31 -1
  2. data/LICENSE +674 -0
  3. data/README.rdoc +73 -0
  4. data/bin/mod_spox +28 -28
  5. data/data/mod_spox/extras/AOLSpeak.rb +2 -3
  6. data/data/mod_spox/extras/AutoKick.rb +10 -23
  7. data/data/mod_spox/extras/AutoMode.rb +12 -23
  8. data/data/mod_spox/extras/Bash.rb +55 -0
  9. data/data/mod_spox/extras/Bouncer.rb +85 -57
  10. data/data/mod_spox/extras/Bullshit.rb +1 -1
  11. data/data/mod_spox/extras/Bytes.rb +1 -2
  12. data/data/mod_spox/extras/Confess.rb +27 -29
  13. data/data/mod_spox/extras/DCC.rb +11 -20
  14. data/data/mod_spox/extras/DevWatch.rb +21 -23
  15. data/data/mod_spox/extras/DownForEveryoneOrJustMe.rb +47 -0
  16. data/data/mod_spox/extras/EightBall.rb +1 -1
  17. data/data/mod_spox/extras/FML.rb +35 -0
  18. data/data/mod_spox/extras/Headers.rb +31 -50
  19. data/data/mod_spox/extras/Karma.rb +81 -29
  20. data/data/mod_spox/extras/Logger.rb +2 -2
  21. data/data/mod_spox/extras/LolSpeak.rb +1 -2
  22. data/data/mod_spox/extras/PhpCli.rb +138 -8
  23. data/data/mod_spox/extras/PhpFuncLookup.rb +20 -23
  24. data/data/mod_spox/extras/Pinger.rb +1 -1
  25. data/data/mod_spox/extras/Quotes.rb +8 -10
  26. data/data/mod_spox/extras/RegexTracker.rb +2 -4
  27. data/data/mod_spox/extras/Roulette.rb +20 -27
  28. data/data/mod_spox/extras/RubyCli.rb +93 -0
  29. data/data/mod_spox/extras/Search.rb +17 -3
  30. data/data/mod_spox/extras/Seen.rb +150 -0
  31. data/data/mod_spox/extras/SlashdotHeadlineGenerator.rb +500 -0
  32. data/data/mod_spox/extras/Talk.rb +2 -4
  33. data/data/mod_spox/extras/Topten.rb +10 -12
  34. data/data/mod_spox/extras/TracTicket.rb +3 -5
  35. data/data/mod_spox/extras/Translate.rb +20 -22
  36. data/data/mod_spox/extras/Twitter.rb +118 -33
  37. data/data/mod_spox/extras/UrbanDictionary.rb +8 -17
  38. data/data/mod_spox/extras/Weather.rb +1 -2
  39. data/data/mod_spox/plugins/Authenticator.rb +93 -98
  40. data/data/mod_spox/plugins/Banner.rb +26 -56
  41. data/data/mod_spox/plugins/Helper.rb +5 -6
  42. data/data/mod_spox/plugins/Initializer.rb +4 -14
  43. data/data/mod_spox/plugins/Joiner.rb +1 -1
  44. data/data/mod_spox/plugins/Nicker.rb +13 -0
  45. data/data/mod_spox/plugins/Parter.rb +2 -2
  46. data/data/mod_spox/plugins/Permissions.rb +60 -0
  47. data/data/mod_spox/plugins/PluginLoader.rb +7 -12
  48. data/data/mod_spox/plugins/Ponger.rb +51 -0
  49. data/data/mod_spox/plugins/Quitter.rb +1 -2
  50. data/data/mod_spox/plugins/Servers.rb +57 -0
  51. data/data/mod_spox/plugins/Status.rb +3 -2
  52. data/data/mod_spox/plugins/Triggers.rb +9 -9
  53. data/lib/mod_spox/Bot.rb +109 -33
  54. data/lib/mod_spox/BotConfig.rb +2 -2
  55. data/lib/mod_spox/ConfigurationWizard.rb +12 -12
  56. data/lib/mod_spox/Database.rb +1 -4
  57. data/lib/mod_spox/Exceptions.rb +26 -0
  58. data/lib/mod_spox/Helpers.rb +29 -68
  59. data/lib/mod_spox/Loader.rb +23 -24
  60. data/lib/mod_spox/Logger.rb +19 -17
  61. data/lib/mod_spox/MessageFactory.rb +50 -24
  62. data/lib/mod_spox/Pipeline.rb +21 -7
  63. data/lib/mod_spox/Plugin.rb +27 -3
  64. data/lib/mod_spox/PluginManager.rb +28 -15
  65. data/lib/mod_spox/PriorityQueue.rb +69 -0
  66. data/lib/mod_spox/Socket.rb +93 -51
  67. data/lib/mod_spox/Sockets.rb +76 -63
  68. data/lib/mod_spox/Timer.rb +21 -141
  69. data/lib/mod_spox/Version.rb +14 -0
  70. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  71. data/lib/mod_spox/handlers/Bounce.rb +5 -5
  72. data/lib/mod_spox/handlers/Created.rb +13 -5
  73. data/lib/mod_spox/handlers/Handler.rb +12 -3
  74. data/lib/mod_spox/handlers/Invite.rb +14 -8
  75. data/lib/mod_spox/handlers/Join.rb +24 -20
  76. data/lib/mod_spox/handlers/Kick.rb +22 -13
  77. data/lib/mod_spox/handlers/Mode.rb +42 -36
  78. data/lib/mod_spox/handlers/Motd.rb +4 -0
  79. data/lib/mod_spox/handlers/Names.rb +66 -39
  80. data/lib/mod_spox/handlers/Nick.rb +20 -14
  81. data/lib/mod_spox/handlers/Part.rb +25 -8
  82. data/lib/mod_spox/handlers/Ping.rb +11 -5
  83. data/lib/mod_spox/handlers/Pong.rb +9 -5
  84. data/lib/mod_spox/handlers/Privmsg.rb +25 -17
  85. data/lib/mod_spox/handlers/Quit.rb +13 -8
  86. data/lib/mod_spox/handlers/Topic.rb +4 -0
  87. data/lib/mod_spox/handlers/Welcome.rb +16 -24
  88. data/lib/mod_spox/handlers/Who.rb +64 -48
  89. data/lib/mod_spox/handlers/Whois.rb +92 -60
  90. data/lib/mod_spox/messages/incoming/Nick.rb +2 -2
  91. data/lib/mod_spox/messages/incoming/Privmsg.rb +1 -1
  92. data/lib/mod_spox/messages/incoming/Whois.rb +1 -0
  93. data/lib/mod_spox/messages/internal/EstablishConnection.rb +1 -1
  94. data/lib/mod_spox/messages/internal/PluginsReady.rb +10 -0
  95. data/lib/mod_spox/messages/internal/QueueSocket.rb +8 -0
  96. data/lib/mod_spox/messages/internal/Reconnect.rb +8 -0
  97. data/lib/mod_spox/messages/internal/UnqueueSocket.rb +8 -0
  98. data/lib/mod_spox/migrations/002_persistent_sigs.rb +14 -0
  99. data/lib/mod_spox/migrations/003_auth_restructure.rb +31 -0
  100. data/lib/mod_spox/migrations/004_mode_index_fix.rb +18 -0
  101. data/lib/mod_spox/migrations/005_nick_mode_nopark.rb +18 -0
  102. data/lib/mod_spox/models/Auth.rb +16 -46
  103. data/lib/mod_spox/models/AuthMask.rb +13 -0
  104. data/lib/mod_spox/models/Channel.rb +46 -27
  105. data/lib/mod_spox/models/Config.rb +10 -19
  106. data/lib/mod_spox/models/Group.rb +20 -8
  107. data/lib/mod_spox/models/Models.rb +1 -1
  108. data/lib/mod_spox/models/Nick.rb +105 -113
  109. data/lib/mod_spox/models/NickMode.rb +23 -9
  110. data/lib/mod_spox/models/Server.rb +12 -1
  111. data/lib/mod_spox/models/Setting.rb +12 -16
  112. data/lib/mod_spox/models/Signature.rb +28 -8
  113. data/tests/BotHolder.rb +24 -0
  114. data/tests/handlers/tc_BadNick.rb +21 -0
  115. data/tests/handlers/tc_Created.rb +24 -0
  116. data/tests/handlers/tc_Invite.rb +50 -0
  117. data/tests/handlers/tc_Join.rb +33 -0
  118. data/tests/handlers/tc_Kick.rb +32 -0
  119. data/tests/handlers/tc_Mode.rb +85 -0
  120. data/tests/handlers/tc_Names.rb +35 -0
  121. data/tests/handlers/tc_Nick.rb +55 -0
  122. data/tests/handlers/tc_Part.rb +44 -0
  123. data/tests/handlers/tc_Ping.rb +40 -0
  124. data/tests/handlers/tc_Pong.rb +28 -0
  125. data/tests/handlers/tc_Privmsg.rb +85 -0
  126. data/tests/handlers/tc_Quit.rb +40 -0
  127. data/tests/handlers/tc_Who.rb +50 -0
  128. data/tests/handlers/tc_Whois.rb +61 -0
  129. data/tests/models/tc_Auth.rb +34 -0
  130. data/tests/models/tc_Channel.rb +52 -0
  131. data/tests/models/tc_Config.rb +19 -0
  132. data/tests/models/tc_Nick.rb +142 -0
  133. data/tests/models/tc_NickMode.rb +40 -0
  134. data/tests/models/tc_Setting.rb +21 -0
  135. data/tests/models/tc_Signature.rb +14 -0
  136. data/tests/run_tests.rb +4 -0
  137. metadata +284 -212
  138. data/README +0 -36
  139. data/lib/mod_spox/Cache.rb +0 -57
  140. data/lib/mod_spox/Monitors.rb +0 -84
  141. data/lib/mod_spox/Pool.rb +0 -164
  142. data/lib/mod_spox/models/AuthGroup.rb +0 -16
  143. data/lib/mod_spox/models/ChannelMode.rb +0 -14
  144. data/lib/mod_spox/models/NickChannel.rb +0 -45
  145. data/lib/mod_spox/models/NickGroup.rb +0 -16
@@ -4,17 +4,15 @@ class Helper < ModSpox::Plugin
4
4
 
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
- Signature.find_or_create(:signature => 'help', :plugin => name, :method => 'default_help',
8
- :description => 'Display default help information')
9
- Signature.find_or_create(:signature => 'help (\S+)', :plugin => name, :method => 'plugin_help',
10
- :description => 'Display help information from given plugin').params = [:plugin]
7
+ add_sig(:sig => 'help', :method => :default_help, :desc => 'Display default help information')
8
+ add_sig(:sig => 'help (\S+)', :method => :plugin_help, :desc => 'Display help information from given plugin', :params => [:plugin])
11
9
  end
12
10
 
13
11
  def default_help(message, params)
14
12
  plugins = Signature.select(:plugin).map(:plugin)
15
13
  plugins.uniq!
16
14
  reply message.replyto, "Plugins currently available for help: #{plugins.sort.join(', ')}"
17
- reply message.replyto, "Request help on a plugin: !help Plugin"
15
+ reply message.replyto, "Request help on a plugin: #{Models::Trigger.filter(:active => true).first.trigger}help Plugin"
18
16
  end
19
17
 
20
18
  def plugin_help(message, params)
@@ -29,6 +27,7 @@ class Helper < ModSpox::Plugin
29
27
  help << "\2Parameters:\2 [#{sig.params.join(' | ')}]" if sig.params
30
28
  help << "\2Auth Group:\2 #{Group[sig.group_id].name}" if sig.group_id
31
29
  help << "\2Description:\2 #{sig.description}" if sig.description
30
+ help << "\2Requirement:\2 #{['public', 'private'].include?(sig.requirement) ? sig.requirement : 'both'}"
32
31
  output << help.join(' ')
33
32
  end
34
33
  if(message.is_dcc?)
@@ -37,7 +36,7 @@ class Helper < ModSpox::Plugin
37
36
  reply message.source, output
38
37
  end
39
38
  else
40
- Signature.all.each{|s| sigs << s.plugin if /#{s.signature.gsub(/\s.*$/, '')}/ =~ params[:plugin]}
39
+ Signature.all.each{|s| sigs << s.plugin if /#{s.signature.gsub(/(\s|\().*$/, '')}/ =~ params[:plugin]}
41
40
  if(sigs.count > 0)
42
41
  sigs.uniq!
43
42
  reply message.replyto, "Possible plugin matches for \2#{params[:plugin]}\2: #{sigs.sort.join(', ')}"
@@ -12,30 +12,20 @@ class Initializer < ModSpox::Plugin
12
12
  # message:: ModSpox::Messages::Internal::BotInitialized
13
13
  # Instructs bot to connect to server
14
14
  def connect(message)
15
- populate_servers if @servers.empty?
16
- s = @servers.pop
17
- @pipeline << Messages::Internal::EstablishConnection.new(s.host, s.port)
15
+ @pipeline << Messages::Internal::EstablishConnection.new
18
16
  end
19
17
 
20
18
  # message:: ModSpox::Messages::Internal::Connected
21
19
  # Send bot information to server when connection is established
22
20
  def send_info(message)
23
- @pipeline << Messages::Outgoing::Nick.new(Models::Config[:bot_nick])
24
- @pipeline << Messages::Outgoing::User.new(Models::Config[:bot_username], Models::Config[:bot_realname], 8)
21
+ @pipeline << Messages::Outgoing::Nick.new(Models::Config.val(:bot_nick))
22
+ @pipeline << Messages::Outgoing::User.new(Models::Config.val(:bot_username), Models::Config.val(:bot_realname), 8)
25
23
  end
26
24
 
27
25
  # message:: ModSpox::Messages::Internal::ConnectionFailed or ModSpox::Messages::Internal::Disconnected
28
26
  # Reconnect to server on disconnection or connection failure
29
27
  def reconnect(message)
30
- @pipeline << Messages::Internal::TimerAdd.new(self, Models::Config[:reconnect_wait].to_i, nil, true){ connect(nil) }
31
- end
32
-
33
- private
34
-
35
- def populate_servers
36
- Models::Server.reverse_order(:priority).each{|s|
37
- @servers << s
38
- }
28
+ @pipeline << Messages::Internal::Reconnect.new
39
29
  end
40
30
 
41
31
  end
@@ -2,7 +2,7 @@ class Joiner < ModSpox::Plugin
2
2
  def initialize(pipeline)
3
3
  super(pipeline)
4
4
  admin = Models::Group.filter(:name => 'admin').first
5
- Models::Signature.find_or_create(:signature => 'join (\S+)', :plugin => name, :method => 'join', :group_id => admin.pk).params = [:channel]
5
+ add_sig(:sig => 'join (\S+)', :method => :join, :group => admin, :params => [:channel])
6
6
  @pipeline.hook(self, :send_who, :Incoming_Join)
7
7
  end
8
8
 
@@ -0,0 +1,13 @@
1
+ class Nicker < ModSpox::Plugin
2
+ def initialize(pipeline)
3
+ super(pipeline)
4
+ admin = Models::Group.filter(:name => 'admin').first
5
+ add_sig(:sig => 'nick (\S+)', :method => :change_nick, :group => admin, :params => [:nick])
6
+ end
7
+
8
+ # message:: ModSpox::Messages::Incoming::Privmsg
9
+ # Join the given channel
10
+ def change_nick(message, params)
11
+ @pipeline << Messages::Outgoing::Nick.new(params[:nick])
12
+ end
13
+ end
@@ -3,8 +3,8 @@ class Parter < ModSpox::Plugin
3
3
  def initialize(pipeline)
4
4
  super(pipeline)
5
5
  admin = Models::Group.filter(:name => 'admin').first
6
- Models::Signature.find_or_create(:signature => 'part (\S+)', :plugin => name, :method => 'part', :group_id => admin.pk).params = [:channel]
7
- Models::Signature.find_or_create(:signature => 'part', :plugin => name, :method => 'direct_part', :group_id => admin.pk)
6
+ add_sig(:sig => 'part (\S+)', :method => :part, :group => admin, :params => [:channel])
7
+ add_sig(:sig => 'part', :method => :direct_part, :group => admin)
8
8
  end
9
9
 
10
10
  # message:: ModSpox::Messages::Incoming::Privmsg
@@ -0,0 +1,60 @@
1
+ class Permissions < ModSpox::Plugin
2
+
3
+ def initialize(pipe)
4
+ super
5
+ admin = Models::Group.find_or_create(:name => 'admin')
6
+ add_sig(:sig => 'perm (\S+)', :group => admin, :method => :show_perm, :desc => 'Display permissions for plugin', :params => [:plugin])
7
+ add_sig(:sig => 'perm (\d+) (\S+)', :group => admin, :method => :set_perm, :desc => 'Sets permission for signature with given ID', :params => [:id, :group])
8
+ add_sig(:sig => 'group add (\S+)', :group => admin, :method => :add_group, :desc => 'Add a new authentication group', :params => [:group])
9
+ add_sig(:sig => 'invalid', :group => admin, :method => :invalid, :desc => 'foobar')
10
+ end
11
+
12
+ def show_perm(m, params)
13
+ output = ["Permissions for signatures owned by \2#{params[:plugin]}\2"]
14
+ Models::Signature.filter(:plugin => params[:plugin]).each do |s|
15
+ g = s.group
16
+ output << "[#{s.pk}] \2#{g.is_a?(Models::Group) ? g.name : 'unset'}\2 - #{s.signature} - #{s.description}"
17
+ end
18
+ if(output.size > 1)
19
+ reply m.replyto, output
20
+ else
21
+ error m.replyto, "Failed to locate signatures for given plugin: #{params[:plugin]}"
22
+ end
23
+ end
24
+
25
+ def set_perm(m, params)
26
+ s = Models::Signature[params[:id].to_i]
27
+ if(s)
28
+ if(params[:group] == 'none')
29
+ g = true
30
+ else
31
+ g = Models::Group.filter(:name => params[:group]).first
32
+ end
33
+ if(g)
34
+ s.group_id = g.is_a?(Models::Group) ? g.pk : nil
35
+ s.save
36
+ information m.replyto, "Signature with ID #{s.pk} has been updated to group: #{g.is_a?(Models::Group) ? g.name : 'unset'}"
37
+ else
38
+ error m.replyto, "Group name is invalid. If it is a new group, add it first. (#{params[:group]})"
39
+ end
40
+ else
41
+ error m.replyto, "Failed to find signature with ID: #{params[:id]}"
42
+ end
43
+ end
44
+
45
+ def add_group(m, params)
46
+ begin
47
+ raise 'Invalid group name: none' if params[:group] == 'none'
48
+ Models::Group.find_or_create(:name => params[:group])
49
+ information m.replyto, "New group \2#{params[:group]}\2 is now available"
50
+ rescue Object => boom
51
+ error m.replyto, "Unknown error when adding new group: #{params[:group]}"
52
+ end
53
+ end
54
+
55
+ def invalid(m, params)
56
+ Models::Signature.dataset.update(:enabled => false)
57
+ information m.replyto, 'ok'
58
+ end
59
+
60
+ end
@@ -3,16 +3,11 @@ class PluginLoader < ModSpox::Plugin
3
3
  def initialize(pipeline)
4
4
  super(pipeline)
5
5
  admin = Models::Group.filter(:name => 'admin').first
6
- Models::Signature.find_or_create(:signature => 'plugins available', :plugin => name, :method => 'available_plugins',
7
- :group_id => admin.pk, :description => 'List all available plugins')
8
- Models::Signature.find_or_create(:signature => 'plugins loaded', :plugin => name, :method => 'loaded_plugins',
9
- :group_id => admin.pk, :description => 'List all plugins currently loaded')
10
- Models::Signature.find_or_create(:signature => 'plugins load (\S+)', :plugin => name, :method => 'load_plugin',
11
- :group_id => admin.pk, :description => 'Load the given plugin').params = [:plugin]
12
- Models::Signature.find_or_create(:signature => 'plugins unload (\S+)', :plugin => name, :method => 'unload_plugin',
13
- :group_id => admin.pk, :description => 'Unload given plugin').params = [:plugin]
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]
6
+ add_sig(:sig => 'plugins available', :method => :available_plugins, :group => admin, :desc => 'List all available plugins')
7
+ add_sig(:sig => 'plugins loaded', :method => :loaded_plugins, :group => admin, :desc => 'List all plugins currently loaded')
8
+ add_sig(:sig => 'plugins load (\S+)', :method => :load_plugin, :group => admin, :desc => 'Load the given plugin', :params => [:plugin])
9
+ add_sig(:sig => 'plugins unload (\S+)', :method => :unload_plugin, :group => admin, :desc => 'Unload given plugin', :params => [:plugin])
10
+ add_sig(:sig => 'plugins reload ?(\S+)?', :method => :reload_plugin, :group => admin, :desc => 'Reload single plugin or all plugins if names not provided', :params => [:plugin])
16
11
  @pipeline.hook(self, :get_module, :Internal_PluginModuleResponse)
17
12
  @plugins_mod = nil
18
13
  end
@@ -93,7 +88,7 @@ class PluginLoader < ModSpox::Plugin
93
88
 
94
89
  # Upgrades extra plugins to latest version
95
90
  def extras_upgrade
96
- Logger.info("Starting plugin upgrade to current version: #{$BOTVERSION}")
91
+ Logger.info("Starting plugin upgrade to current version: #{ModSpox.botversion}")
97
92
  extras = plugin_discovery(BotConfig[:pluginextraspath])
98
93
  pl = plugin_list
99
94
  extras.keys.each{|d| extras.delete(d) unless pl.include?(d)}
@@ -107,7 +102,7 @@ class PluginLoader < ModSpox::Plugin
107
102
  extras.each do |name, path|
108
103
  @pipeline << Messages::Internal::PluginLoadRequest.new(self, path)
109
104
  end
110
- Logger.info("Plugin upgrade is now complete. Upgraded to version: #{$BOTVERSION}")
105
+ Logger.info("Plugin upgrade is now complete. Upgraded to version: #{ModSpox.botversion}")
111
106
  end
112
107
 
113
108
  private
@@ -2,7 +2,16 @@ class Ponger < ModSpox::Plugin
2
2
 
3
3
  def initialize(pipeline)
4
4
  super(pipeline)
5
+ @lag = nil
6
+ @last = nil
7
+ @attempts = 0
8
+ add_sig(:sig => 'lag', :method => :print_lag, :desc => 'Shows bot\'s current lag to server')
5
9
  @pipeline.hook(self, :ping, :Incoming_Ping)
10
+ @pipeline.hook(self, :get_lag_pong, :Incoming_Pong)
11
+ @lock = Mutex.new
12
+ @pipeline.hook(self, :check_start_ponger, :Internal_PluginsReady)
13
+ @running = false
14
+ send_lag_ping
6
15
  end
7
16
 
8
17
  # message:: ModSpox::Messages::Incoming::Ping
@@ -10,5 +19,47 @@ class Ponger < ModSpox::Plugin
10
19
  def ping(message)
11
20
  @pipeline << Messages::Outgoing::Pong.new(message.server, message.string)
12
21
  end
22
+
23
+ def send_lag_ping
24
+ if(@attempts > 5)
25
+ @pipeline << Messages::Internal::Reconnect.new
26
+ @lag = nil
27
+ @last = nil
28
+ @attempts = 0
29
+ else
30
+ t = Time.now
31
+ @last = t.to_f.to_s
32
+ @pipeline << Messages::Outgoing::Ping.new("#{@last}")
33
+ @attempts += 1
34
+ end
35
+ end
36
+
37
+ def get_lag_pong(m)
38
+ @lock.synchronize do
39
+ t = m.string.to_f
40
+ return unless m.string == @last
41
+ @lag = Time.now.to_f - t
42
+ @last = nil
43
+ @attempts = 0
44
+ end
45
+ end
46
+
47
+ def print_lag(m, params)
48
+ if(@lag.nil?)
49
+ warning m.replyto, 'Lag time currently unavailable'
50
+ else
51
+ information m.replyto, "Current lag time: #{sprintf('%0.4f', @lag)} seconds"
52
+ end
53
+ end
54
+
55
+ def start_ponger(m)
56
+ @running = true
57
+ send_lag_ping
58
+ @pipeline << Messages::Internal::TimerAdd.new(self, 60){ send_lag_ping }
59
+ end
60
+
61
+ def check_start_ponger(m)
62
+ @pipeline << Messages::Internal::TimerAdd.new(self, 30, nil, true){ @lock.synchronize{start_ponger(nil) unless @running} }
63
+ end
13
64
 
14
65
  end
@@ -2,8 +2,7 @@ class Quitter < ModSpox::Plugin
2
2
 
3
3
  def initialize(pipeline)
4
4
  super(pipeline)
5
- Models::Signature.find_or_create(:signature => 'quit(\s.+)?', :plugin => name, :method => 'quit',
6
- :group_id => Models::Group.filter(:name => 'admin').first.pk).params = [:channel, :message]
5
+ add_sig(:sig => 'quit(\s.+)?', :method => :quit, :group => Models::Group.filter(:name => 'admin').first, :params => [:channel, :message])
7
6
  end
8
7
 
9
8
  # message:: ModSpox::Messages::Incoming::Privmsg
@@ -0,0 +1,57 @@
1
+ class Servers < ModSpox::Plugin
2
+ def initialize(pipeline)
3
+ super
4
+ admin = Models::Group.find_or_create(:name => 'admin')
5
+ add_sig(:sig => 'servers list', :method => :list, :group => admin, :desc => 'Show server list')
6
+ add_sig(:sig => 'servers add (\S+) (\d+)( \d+)?', :method => :add, :group => admin, :desc => 'Add server to list', :params => [:server, :port, :prio])
7
+ add_sig(:sig => 'servers del (\d+)', :method => :remove, :group => admin, :desc => 'Remove server from list', :params => [:id])
8
+ add_sig(:sig => 'servers prio (\d+) (\+|\-|\d+)', :method => :prio, :group => admin, :desc => 'Prioritize server', :params => [:id, :move])
9
+ end
10
+
11
+ def list(m, params)
12
+ output = ["\2Server list:\2"]
13
+ Models::Server.reverse_order(:priority).each do |s|
14
+ output << "\2[#{s.id}]\2 #{s.host}:#{s.port} \2Priority:\2 #{s.priority}"
15
+ end
16
+ reply m.replyto, output
17
+ end
18
+
19
+ def add(m, params)
20
+ begin
21
+ s = Models::Server.new(:host => params[:server], :port => params[:port].to_i)
22
+ s.priority = params[:prio].to_i if params[:prio]
23
+ s.save
24
+ information m.replyto, "New server has been added: #{params[:server]}:#{params[:port]}"
25
+ rescue Object => boom
26
+ error m.replyto, "Failed to add new server. Reason: #{boom}"
27
+ end
28
+ end
29
+
30
+ def remove(m, params)
31
+ begin
32
+ raise "List must contain one server" unless Models::Server.count > 1
33
+ Models::Server[params[:id].to_i].destroy
34
+ information m.replyto, 'Server has been removed'
35
+ rescue Object => boom
36
+ error m.replyto, "Failed to remove server. Reason: #{boom}"
37
+ end
38
+ end
39
+
40
+ def prio(m, params)
41
+ begin
42
+ s = Models::Server[params[:id].to_i]
43
+ if(params[:move] == '+')
44
+ s.priority += 1
45
+ elsif(params[:move] == '-')
46
+ s.priority -= 1 if s.priority > 0
47
+ else
48
+ s.priority = params[:move].to_i
49
+ end
50
+ s.save_changes
51
+ information m.replyto, 'Server priority has been updated.'
52
+ rescue Object => boom
53
+ error m.replyto, "Failed to update priority. Reason: #{boom}"
54
+ end
55
+ end
56
+
57
+ end
@@ -4,6 +4,7 @@ class Status < ModSpox::Plugin
4
4
  super
5
5
  add_sig(:sig => 'status', :method => :status, :desc => 'Show current status')
6
6
  add_sig(:sig => 'version', :method => :version, :desc => 'Show version information')
7
+ add_sig(:sig => 'VERSION', :method => :version, :desc => 'Show version information')
7
8
  @pipeline.hook(self, :get_status, :Internal_StatusResponse)
8
9
  @resp = []
9
10
  end
@@ -14,13 +15,13 @@ class Status < ModSpox::Plugin
14
15
  end
15
16
 
16
17
  def version(message, params)
17
- reply message.replyto, "mod_spox IRC bot - Version: \2#{$BOTVERSION}\2 (#{$BOTCODENAME}) [http://modspox.rubyforge.org]"
18
+ reply message.replyto, "mod_spox IRC bot - Version: \2#{ModSpox.botversion}\2 (#{ModSpox.botcodename}) [http://modspox.rubyforge.org]"
18
19
  end
19
20
 
20
21
  def get_status(m)
21
22
  @resp.uniq!
22
23
  @resp.each do |c|
23
- reply c, "\2Status:\2 \2Uptime:\2 #{m.status[:uptime]} \2Plugins:\2 #{m.status[:plugins]} loaded \2Lines sent:\2 #{m.status[:sent]} \2Lines Received:\2 #{m.status[:received]}"
24
+ reply c, "\2Status:\2 \2Uptime:\2 #{m.status[:uptime]} \2Plugins:\2 #{m.status[:plugins]} loaded \2Socket Connected:\2 #{m.status[:socket_connect].strftime("%Y/%m/%d-%H:%M:%S")} \2Lines sent:\2 #{m.status[:sent]} \2Lines Received:\2 #{m.status[:received]}"
24
25
  @resp.delete(c)
25
26
  end
26
27
  end
@@ -5,12 +5,12 @@ include Messages::Outgoing
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
7
  admin = Models::Group.filter(:name => 'admin').first
8
- Models::Signature.find_or_create(:signature => 'triggers active', :plugin => name, :method => 'active', :group_id => admin.pk, :description => 'List all currently active triggers')
9
- Models::Signature.find_or_create(:signature => 'triggers list', :plugin => name, :method => 'list', :group_id => admin.pk, :description => 'List all triggers and their current status')
10
- Models::Signature.find_or_create(:signature => 'triggers add (\S+)', :plugin => name, :method => 'add', :group_id => admin.pk, :description => 'Add a new trigger and activate it').params = [:trigger]
11
- Models::Signature.find_or_create(:signature => 'triggers remove (\d+)', :plugin => name, :method => 'remove', :group_id => admin.pk, :description => 'Remove trigger').params = [:id]
12
- Models::Signature.find_or_create(:signature => 'triggers activate (\d+)', :plugin => name, :method => 'activate', :group_id => admin.pk, :description => 'Activate the trigger').params = [:id]
13
- Models::Signature.find_or_create(:signature => 'triggers deactivate (\d+)', :plugin => name, :method => 'deactivate', :group_id => admin.pk, :description => 'Deactivate the trigger').params = [:id]
8
+ add_sig(:sig => 'triggers active', :method => :active, :group => admin, :desc => 'List all currently active triggers')
9
+ add_sig(:sig => 'triggers list', :method => :list, :group => admin, :desc => 'List all triggers and their current status')
10
+ add_sig(:sig => 'triggers add (\S+)', :method => :add, :group => admin, :desc => 'Add a new trigger and activate it', :params => [:trigger])
11
+ add_sig(:sig => 'triggers remove (\d+)', :method => :remove, :group => admin, :desc => 'Remove trigger', :params => [:id])
12
+ add_sig(:sig => 'triggers activate (\d+)', :method => :activate, :group => admin, :desc => 'Activate the trigger', :params => [:id])
13
+ add_sig(:sig => 'triggers deactivate (\d+)', :method => :deactivate, :group => admin, :desc => 'Deactivate the trigger', :params => [:id])
14
14
  end
15
15
 
16
16
  def active(message, params)
@@ -40,7 +40,7 @@ include Messages::Outgoing
40
40
  end
41
41
 
42
42
  def add(message, params)
43
- Models::Trigger.find_or_create(:trigger => params[:trigger]).update_with_params(:active => true)
43
+ Models::Trigger.find_or_create(:trigger => params[:trigger]).update(:active => true)
44
44
  @pipeline << Privmsg.new(message.replyto, "Trigger #{params[:trigger]} is now active")
45
45
  @pipeline << Messages::Internal::TriggersUpdate.new
46
46
  end
@@ -60,7 +60,7 @@ include Messages::Outgoing
60
60
  def activate(message, params)
61
61
  trigger = Models::Trigger[params[:id]]
62
62
  if(trigger)
63
- trigger.update_with_params(:active => true)
63
+ trigger.update(:active => true)
64
64
  @pipeline << Privmsg.new(message.replyto, "Trigger #{trigger.trigger} has been activated")
65
65
  @pipeline << Messages::Internal::TriggersUpdate.new
66
66
  else
@@ -71,7 +71,7 @@ include Messages::Outgoing
71
71
  def deactivate(message, params)
72
72
  trigger = Models::Trigger[params[:id]]
73
73
  if(trigger)
74
- trigger.update_with_params(:active => false)
74
+ trigger.update(:active => false)
75
75
  @pipeline << Privmsg.new(message.replyto, "Trigger #{trigger.trigger} has been deactivated")
76
76
  @pipeline << Messages::Internal::TriggersUpdate.new
77
77
  else
@@ -4,17 +4,22 @@
4
4
  'mod_spox/PluginManager',
5
5
  'mod_spox/MessageFactory',
6
6
  'mod_spox/BaseConfig',
7
- 'mod_spox/Timer',
8
7
  'mod_spox/messages/Messages',
9
8
  'mod_spox/models/Models',
10
9
  'mod_spox/Helpers',
11
- 'mod_spox/Pool'].each{|f|require f}
10
+ 'mod_spox/Timer'].each{|f|require f}
11
+ require 'actionpool'
12
+ require 'actiontimer'
13
+
12
14
  module ModSpox
13
15
 
14
16
  class Bot
15
17
 
16
18
  # bot timer
17
19
  attr_reader :timer
20
+
21
+ # thread pool
22
+ attr_reader :pool
18
23
 
19
24
  # message pipeline
20
25
  attr_reader :pipeline
@@ -30,15 +35,19 @@ module ModSpox
30
35
 
31
36
  # Create a Bot
32
37
  def initialize
33
- Logger.initialize($LOGTO, $LOGLEVEL)
34
- Pool.instance
38
+ unless(ModSpox.logto.nil?)
39
+ logger = ::Logger.new(ModSpox.logto, 'daily')
40
+ Logger.initialize(logger, ModSpox.loglevel)
41
+ end
35
42
  clean_models
43
+ @servers = Array.new
44
+ @channels = Array.new
36
45
  @start_time = Time.now
37
- @pipeline = Pipeline.new
38
- @timer = Timer.new(@pipeline)
39
- @timer.start
46
+ @pool = ActionPool::Pool.new(10, 100, 60, nil, logger)
47
+ @pipeline = Pipeline.new(@pool)
48
+ @timer = Timer.new(ActionTimer::Timer.new(@pool, logger), @pipeline)
40
49
  @config = BaseConfig.new(BotConfig[:userconfigpath])
41
- @factory = MessageFactory.new(@pipeline)
50
+ @factory = MessageFactory.new(@pipeline, @pool)
42
51
  @socket = nil
43
52
  @plugin_manager = PluginManager.new(@pipeline)
44
53
  if(@config[:plugin_upgrade] == 'yes')
@@ -60,10 +69,10 @@ module ModSpox
60
69
 
61
70
  # Run the bot
62
71
  def run
63
- trap('SIGTERM'){ Logger.warn("Caught SIGTERM"); start_shutdown }
64
- trap('SIGKILL'){ Logger.warn("Caught SIGKILL"); start_shutdown }
65
- trap('SIGINT'){ Logger.warn("Caught SIGINT"); start_shutdown }
66
- trap('SIGQUIT'){ Logger.warn("Caught SIGQUIT"); start_shutdown }
72
+ trap('SIGTERM'){ Logger.warn("Caught SIGTERM"); halt }
73
+ trap('SIGKILL'){ Logger.warn("Caught SIGKILL"); halt }
74
+ trap('SIGINT'){ Logger.warn("Caught SIGINT"); halt }
75
+ trap('SIGQUIT'){ Logger.warn("Caught SIGQUIT"); halt }
67
76
  until @shutdown do
68
77
  @pipeline << Messages::Internal::BotInitialized.new
69
78
  begin
@@ -106,10 +115,28 @@ module ModSpox
106
115
  begin
107
116
  @socket = Sockets.new(self) if @socket.nil?
108
117
  @socket.irc_connect(message.server, message.port)
109
- @pipeline << Messages::Internal::Connected.new(message.server, message.port)
110
118
  rescue Object => boom
111
119
  Logger.warn("Failed connection to server: #{boom}")
112
- @pipeline << Messages::Internal::ConnectionFailed.new(message.server, message.port)
120
+ @pipeline << Messages::Internal::ConnectionFailed.new(@socket.irc_socket.server, @socket.irc_socket.port)
121
+ end
122
+ end
123
+
124
+ # message:: Messages::Internal::Reconnect
125
+ # instructs bot to reconnect to IRC server
126
+ def reconnect(message=nil)
127
+ begin
128
+ @plugin_manager.reload_plugins
129
+ @socket.irc_reconnect
130
+ rescue Object => boom
131
+ Logger.warn("Initial reconnect failed. (#{boom}) Starting timed reconnect process.")
132
+ begin
133
+ @socket.irc_reconnect
134
+ rescue Object => boom
135
+ Logger.warn("Failed to connect to server. Reason: #{boom}")
136
+ Logger.warn("Will retry in 20 seconds")
137
+ sleep(20)
138
+ retry
139
+ end
113
140
  end
114
141
  end
115
142
 
@@ -123,6 +150,7 @@ module ModSpox
123
150
  def bot_stats
124
151
  return {:uptime => Helpers::format_seconds(Time.now - @start_time),
125
152
  :plugins => @plugin_manager.plugins.size,
153
+ :socket_connect => @socket.irc_socket.connected_at,
126
154
  :sent => @socket.irc_socket.sent,
127
155
  :received => @socket.irc_socket.received}
128
156
  end
@@ -154,7 +182,8 @@ module ModSpox
154
182
  :Internal_StatusRequest => :status, :Internal_ChangeNick => :set_nick,
155
183
  :Internal_NickRequest => :get_nick, :Internal_HaltBot => :halt,
156
184
  :Internal_Disconnected => :disconnected, :Internal_TimerClear => :clear_timer,
157
- :Outgoing_Raw => :raw
185
+ :Outgoing_Raw => :raw, :Internal_Reconnect => :reconnect,
186
+ :Incoming_Join => :check_join, :Incoming_Part => :check_part
158
187
  }.each_pair{ |type,method| @pipeline.hook(self, method, type) }
159
188
  end
160
189
 
@@ -167,12 +196,11 @@ module ModSpox
167
196
  # message:: Messages::Internal::Disconnected
168
197
  # Disconnect the bot from the IRC server
169
198
  def disconnected(message)
170
- @socket.shutdown
171
- @socket = nil
199
+ reload
172
200
  end
173
201
 
174
202
  # Stop the bot
175
- def halt(message)
203
+ def halt(message=nil)
176
204
  @shutdown = true
177
205
  reload
178
206
  end
@@ -282,6 +310,7 @@ module ModSpox
282
310
  # message:: Messages::Outgoing::Invite message
283
311
  # Sends INVITE message to server
284
312
  def invite(message)
313
+ okay_to_send(message.channel)
285
314
  nick = message.nick.is_a?(Models::Nick) ? message.nick.nick : message.nick
286
315
  channel = message.channel.is_a?(Models::Channel) ? message.channel.name : message.channel
287
316
  @socket << "INVITE #{nick} #{channel}"
@@ -290,6 +319,7 @@ module ModSpox
290
319
  # message:: Messages::Outgoing::Kick message
291
320
  # Sends KICK message to server
292
321
  def kick(message)
322
+ okay_to_send(message.channel)
293
323
  nick = message.nick.is_a?(Models::Nick) ? message.nick.nick : message.nick
294
324
  channel = message.channel.is_a?(Models::Channel) ? message.channel.name : message.channel
295
325
  @socket << "KICK #{channel} #{nick} :#{message.reason}"
@@ -298,18 +328,19 @@ module ModSpox
298
328
  # message:: Messages::Outgoing::Privmsg message
299
329
  # Sends PRIVMSG message to server
300
330
  def privmsg(message)
331
+ okay_to_send(message.target)
301
332
  target = message.target.name if message.target.is_a?(Models::Channel)
302
333
  target = message.target.nick if message.target.is_a?(Models::Nick)
303
334
  target = message.target unless target
304
335
  messages = message.message.is_a?(Array) ? message.message : [message.message]
305
336
  messages.each do |part|
306
337
  part.split("\n").each do |content|
307
- while(content.size > 450)
308
- output = content[0..450]
309
- content.slice!(0, 451) #(450, content.size)
310
- @socket << "PRIVMSG #{target} :#{message.is_ctcp? ? "\cA#{message.ctcp_type} #{output}\cA" : output}"
338
+ while(content.size > 400)
339
+ output = content[0..400]
340
+ content.slice!(0, 401) #(450, content.size)
341
+ @socket.prioritize_message(target, "PRIVMSG #{target} :#{message.is_ctcp? ? "\cA#{message.ctcp_type} #{output}\cA" : output}")
311
342
  end
312
- @socket << "PRIVMSG #{target} :#{message.is_ctcp? ? "\cA#{message.ctcp_type} #{content}\cA" : content}"
343
+ @socket.prioritize_message(target, "PRIVMSG #{target} :#{message.is_ctcp? ? "\cA#{message.ctcp_type} #{content}\cA" : content}")
313
344
  end
314
345
  end
315
346
  end
@@ -317,6 +348,7 @@ module ModSpox
317
348
  # message:: Messages::Outgoing::Notice message
318
349
  # Sends NOTICE message to server
319
350
  def notice(message)
351
+ okay_to_send(message.target)
320
352
  target = message.target.name if message.target.is_a?(Models::Channel)
321
353
  target = message.target.nick if message.target.is_a?(Models::Nick)
322
354
  @socket << "NOTICE #{target} :#{message}"
@@ -399,14 +431,14 @@ module ModSpox
399
431
  # Sends WHO message to server
400
432
  def who(message)
401
433
  o = message.only_ops? ? 'o' : ''
402
- @socket << "WHO #{message.mask} #{o}"
434
+ @socket.prioritize_message('*who', "WHO #{message.mask} #{o}")
403
435
  end
404
436
 
405
437
  # message:: Messages::Outgoing::Whois message
406
438
  # Sends WHOIS message to server
407
439
  def whois(message)
408
440
  nick = message.nick.is_a?(Models::Nick) ? message.nick.nick : message.nick
409
- @socket << "WHOIS #{message.target_server} #{nick}"
441
+ @socket.prioritize_message('*whois', "WHOIS #{message.target_server} #{nick}")
410
442
  end
411
443
 
412
444
  # message:: Messages::Outgoing::WhoWas message
@@ -502,22 +534,66 @@ module ModSpox
502
534
  @socket << message.message
503
535
  end
504
536
 
537
+ def check_join(m)
538
+ if(m.nick.botnick)
539
+ @channels << m.channel.name.downcase
540
+ end
541
+ end
542
+
543
+ def check_part(m)
544
+ if(m.nick.botnick)
545
+ @channels.delete(m.channel.name.downcase)
546
+ end
547
+ end
548
+
505
549
  private
506
550
 
507
- def start_shutdown
508
- @shutdown = true
509
- @lock.synchronize do
510
- @waiter.signal
551
+ # channel:: channel to check
552
+ # checks if the bot is parked in the given channel
553
+ # and raises an exception (and logs) if the bot
554
+ # is not in the given channel
555
+ def okay_to_send(channel)
556
+ if(channel.is_a?(String) && ['&', '#', '+', '!'].include?(channel[0]))
557
+ channel = Helpers.find_model(channel)
511
558
  end
559
+ return unless channel.is_a?(Models::Channel)
560
+ if(channel.quiet)
561
+ Logger.error("Attempted to send to channel where bot is not allowed to speak: #{channel.name}")
562
+ raise Exceptions::QuietChannel.new(channel)
563
+ end
564
+ unless(in_channel?(channel))
565
+ Logger.error("Attempted to send to channel where bot is not parked: #{channel.name}.")
566
+ raise Exceptions::NotInChannel.new(channel)
567
+ end
568
+ end
569
+
570
+ def in_channel?(channel)
571
+ unless(@channels.include?(channel.name.downcase))
572
+ repopulate_channels
573
+ return @channels.include?(channel.name.downcase)
574
+ else
575
+ return true
576
+ end
577
+ end
578
+
579
+ def repopulate_channels
580
+ bot = Models::Nick.filter(:botnick => true).first
581
+ raise Exceptions::BotException.new("I DON'T KNOW WHO I AM") unless bot
582
+ @channels.clear
583
+ bot.channels.each{|c| @channels << c.name.downcase}
512
584
  end
513
585
 
514
586
  # Cleans information from models to avoid
515
587
  # stale values
516
588
  def clean_models
517
- Models::Nick.clean
518
- Models::Channel.clean
519
- Models::NickChannel.destroy_all
520
- Models::Signature.delete_all
589
+ Models::NickMode.destroy
590
+ Models::Channel.update(:topic => nil)
591
+ Models::Nick.update(:username => nil, :real_name => nil, :address => nil,
592
+ :source => nil, :connected_at => nil, :connected_to => nil,
593
+ :seconds_idle => nil, :away => false, :visible => false, :botnick => false)
594
+ Models::Auth.update(:authed => false)
595
+ Database.db[:auth_masks_nicks].delete
596
+ Database.db[:nick_channels].delete
521
597
  end
522
598
  end
523
599