mod_spox 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/CHANGELOG +20 -0
  2. data/bin/mod_spox +1 -1
  3. data/data/mod_spox/extras/AutoKick.rb +32 -2
  4. data/data/mod_spox/extras/Bouncer.rb +192 -0
  5. data/data/mod_spox/extras/Karma.rb +132 -5
  6. data/data/mod_spox/extras/PhpCli.rb +13 -4
  7. data/data/mod_spox/extras/PhpFuncLookup.rb +6 -2
  8. data/data/mod_spox/extras/Roulette.rb +2 -1
  9. data/data/mod_spox/plugins/Authenticator.rb +1 -1
  10. data/data/mod_spox/plugins/Helper.rb +9 -7
  11. data/lib/mod_spox/Bot.rb +8 -6
  12. data/lib/mod_spox/ConfigurationWizard.rb +5 -5
  13. data/lib/mod_spox/Pipeline.rb +5 -3
  14. data/lib/mod_spox/PluginManager.rb +11 -5
  15. data/lib/mod_spox/handlers/Join.rb +5 -18
  16. data/lib/mod_spox/handlers/Names.rb +1 -1
  17. data/lib/mod_spox/handlers/Privmsg.rb +4 -14
  18. data/lib/mod_spox/handlers/Who.rb +9 -8
  19. data/lib/mod_spox/models/Auth.rb +8 -0
  20. data/lib/mod_spox/models/Config.rb +1 -1
  21. data/lib/mod_spox/models/Setting.rb +2 -2
  22. metadata +3 -13
  23. data/lib/mod_spox/migration/001_create_auths.rb +0 -13
  24. data/lib/mod_spox/migration/001_create_channel.rb +0 -13
  25. data/lib/mod_spox/migration/001_create_channel_modes.rb +0 -13
  26. data/lib/mod_spox/migration/001_create_config.rb +0 -13
  27. data/lib/mod_spox/migration/001_create_nick_channels.rb +0 -13
  28. data/lib/mod_spox/migration/001_create_nick_modes.rb +0 -13
  29. data/lib/mod_spox/migration/001_create_nicks.rb +0 -13
  30. data/lib/mod_spox/migration/001_create_servers.rb +0 -13
  31. data/lib/mod_spox/migration/001_create_settings.rb +0 -13
  32. data/lib/mod_spox/migration/001_create_signatures.rb +0 -13
  33. data/lib/mod_spox/migration/001_create_triggers.rb +0 -13
data/CHANGELOG CHANGED
@@ -1,3 +1,23 @@
1
+ 0.1.0 Release (Beta status)
2
+ Core:
3
+ * Plugins use symlinks
4
+ * Updates for sequel library compatibility
5
+ * Fixed bug in configuration wizard causing failure
6
+ * Triggerless commands usable when directly privmsging the bot
7
+ * Triggers are escaped properly before applying regex match
8
+ * Fixed trigger matching error when only trigger is provided
9
+ * Fixed output error when multiple lines are sent for output
10
+ Plugins:
11
+ * Karma plugin updates
12
+ * Added aliasing
13
+ * Auto decrement on self karma whoring
14
+ * Added a karma fight trigger
15
+ * Authentication plugin fixed to allow adding new groups to existing masks
16
+ * AutoKick ignores case during regex matching
17
+ * Fixed Roulette to have 6 chambers (was previously using only 5)
18
+ * Added option to kick on colored messages to AutoKick plugin
19
+ * PhpCli plugin properly remembers what channels it is enabled on
20
+
1
21
  0.0.5 Release (Alpha status)
2
22
  * Added new RAW message type for outgoing messages
3
23
  * Ability to load/unload/reload individual plugins
@@ -18,7 +18,7 @@ rescue Object => boom
18
18
  # ignore if not found #
19
19
  end
20
20
 
21
- $BOTVERSION='0.0.5'
21
+ $BOTVERSION='0.1.0'
22
22
  $VERBOSITY = 0
23
23
  $MOD_SPOX_PATH = nil
24
24
 
@@ -14,13 +14,38 @@ class AutoKick < ModSpox::Plugin
14
14
  :group_id => group.pk, :description => 'Add a new autokick rule').params = [:time, :regex, :message]
15
15
  Signature.find_or_create(:signature => 'autokick remove (\d+)', :plugin => name, :method => 'remove',
16
16
  :group_id => group.pk, :description => 'Remove an autokick rule').params = [:id]
17
+ Signature.find_or_create(:signature => 'autokick colors ?(on|off)?', :plugin => name, :method => 'colors',
18
+ :group_id => group.pk, :description => 'Kick user for using colors', :requirement => 'public').params = [:action]
17
19
  @pipeline.hook(self, :banner_watch, :Internal_PluginResponse)
18
20
  @banner = nil
19
21
  @map = nil
22
+ @colors = Setting[:colorkick]
23
+ @colors = Array.new if @colors.nil?
20
24
  AutoKickRecord.create_table unless AutoKickRecord.table_exists?
21
25
  do_listen
22
26
  end
23
27
 
28
+ def colors(message, params)
29
+ if(params[:action])
30
+ if(params[:action] == 'on')
31
+ if(@colors.include?(message.target.pk))
32
+ reply message.replyto, 'Colored autokick is already enabled'
33
+ else
34
+ @colors << message.target.pk
35
+ Setting[:colorkick] = @colors
36
+ reply message.replyto, 'Colored autokick has been enabled'
37
+ end
38
+ else
39
+ @colors.delete(message.target.pk)
40
+ Setting[:colorkick] = @colors
41
+ reply message.replyto, 'Colored autokick has been disabled'
42
+ end
43
+ else
44
+ status = @colors.include?(message.target.pk) ? 'on' : 'off'
45
+ reply message.replyto, "Colored autokick is currently \2#{status}\2"
46
+ end
47
+ end
48
+
24
49
  def list(message, params)
25
50
  records = AutoKickRecord.all
26
51
  unless(records.empty?)
@@ -61,13 +86,18 @@ class AutoKick < ModSpox::Plugin
61
86
  def listener(message)
62
87
  if(@map.keys.include?(message.target.pk))
63
88
  @map[message.target.pk].each do |pattern|
64
- reg = Regexp.new(pattern)
89
+ reg = Regexp.new(pattern, Regexp::IGNORECASE)
65
90
  unless(reg.match(message.message).nil?)
66
91
  record = AutoKickRecord.filter(:pattern => pattern).first
67
- @banner.plugin.ban(message.source, message.target, record.bantime, record.message, invite=false, show_time=true)
92
+ @banner.plugin.ban(message.source, message.target, record.bantime, record.message, false, true)
68
93
  end
69
94
  end
70
95
  end
96
+ if(@colors.include?(message.target.pk))
97
+ if(message.is_colored?)
98
+ @banner.plugin.ban(message.source, message.target, 60, 'No color codes allowed', false, true)
99
+ end
100
+ end
71
101
  end
72
102
 
73
103
  def banner_watch(message)
@@ -0,0 +1,192 @@
1
+ class Bouncer < ModSpox::Plugin
2
+
3
+ include Models
4
+
5
+ def initialize(pipeline)
6
+ super
7
+ admin = Group.find_or_create(:name => 'bouncer')
8
+ Signature.find_or_create(:signature => 'bouncer port ?(\d+)?', :plugin => name, :method => 'port',
9
+ :group_id => admin.pk, :description => 'Show or set bouncer port').params = [:port]
10
+ Signature.find_or_create(:signature => 'bouncer (start|stop|restart)', :plugin => name, :method => 'do_service',
11
+ :group_id => admin.pk, :description => 'Start or stop the bouncer').params = [:action]
12
+ Signature.find_or_create(:signature => 'bouncer status', :plugin => name, :method => 'status',
13
+ :group_id => admin.pk, :description => 'Show current bouncer status')
14
+ Signature.find_or_create(:signature => 'bouncer disconnect', :plugin => name, :method => 'disconnect',
15
+ :group_id => admin.pk, :description => 'Disconnect all users connected to bouncer')
16
+ Signature.find_or_create(:signature => 'bouncer clients', :plugin => name, :method => 'clients',
17
+ :group_id => admin.pk, :description => 'List clients connected to bouncer')
18
+ @pipeline.hook(self, :get_msgs, :Incoming)
19
+ @listener = nil
20
+ @clients = []
21
+ @socket = nil
22
+ @processor = nil
23
+ @to_server = Queue.new
24
+ if(Config[:bouncer_port])
25
+ start_listener
26
+ end
27
+ end
28
+
29
+ def get_msgs(message)
30
+ unless(@clients.empty?)
31
+ Logger.log("BOUNCER: Sending to #{@clients.size} clients")
32
+ @clients.each do |client|
33
+ begin
34
+ if(message.raw_content.is_a?(Array))
35
+ message.raw_content.each do |m|
36
+ client[:connection].puts(m + "\n")
37
+ end
38
+ else
39
+ client[:connection].puts(message.raw_content + "\n")
40
+ end
41
+ rescue Object => boom
42
+ client[:thread].kill if client[:thread].alive?
43
+ @clients.delete(client)
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ def port(message, params)
50
+ unless(params[:port])
51
+ if(Config[:bouncer_port])
52
+ reply message.replyto, "Bouncer is currently listening on port: #{Config[:bouncer_port]}"
53
+ else
54
+ reply message.replyto, "\2Warning:\2 Listening port is not currently set for bouncer"
55
+ end
56
+ else
57
+ Config[:bouncer_port] = params[:port].to_i
58
+ reply message.replyto, "Bouncer will now listen on port: #{params[:port].to_i}"
59
+ restart_listener
60
+ end
61
+ end
62
+
63
+ def do_service(message, params)
64
+ if(params[:action] == 'start')
65
+ if(listening?)
66
+ reply message.replyto, "\2Error:\2 Bouncer is already running"
67
+ else
68
+ start_listener
69
+ reply message.replyto, "Bouncer has been started"
70
+ end
71
+ elsif(params[:action] == 'stop')
72
+ if(listening?)
73
+ stop_listener
74
+ reply message.replyto, "Bouncer has been stopped"
75
+ else
76
+ reply message.replyto, "\2Error:\2 Bouncer is not currently running"
77
+ end
78
+ elsif(params[:action] == 'restart')
79
+ stop_listener
80
+ start_listener
81
+ reply message.replyto, "Bouncer has been restarted"
82
+ end
83
+ end
84
+
85
+ def disconnect(message, params)
86
+ unless(@clients.empty?)
87
+ @clients.each do |socket|
88
+ socket[:connection].close
89
+ @clients.delete(socket)
90
+ end
91
+ reply message.replyto, "Bouncer has disconnected all clients"
92
+ else
93
+ reply message.replyto, "\2Error:\2 No clients connected to bouncer"
94
+ end
95
+ end
96
+
97
+ def status(message, params)
98
+ end
99
+
100
+ private
101
+
102
+ def start_listener
103
+ port = Config[:bouncer_port]
104
+ if(port)
105
+ @socket = TCPServer.new(port)
106
+ @listener = Thread.new do
107
+ until(@socket.closed?)
108
+ begin
109
+ new_con = @socket.accept_nonblock
110
+ Logger.log("BOUNCER: New connection established on bouncer")
111
+ @clients << {
112
+ :connection => new_con,
113
+ :thread => Thread.new(new_con) do | con |
114
+ begin
115
+ Logger.log("CONNECTION: #{con}")
116
+ until(con.closed?)
117
+ Logger.log("WAITING FOR STUFF ON :#{con}")
118
+ Kernel.select([con], nil, nil, nil)
119
+ Logger.log("Woken up and ready to read")
120
+ string = con.gets
121
+ Logger.log("BOUNCER GOT MESSAGE: #{string}")
122
+ if(string.empty?)
123
+ raise Exception.new("EMPTY STRING")
124
+ else
125
+ @to_server << {:message => string, :socket => con}
126
+ end
127
+ end
128
+ rescue Object => boom
129
+ Logger.log("THREAD BOUNCER ERROR: #{boom}")
130
+ end
131
+ end
132
+ }
133
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
134
+ IO.select([@socket])
135
+ retry
136
+ end
137
+ end
138
+ @listener = nil
139
+ end
140
+ start_processor
141
+ else
142
+ Logger.log("Error: Bouncer was not started. Failed to find set port number")
143
+ end
144
+ end
145
+
146
+ def stop_listener
147
+ @socket.close
148
+ @listener.kill unless @listener.nil?
149
+ @listener = nil
150
+ @to_server.clear
151
+ @processor.kill if !@processor.nil? && @processor.alive?
152
+ @processor = nil
153
+ end
154
+
155
+ def start_processor
156
+ @processor.kill if !@processor.nil? && @processor.alive?
157
+ @processor = Thread.new do
158
+ begin
159
+ while(@listener) do
160
+ info = @to_server.pop
161
+ Logger.log("Processing message: #{info[:message]}")
162
+ if(info[:message] =~ /^USER\s/i)
163
+ initialize_connection(info[:socket])
164
+ else
165
+ @pipeline << Messages::Outgoing::Raw.new(info[:message])
166
+ end
167
+ end
168
+ rescue Object => boom
169
+ Logger.log("BOUNCER ERROR: #{boom}")
170
+ unless(@clients.empty?)
171
+ @clients.each do |socket|
172
+ socket[:connection].close
173
+ @clients.delete(socket)
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ def listening?
181
+ return !@listener.nil?
182
+ end
183
+
184
+ def initialize_connection(connection)
185
+ # send channel info and such to client
186
+ connection.puts(":localhost 001 #{me.nick} :Welcome to the network #{me.source}\n")
187
+ Models::Channel.filter(:parked => true).each do |channel|
188
+ connection.puts(":#{me.source} JOIN :#{channel.name}\n")
189
+ end
190
+ end
191
+
192
+ end
@@ -5,9 +5,19 @@ class Karma < ModSpox::Plugin
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
7
  Datatype::Karma.create_table unless Datatype::Karma.table_exists?
8
+ Datatype::Alias.create_table unless Datatype::Alias.table_exists?
9
+ alias_group = Models::Group.find_or_create(:name => 'alias')
8
10
  Models::Signature.find_or_create(:signature => 'karma (\S+)', :plugin => name, :method => 'score', :description => 'Returns karma for given thing').params = [:thing]
9
11
  Models::Signature.find_or_create(:signature => 'karma reset (\S+)', :plugin => name, :method => 'reset',
10
12
  :group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Reset a karma score').params = [:thing]
13
+ Models::Signature.find_or_create(:signature => 'karma alias (\S+) (\S+)', :plugin => name, :method => 'aka',
14
+ :group_id => alias_group.pk, :description => 'Alias a karma object to another karma object').params = [:thing, :thang]
15
+ Models::Signature.find_or_create(:signature => 'karma dealias (\S+) (\S+)', :plugin => name, :method => 'dealias',
16
+ :group_id => alias_group.pk, :description => 'Remove a karma alias').params = [:thing, :otherthing]
17
+ Models::Signature.find_or_create(:signature => 'karma aliases (\S+)', :plugin => name, :method => 'show_aliases',
18
+ :description => 'Show all aliases for given thing').params = [:thing]
19
+ Models::Signature.find_or_create(:signature => 'karma fight (\S+) (\S+)', :plugin => name, :method => 'fight',
20
+ :description => 'Make two karma objects fight').params = [:thing, :thang]
11
21
  @pipeline.hook(self, :check, :Incoming_Privmsg)
12
22
  @thing_maxlen = 32
13
23
  @karma_regex = /(\(.{1,#@thing_maxlen}?\)|\S{1,#@thing_maxlen})([+-]{2})(?:\s|$)/
@@ -20,18 +30,26 @@ class Karma < ModSpox::Plugin
20
30
  thing.downcase!
21
31
  thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..1] == ')'
22
32
  adj = adj == '++' ? +1 : -1
33
+ things = [thing]
23
34
  karma = Datatype::Karma.find_or_create(:thing => thing, :channel_id => message.target.pk)
24
- karma.update_with_params(:score => karma.score + adj)
35
+ Datatype::Alias.get_aliases(karma.pk).each do |id|
36
+ things << Datatype::Karma[id].thing.downcase
37
+ end
38
+ if(things.include?(message.source.nick.downcase))
39
+ adj = -1
40
+ end
41
+ karma = Datatype::Karma.find_or_create(:thing => thing, :channel_id => message.target.pk)
42
+ karma.score = karma.score + adj
43
+ karma.save
25
44
  end
26
45
  end
27
46
  end
28
47
 
29
48
  def score(message, params)
30
- params[:thing].downcase!
31
49
  return unless message.is_public?
32
- karma = Datatype::Karma.filter(:thing => params[:thing], :channel_id => message.target.pk).first
50
+ karma = Datatype::Karma.filter(:thing => params[:thing].downcase, :channel_id => message.target.pk).first
33
51
  if(karma)
34
- @pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 is #{karma.score}")
52
+ @pipeline << Privmsg.new(message.replyto, "Karma for \2#{params[:thing]}\2 is #{Datatype::Alias.score_object(karma.pk)}")
35
53
  else
36
54
  @pipeline << Privmsg.new(message.replyto, "\2Error:\2 #{params[:thing]} has no karma")
37
55
  end
@@ -48,19 +66,128 @@ class Karma < ModSpox::Plugin
48
66
  @pipeline << Privmsg.new(message.replyto, "\2Error:\2 #{params[:thing]} has no karma")
49
67
  end
50
68
  end
69
+
70
+ def fight(message, params)
71
+ thing = Datatype::Karma.find_or_create(:thing => params[:thing].downcase)
72
+ thang = Datatype::Karma.find_or_create(:thing => params[:thang].downcase)
73
+ thing_score = Datatype::Alias.score_object(thing.pk)
74
+ thang_score = Datatype::Alias.score_object(thang.pk)
75
+ winner = thing_score > thang_score ? params[:thing] : params[:thang]
76
+ loser = thing_score > thang_score ? params[:thang] : params[:thing]
77
+ distance = (thing_score - thang_score).abs
78
+ reply message.replyto, "\2KARMA FIGHT RESULTS:\2 \2#{winner}\2 has beaten \2#{loser}\2 by a #{distance} point lead"
79
+ end
80
+
81
+ def aka(message, params)
82
+ thing = Datatype::Karma.find_or_create(:thing => params[:thing].downcase, :channel_id => message.target.pk)
83
+ thang = Datatype::Karma.find_or_create(:thing => params[:thang].downcase, :channel_id => message.target.pk)
84
+ if(Datatype::Alias.filter('(thing_id = ? AND aka_id = ?) OR (thing_id = ? AND aka_id = ?)', thing.pk, thang.pk, thang.pk, thing.pk).first)
85
+ reply message.replyto, "\2Error:\2 #{params[:thing]} is already aliased to #{params[:thang]}"
86
+ else
87
+ Datatype::Alias.find_or_create(:thing_id => thing.pk, :aka_id => thang.pk)
88
+ reply message.replyto, "\2Karma Alias:\2 #{params[:thing]} is now aliased to #{params[:thang]}"
89
+ end
90
+ end
91
+
92
+ def dealias(message, params)
93
+ thing = Datatype::Karma.filter(:thing => params[:thing].downcase, :channel_id => message.target.pk).first
94
+ otherthing = Datatype::Karma.filter(:thing => params[:otherthing].downcase, :channel_id => message.target.pk).first
95
+ if(thing && otherthing)
96
+ set = Datatype::Alias.filter('(thing_id = ? AND aka_id = ?) OR (thing_id = ? AND aka_id = ?)', thing.pk, otherthing.pk, otherthing.pk, thing.pk)
97
+ if(set.size < 1)
98
+ reply message.replyto, "\2Error:\2 No alias found between #{params[:thing]} and #{params[:otherthing]}"
99
+ else
100
+ set.destroy
101
+ reply message.replyto, "#{params[:thing]} has been successfully dealiased from #{params[:otherthing]}"
102
+ end
103
+ else
104
+ reply message.replyto, "\2Error:\2 No alias found between #{params[:thing]} and #{params[:otherthing]}"
105
+ end
106
+ end
107
+
108
+ def show_aliases(message, params)
109
+ thing = Datatype::Karma.filter(:thing => params[:thing].downcase, :channel_id => message.target.pk).first
110
+ if(thing)
111
+ things = []
112
+ Datatype::Alias.get_aliases(thing.pk).each do |id|
113
+ things << Datatype::Karma[id].thing
114
+ end
115
+ if(things.empty?)
116
+ reply message.replyto, "#{params[:thing]} is not currently aliased"
117
+ else
118
+ reply message.replyto, "#{params[:thing]} is currently aliased to: #{things.join(', ')}"
119
+ end
120
+ else
121
+ reply message.replyto, "\2Error:\2 #{params[:thing]} has never been used and has no aliases"
122
+ end
123
+ end
51
124
 
52
125
  module Datatype
53
126
  class Karma < Sequel::Model
54
127
  set_schema do
55
128
  primary_key :id
56
- text :thing, :null => false, :unique => true
129
+ text :thing, :null => false
57
130
  integer :score, :null => false, :default => 0
58
131
  foreign_key :channel_id, :table => :channels
132
+ index [:thing, :channel_id], :unique => true
59
133
  end
60
134
 
61
135
  def channel
62
136
  ModSpox::Models::Channel[channel_id]
63
137
  end
64
138
  end
139
+ class Alias < Sequel::Model
140
+ set_schema do
141
+ primary_key :id
142
+ foreign_key :thing_id, :null => false
143
+ foreign_key :aka_id, :null => false
144
+ end
145
+
146
+ def thing
147
+ Karma[thing_id]
148
+ end
149
+
150
+ def aka
151
+ Karma[aka_id]
152
+ end
153
+
154
+ def Alias.score_object(object_id)
155
+ Alias.create_lock unless class_variable_defined?(:@@lock)
156
+ @@objects = []
157
+ score = 0
158
+ @@lock.synchronize do
159
+ score += Alias.sum_objects(object_id)
160
+ end
161
+ return score
162
+ end
163
+
164
+ def Alias.get_aliases(object_id)
165
+ Alias.score_object(object_id)
166
+ objs = @@objects.dup
167
+ objs.delete(object_id)
168
+ return objs
169
+ end
170
+
171
+ private
172
+
173
+ def Alias.sum_objects(object_id)
174
+ return 0 if @@objects.include?(object_id)
175
+ @@objects << object_id
176
+ object = Karma[object_id]
177
+ score = object ? object.score : 0
178
+ Alias.filter(:thing_id => object_id).each do |ali|
179
+ score += Alias.sum_objects(ali.aka.pk)
180
+ end
181
+ Alias.filter(:aka_id => object_id).each do |ali|
182
+ score += Alias.sum_objects(ali.thing.pk)
183
+ end
184
+ return score
185
+ end
186
+
187
+ def Alias.create_lock
188
+ @@lock = Mutex.new
189
+ end
190
+
191
+ end
65
192
  end
66
193
  end
@@ -24,8 +24,13 @@ class PhpCli < ModSpox::Plugin
24
24
  :description => 'Add or remove channel from allowing PHP command').params = [:action]
25
25
  Signature.find_or_create(:signature => 'php (?!on|off)(.+)', :plugin => name, :method => 'execute_php', :group_id => php.pk,
26
26
  :description => 'Execute PHP code').params = [:code]
27
- Setting[:phpcli] = '' if Setting[:phpcli].nil?
28
- @channels = Setting[:phpcli].split('|')
27
+ @channels = Setting.find(:name => 'phpcli')
28
+ if(@channels.nil?)
29
+ Logger.log("WE ARE NIL PEOPLE")
30
+ @channels = []
31
+ else
32
+ @channels = @channels.value
33
+ end
29
34
  end
30
35
 
31
36
  def set_channel(message, params)
@@ -33,7 +38,9 @@ class PhpCli < ModSpox::Plugin
33
38
  if(params[:action] == 'on')
34
39
  unless(@channels.include?(message.target.pk))
35
40
  @channels << message.target.pk
36
- Setting[:phpcli] = @channels.join('|')
41
+ tmp = Setting.find_or_create(:name => 'phpcli')
42
+ tmp.value = @channels
43
+ tmp.save
37
44
  end
38
45
  reply message.replyto, 'PHP command now active'
39
46
  else
@@ -41,7 +48,9 @@ class PhpCli < ModSpox::Plugin
41
48
  reply message.replyto, 'PHP command is not currently active in this channel'
42
49
  else
43
50
  @channels.delete(message.target.pk)
44
- Setting[:phpcli] = @channels.join('|')
51
+ tmp = Setting.find_or_create(:name => 'phpcli')
52
+ tmp.value = @channels
53
+ tmp.save
45
54
  reply message.replyto, 'PHP command is now disabled'
46
55
  end
47
56
  end
@@ -219,8 +219,12 @@ class PhpFuncLookup < ModSpox::Plugin
219
219
  end
220
220
  end
221
221
  matches.sort!
222
- output = ["Lots of matching functions. Truncating list to 20 results."]
223
- output << matches.values_at(0..19).join(', ')
222
+ output = matches.size > 20 ? ["Lots of matching functions. Truncating list to 20 results."] : []
223
+ if(matches.empty?)
224
+ output = "\2Error:\2 No matches found"
225
+ else
226
+ output << matches.values_at(0..19).join(', ')
227
+ end
224
228
  reply m.replyto, output
225
229
  end
226
230
 
@@ -187,6 +187,7 @@ class Roulette < ModSpox::Plugin
187
187
  rescue Banner::NotOperator => boom
188
188
  reply(channel, "#{nick.nick}: *BANG*")
189
189
  rescue Object => boom
190
+ reply(channel, "#{nick.nick}: *BANG*")
190
191
  Logger.log("Error: Roulette ban generated an unexpected error: #{boom}")
191
192
  end
192
193
  else
@@ -200,7 +201,7 @@ class Roulette < ModSpox::Plugin
200
201
  @pipeline << Messages::Internal::PluginRequest.new(self, 'Banner') if @banner.nil?
201
202
  game = Game.filter('shots > ?', 0).filter('channel_id = ?', channel.pk).first
202
203
  unless(game)
203
- chamber = rand(5) + 1
204
+ chamber = rand(6) + 1
204
205
  game = Game.new(:chamber => chamber, :shots => chamber, :channel_id => channel.pk)
205
206
  game.save
206
207
  end
@@ -9,7 +9,7 @@ class Authenticator < ModSpox::Plugin
9
9
  Models::Signature.find_or_create(:signature => 'auth mask add (\S+) (\S+)', :plugin => name, :method => 'add_mask',
10
10
  :group_id => group.pk, :description => 'Add authentication mask and set initial group').params = [:mask, :group]
11
11
  Models::Signature.find_or_create(:signature => 'auth mask set (\d+) (.+)', :plugin => name, :method => 'set_mask_groups',
12
- :group_id => group.pk, :description => 'Set groups for the given mask').params = [:id, :group_ids]
12
+ :group_id => group.pk, :description => 'Set groups for the given mask').params = [:id, :groups]
13
13
  Models::Signature.find_or_create(:signature => 'auth mask unset (\d+) (.+)', :plugin => name, :method => 'del_mask_groups',
14
14
  :group_id => group.pk, :description => 'Remove groups for the given mask').params = [:id, :groups]
15
15
  Models::Signature.find_or_create(:signature => 'auth mask remove (\d+)', :plugin => name, :method => 'remove_mask',
@@ -20,15 +20,17 @@ class Helper < ModSpox::Plugin
20
20
  def plugin_help(message, params)
21
21
  sigs = Signature.filter(:plugin => params[:plugin])
22
22
  if(sigs.count > 0)
23
- reply message.source, "Available triggers for plugin: \2#{params[:plugin]}\2"
23
+ output = []
24
+ output << "Available triggers for plugin: \2#{params[:plugin]}\2"
24
25
  sigs.each do |sig|
25
- output = []
26
- output << "\2Pattern:\2 #{sig.signature}"
27
- output << "\2Parameters:\2 [#{sig.params.join(' | ')}]" if sig.params
28
- output << "\2Auth Group:\2 #{Group[sig.group_id].name}" if sig.group_id
29
- output << "\2Description:\2 #{sig.description}" if sig.description
30
- reply message.source, output.join(' ')
26
+ help = []
27
+ help << "\2Pattern:\2 #{sig.signature}"
28
+ help << "\2Parameters:\2 [#{sig.params.join(' | ')}]" if sig.params
29
+ help << "\2Auth Group:\2 #{Group[sig.group_id].name}" if sig.group_id
30
+ help << "\2Description:\2 #{sig.description}" if sig.description
31
+ output << help.join(' ')
31
32
  end
33
+ reply message.source, output
32
34
  else
33
35
  reply message.replyto, "\2Error:\2 No triggers found for plugin named: #{params[:plugin]}"
34
36
  end
@@ -286,13 +286,15 @@ module ModSpox
286
286
  target = message.target.nick if message.target.is_a?(Models::Nick)
287
287
  target = message.target unless target
288
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}"
289
+ messages.each do |part|
290
+ part.split("\n").each do |content|
291
+ while(content.size > 450)
292
+ output = content[0..450]
293
+ content.slice!(0, 450) #(450, content.size)
294
+ @socket << "PRIVMSG #{target} :#{message.is_action? ? "\cAACTION #{output}\cA" : output}"
295
+ end
296
+ @socket << "PRIVMSG #{target} :#{message.is_action? ? "\cAACTION #{content}\cA" : content}"
294
297
  end
295
- @socket << "PRIVMSG #{target} :#{message.is_action? ? "\cAACTION #{content}\cA" : content}"
296
298
  end
297
299
  end
298
300
 
@@ -1,9 +1,7 @@
1
1
  ['etc',
2
2
  'mod_spox/Database',
3
3
  'mod_spox/BotConfig',
4
- 'mod_spox/BaseConfig'
5
- 'mod_spox/models/Models',
6
- 'mod_spox/Helpers'].each{|f|require f}
4
+ 'mod_spox/BaseConfig'].each{|f|require f}
7
5
 
8
6
 
9
7
  module ModSpox
@@ -75,6 +73,8 @@ module ModSpox
75
73
  }
76
74
  config.write_configuration
77
75
  initialize_bot
76
+ require 'mod_spox/models/Models'
77
+ require 'mod_spox/Helpers'
78
78
  create_databases
79
79
  #Migrators.constants.each{|m| Migrators.const_get(m).apply(Database.db, :up)}
80
80
  @config.each{|value|
@@ -87,7 +87,7 @@ module ModSpox
87
87
  a.password = find(:admin_password)
88
88
  a.save
89
89
  t = Models::Trigger.find_or_create(:trigger => find(:trigger))
90
- t.active = true
90
+ t.update_with_params(:active => true)
91
91
  t.save
92
92
  end
93
93
 
@@ -164,7 +164,7 @@ module ModSpox
164
164
  Database.db << "CREATE TABLE nick_modes (id serial not null primary key, mode varchar(255) not null, nick_id integer not null references nicks, channel_id integer references channels, unique (nick_id, channel_id))"
165
165
  Database.db << "CREATE TABLE servers (id serial not null primary key, host varchar(255) not null, port integer not null default 6667, priority integer not null default 0, connected boolean not null default false, unique (host, port))"
166
166
  Database.db << "CREATE TABLE signatures (id serial not null primary key, signature varchar(255) not null, params varchar(255), group_id integer default null references groups, method varchar(255) not null, plugin varchar(255) not null, description varchar(255), requirement varchar(255) default 'both' not null)"
167
- Database.db << "CREATE TABLE settings (id serial not null primary key, name varchar(255) unique not null, value varchar(255))"
167
+ Database.db << "CREATE TABLE settings (id serial not null primary key, name varchar(255) unique not null, value text)"
168
168
  Database.db << "CREATE TABLE triggers (id serial not null primary key, trigger varchar(255) unique not null, active boolean not null default false)"
169
169
  Database.db << "CREATE TABLE auth_groups (auth_id integer not null references auths, group_id integer not null references groups, primary key (auth_id, group_id))"
170
170
  when :sqlite
@@ -153,10 +153,11 @@ module ModSpox
153
153
  def parse(message)
154
154
  return unless message.kind_of?(Messages::Incoming::Privmsg) || message.kind_of?(Messages::Incoming::Notice)
155
155
  trigger = nil
156
- @triggers.each{|t| trigger = t if message.message =~ /^#{t}/}
156
+ @triggers.each{|t| trigger = t if message.message =~ /^#{Regexp.escape(t)}/}
157
157
  if(!trigger.nil? || message.addressed?)
158
+ return if !trigger.nil? && message.message.length == trigger.length
158
159
  Logger.log("Message has matched against a known trigger", 15)
159
- c = message.addressed? ? message.message[0].chr.downcase : message.message[1].chr.downcase
160
+ c = (message.addressed? && trigger.nil?) ? message.message[0].chr.downcase : message.message[trigger.length].chr.downcase
160
161
  if(c =~ /^[a-z]$/)
161
162
  type = c.to_sym
162
163
  elsif(c =~ /^[0-9]$/)
@@ -167,7 +168,8 @@ module ModSpox
167
168
  return unless @signatures[type]
168
169
  @signatures[type].each do |sig|
169
170
  Logger.log("Matching against: #{trigger}#{sig.signature}")
170
- res = message.message.scan(/^#{trigger}#{sig.signature}$/)
171
+ esc_trig = trigger.nil? ? '' : Regexp.escape(trigger)
172
+ res = message.message.scan(/^#{esc_trig}#{sig.signature}$/)
171
173
  if(res.size > 0)
172
174
  next unless message.source.auth_groups.include?(sig.group) || message.source.auth_groups.include?(@admin) ||sig.group.nil?
173
175
  next if sig.requirement == 'private' && message.is_public?
@@ -55,7 +55,11 @@ module ModSpox
55
55
  def load_plugin(message)
56
56
  begin
57
57
  path = !message.name ? "#{BotConfig[:userpluginpath]}/#{message.path.gsub(/^.+\//, '')}" : "#{BotConfig[:userpluginpath]}/#{message.name}"
58
- FileUtils.copy(message.path, path)
58
+ begin
59
+ File.symlink(message.path, path)
60
+ rescue NotImplementedError => boom
61
+ FileUtils.copy(message.path, path)
62
+ end
59
63
  do_load(path)
60
64
  @pipeline << Messages::Internal::PluginLoadResponse.new(message.requester, true)
61
65
  Logger.log("Loaded new plugin: #{message.path}", 10)
@@ -71,10 +75,12 @@ module ModSpox
71
75
  def unload_plugin(message)
72
76
  begin
73
77
  do_unload(message.path)
74
- unless(message.name.nil?)
75
- FileUtils.copy(message.path, "#{BotConfig[:userpluginpath]}/#{message.name}")
78
+ unless(File.symlink?(message.path))
79
+ unless(message.name.nil?)
80
+ FileUtils.copy(message.path, "#{BotConfig[:userpluginpath]}/#{message.name}")
81
+ end
76
82
  end
77
- FileUtils.remove_file(message.path)
83
+ File.delete(message.path)
78
84
  @pipeline << Messages::Internal::PluginUnloadResponse.new(message.requester, true)
79
85
  Logger.log("Unloaded plugin: #{message.path}", 10)
80
86
  rescue Object => boom
@@ -124,7 +130,7 @@ module ModSpox
124
130
  # Destroys plugins
125
131
  def unload_plugins
126
132
  @plugins.each_pair do |sym, holder|
127
- holder.plugin.destroy
133
+ holder.plugin.destroy unless holder.plugin.nil?
128
134
  @pipeline.unhook_plugin(holder.plugin)
129
135
  end
130
136
  Models::Signature.destroy_all
@@ -10,25 +10,12 @@ module ModSpox
10
10
  source = $1
11
11
  chan = $2
12
12
  if(source =~ /^(.+?)!(.+?)@(.+)$/)
13
- do_save = false
14
13
  nick = find_model($1)
15
- unless(nick.username == $2)
16
- nick.username == $2
17
- do_save = true
18
- end
19
- unless(nick.address == $3)
20
- nick.address = $3
21
- do_save = true
22
- end
23
- unless(nick.source == source)
24
- nick.source = source
25
- do_save = true
26
- end
27
- unless(nick.visible == true)
28
- nick.visible = true
29
- do_save = true
30
- end
31
- nick.save if do_save
14
+ nick.username == $2
15
+ nick.address = $3
16
+ nick.source = source
17
+ nick.visible = true
18
+ nick.save_changes
32
19
  channel = find_model(chan)
33
20
  channel.nick_add(nick)
34
21
  return Messages::Incoming::Join.new(string, channel, nick)
@@ -29,7 +29,7 @@ module ModSpox
29
29
  nicks = Array.new
30
30
  ops = Array.new
31
31
  voice = Array.new
32
- raw = @raw[chan].join(' ')
32
+ raw = @raw[chan]
33
33
  @names[chan].each{|n|
34
34
  nick = Models::Nick.find_or_create(:nick => n.gsub(/^[@+]/, ''))
35
35
  nicks << nick
@@ -13,20 +13,10 @@ module ModSpox
13
13
  base_source = $1
14
14
  source = find_model(base_source.gsub(/!.+$/, ''))
15
15
  if(base_source =~ /!(.+)@(.+)$/)
16
- do_save = false
17
- unless(source.username == $1)
18
- source.username == $1
19
- do_save = true
20
- end
21
- unless(source.address == $2)
22
- source.address = $2
23
- do_save = true
24
- end
25
- unless(source.source == base_source)
26
- source.source = base_source
27
- do_save = true
28
- end
29
- source.save if do_save
16
+ source.username == $1
17
+ source.address = $2
18
+ source.source = base_source
19
+ source.save_changes
30
20
  end
31
21
  Models::NickChannel.find_or_create(:channel_id => target.pk, :nick_id => source.pk) if target.is_a?(ModSpox::Models::Channel)
32
22
  return Messages::Incoming::Privmsg.new(string, source, target, message)
@@ -9,6 +9,8 @@ module ModSpox
9
9
  @raw_cache = Hash.new
10
10
  end
11
11
  def process(string)
12
+ # :not.configured 352 mod_spox #foobar ~mod_spox 192.168.0.25 not.configured mod_spox H :0 mod_spox IRC bot
13
+ # :not.configured 352 mod_spox * ~mod_spox 192.168.0.25 not.configured mod_spox H :0 mod_spox IRC bot
12
14
  if(string =~ /#{RPL_WHOREPLY}\s\S+\s(\S+|\*|\*\s\S+)\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s(\S+)\s:(\d)\s(.+)$/)
13
15
  # Items matched are as follows:
14
16
  # 1: location
@@ -19,9 +21,7 @@ module ModSpox
19
21
  # 6: info
20
22
  # 7: hops
21
23
  # 8: realname
22
- location = $1 unless $1.include?('*')
23
- location = $5 if $5 == '*'
24
- location = $1.gsub(/\*\s/, '') if location.include?('* ')
24
+ location = $1 == '*' ? nil : $1
25
25
  info = $6
26
26
  nick = find_model($5)
27
27
  nick.username = $2
@@ -30,11 +30,12 @@ module ModSpox
30
30
  nick.connected_to = $4
31
31
  nick.away = info =~ /G/ ? true : false
32
32
  nick.save
33
- @cache[location] = Array.new unless @cache[location]
34
- @cache[location] << nick
35
- @raw_cache[location] = Array.new unless @raw_cache[location]
36
- @raw_cache[location] << string
37
- if(location[0].chr !~ /[A-Za-z]/)
33
+ key = location.nil? ? nick.nick : location
34
+ @cache[key] = Array.new unless @cache[location]
35
+ @cache[key] << nick
36
+ @raw_cache[key] = Array.new unless @raw_cache[location]
37
+ @raw_cache[key] << string
38
+ unless(location.nil?)
38
39
  channel = find_model(location)
39
40
  Models::NickChannel.find_or_create(:channel_id => channel.pk, :nick_id => nick.pk)
40
41
  if(info.include?('+'))
@@ -8,12 +8,20 @@ module ModSpox
8
8
  # mask:: Mask to authenticate source against
9
9
  # authed:: Nick has authenticated
10
10
  class Auth < Sequel::Model(:auths)
11
+
12
+ before_destroy :clear_auth_groups
13
+
14
+ # Clear relations before destroying
15
+ def clear_auth_groups
16
+ AuthGroup.filter(:auth_id => pk).destroy
17
+ end
11
18
 
12
19
  # Nick associated with this Auth
13
20
  def nick
14
21
  Nick[nick_id]
15
22
  end
16
23
 
24
+ # Is nick identified with services
17
25
  def services
18
26
  s = values[:services]
19
27
  if(s == 0 || s == '0' || !s)
@@ -23,7 +23,7 @@ module ModSpox
23
23
  def self.[]=(key, val)
24
24
  key = key.to_s if key.is_a?(Symbol)
25
25
  model = Config.find_or_create(:name => key)
26
- model.value = val
26
+ model.update_with_params(:value => val)
27
27
  model.save
28
28
  end
29
29
  end
@@ -9,7 +9,7 @@ module ModSpox
9
9
  class Setting < Sequel::Model(:settings)
10
10
 
11
11
  def value=(val)
12
- update_values(:value => [Marshal.dump(val)].pack('m'))
12
+ update_values(:value => [Marshal.dump(val.dup)].pack('m'))
13
13
  end
14
14
 
15
15
  def value
@@ -31,7 +31,7 @@ module ModSpox
31
31
  def self.[]=(key, val)
32
32
  key = key.to_s if key.is_a?(Symbol)
33
33
  model = Setting.find_or_create(:name => key)
34
- model.update_with_params(:value => [Marshal.dump(val)].pack('m'))
34
+ model.update_with_params(:value => [Marshal.dump(val.dup)].pack('m'))
35
35
  end
36
36
  end
37
37
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: mod_spox
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.5
7
- date: 2008-06-12 00:00:00 -07:00
6
+ version: 0.1.0
7
+ date: 2008-07-11 00:00:00 -07:00
8
8
  summary: The mod_spox IRC robot
9
9
  require_paths:
10
10
  - lib
@@ -46,17 +46,6 @@ files:
46
46
  - lib/mod_spox/models/NickMode.rb
47
47
  - lib/mod_spox/models/Group.rb
48
48
  - lib/mod_spox/models/Models.rb
49
- - lib/mod_spox/migration/001_create_channel_modes.rb
50
- - lib/mod_spox/migration/001_create_nick_modes.rb
51
- - lib/mod_spox/migration/001_create_nick_channels.rb
52
- - lib/mod_spox/migration/001_create_settings.rb
53
- - lib/mod_spox/migration/001_create_auths.rb
54
- - lib/mod_spox/migration/001_create_signatures.rb
55
- - lib/mod_spox/migration/001_create_config.rb
56
- - lib/mod_spox/migration/001_create_triggers.rb
57
- - lib/mod_spox/migration/001_create_nicks.rb
58
- - lib/mod_spox/migration/001_create_channel.rb
59
- - lib/mod_spox/migration/001_create_servers.rb
60
49
  - lib/mod_spox/handlers/LuserClient.rb
61
50
  - lib/mod_spox/handlers/Handler.rb
62
51
  - lib/mod_spox/handlers/Topic.rb
@@ -249,6 +238,7 @@ files:
249
238
  - data/mod_spox/extras/Logger.rb
250
239
  - data/mod_spox/extras/Topten.rb
251
240
  - data/mod_spox/extras/AutoMode.rb
241
+ - data/mod_spox/extras/Bouncer.rb
252
242
  test_files: []
253
243
 
254
244
  rdoc_options: []
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateAuths < Sequel::Migration
4
- def up
5
- Models::Auth.create_table unless Models::Auth.table_exists?
6
- end
7
-
8
- def down
9
- Models::Auth.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateChannels < Sequel::Migration
4
- def up
5
- Models::Channel.create_table unless Models::Channel.table_exists?
6
- end
7
-
8
- def down
9
- Models::Channel.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateChannelModes < Sequel::Migration
4
- def up
5
- Models::ChannelMode.create_table unless Models::ChannelMode.table_exists?
6
- end
7
-
8
- def down
9
- Models::ChannelMode.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateConfigs < Sequel::Migration
4
- def up
5
- Models::Config.create_table unless Models::Config.table_exists?
6
- end
7
-
8
- def down
9
- Models::Config.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateNickChannels < Sequel::Migration
4
- def up
5
- Models::NickChannel.create_table unless Models::NickChannel.table_exists?
6
- end
7
-
8
- def down
9
- Models::NickChannel.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateNickModes < Sequel::Migration
4
- def up
5
- Models::NickMode.create_table unless Models::NickMode.table_exists?
6
- end
7
-
8
- def down
9
- Models::NickMode.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateNicks < Sequel::Migration
4
- def up
5
- Models::Nick.create_table unless Models::Nick.table_exists?
6
- end
7
-
8
- def down
9
- Models::Nick.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateServers < Sequel::Migration
4
- def up
5
- Models::Server.create_table unless Models::Server.table_exists?
6
- end
7
-
8
- def down
9
- Models::Server.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateSettings < Sequel::Migration
4
- def up
5
- Models::Setting.create_table unless Models::Setting.table_exists?
6
- end
7
-
8
- def down
9
- Models::Setting.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateSignatures < Sequel::Migration
4
- def up
5
- Models::Signature.create_table unless Models::Signature.table_exists?
6
- end
7
-
8
- def down
9
- Models::Signature.drop_table
10
- end
11
- end
12
- end
13
- end
@@ -1,13 +0,0 @@
1
- module ModSpox
2
- module Migrators
3
- class CreateTriggers < Sequel::Migration
4
- def up
5
- Models::Trigger.create_table unless Models::Trigger.table_exists?
6
- end
7
-
8
- def down
9
- Models::Trigger.drop_table
10
- end
11
- end
12
- end
13
- end