spox-mod_spox 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/README.rdoc +61 -1
- data/bin/mod_spox +1 -7
- data/data/mod_spox/extras/AutoKick.rb +3 -2
- data/data/mod_spox/extras/AutoMode.rb +2 -1
- data/data/mod_spox/extras/AutoRejoin.rb +5 -4
- data/data/mod_spox/extras/Bouncer.rb +243 -131
- data/data/mod_spox/extras/FloodKicker.rb +2 -1
- data/data/mod_spox/extras/Fortune.rb +5 -1
- data/data/mod_spox/extras/Karma.rb +2 -1
- data/data/mod_spox/extras/Logger.rb +11 -9
- data/data/mod_spox/extras/NickServ.rb +2 -1
- data/data/mod_spox/extras/PhpCli.rb +1 -1
- data/data/mod_spox/extras/PhpFuncLookup.rb +2 -1
- data/data/mod_spox/extras/RegexTracker.rb +2 -1
- data/data/mod_spox/extras/Roulette.rb +2 -1
- data/data/mod_spox/extras/Seen.rb +10 -8
- data/data/mod_spox/extras/Topten.rb +2 -1
- data/data/mod_spox/extras/Translate.rb +2 -1
- data/data/mod_spox/extras/Twitter.rb +1 -1
- data/data/mod_spox/plugins/Authenticator.rb +7 -7
- data/data/mod_spox/plugins/Banner.rb +6 -6
- data/data/mod_spox/plugins/BotNick.rb +2 -1
- data/data/mod_spox/plugins/Initializer.rb +4 -4
- data/data/mod_spox/plugins/Joiner.rb +1 -1
- data/data/mod_spox/plugins/PluginLoader.rb +1 -1
- data/data/mod_spox/plugins/Ponger.rb +8 -8
- data/data/mod_spox/plugins/Status.rb +1 -1
- data/lib/mod_spox/Bot.rb +27 -27
- data/lib/mod_spox/BotConfig.rb +17 -21
- data/lib/mod_spox/Filter.rb +29 -0
- data/lib/mod_spox/FilterManager.rb +63 -0
- data/lib/mod_spox/Helpers.rb +120 -14
- data/lib/mod_spox/Loader.rb +1 -1
- data/lib/mod_spox/MessageFactory.rb +10 -2
- data/lib/mod_spox/Pipeline.rb +66 -61
- data/lib/mod_spox/PluginManager.rb +5 -5
- data/lib/mod_spox/PriorityQueue.rb +21 -8
- data/lib/mod_spox/Sockets.rb +6 -6
- data/lib/mod_spox/Timer.rb +3 -3
- data/lib/mod_spox/Version.rb +2 -2
- data/lib/mod_spox/handlers/UserHost.rb +32 -0
- data/lib/mod_spox/handlers/Whois.rb +7 -7
- data/lib/mod_spox/messages/incoming/Pong.rb +11 -2
- data/lib/mod_spox/messages/incoming/UserHost.rb +24 -0
- data/lib/mod_spox/messages/internal/FilterAdd.rb +20 -0
- data/lib/mod_spox/messages/internal/FilterList.rb +18 -0
- data/lib/mod_spox/messages/internal/FilterListing.rb +22 -0
- data/lib/mod_spox/messages/internal/FilterRemove.rb +20 -0
- data/lib/mod_spox/messages/internal/Incoming.rb +15 -0
- data/lib/mod_spox/migrations/006_ignore.rb +21 -0
- data/lib/mod_spox/models/Nick.rb +11 -0
- data/lib/mod_spox/rfc2812.rb +2 -1
- data/lib/mod_spox/rfc2812_full.rb +185 -0
- data/tests/BotHolder.rb +7 -1
- data/tests/handlers/tc_Created.rb +28 -8
- data/tests/handlers/tc_Invite.rb +11 -9
- data/tests/handlers/tc_Join.rb +36 -16
- data/tests/handlers/tc_Kick.rb +27 -6
- data/tests/handlers/tc_Mode.rb +23 -13
- data/tests/handlers/tc_Names.rb +29 -9
- data/tests/handlers/tc_Nick.rb +30 -8
- data/tests/handlers/tc_Part.rb +30 -20
- data/tests/handlers/tc_Ping.rb +32 -19
- data/tests/handlers/tc_Pong.rb +28 -8
- data/tests/handlers/tc_Privmsg.rb +33 -13
- data/tests/handlers/tc_Quit.rb +30 -17
- data/tests/handlers/tc_Who.rb +8 -3
- data/tests/handlers/tc_Whois.rb +7 -3
- data/tests/lib/tc_BotConfig.rb +35 -0
- data/tests/lib/tc_Helpers.rb +139 -0
- data/tests/lib/tc_PriorityQueue.rb +31 -0
- metadata +17 -2
@@ -0,0 +1,63 @@
|
|
1
|
+
module ModSpox
|
2
|
+
class FilterManager
|
3
|
+
|
4
|
+
def initialize(pipeline)
|
5
|
+
@pipeline = pipeline
|
6
|
+
@filters = {}
|
7
|
+
[:FilterAdd, :FilterRemove, :FilterList, :FilterListing].each{|f| Helpers.load_message(:internal, f)}
|
8
|
+
@pipeline.hook(self, :add_filter, ModSpox::Messages::Internal::FilterAdd)
|
9
|
+
@pipeline.hook(self, :remove_filter, ModSpox::Messages::Internal::FilterRemove)
|
10
|
+
@pipeline.hook(self, :list_filter, ModSpox::Messages::Internal::FilterList)
|
11
|
+
end
|
12
|
+
|
13
|
+
# filter:: ModSpox::Filter object
|
14
|
+
# type:: type of message to filter
|
15
|
+
def add(filter, type)
|
16
|
+
type = Helpers.find_const(type)
|
17
|
+
@filters[type] ||= []
|
18
|
+
@filters[type] << filter
|
19
|
+
end
|
20
|
+
|
21
|
+
# filter:: ModSpox::Filter object
|
22
|
+
# type:: type of message filter is associated to
|
23
|
+
# Remove a filter. If a type is defined, the filter
|
24
|
+
# will only be removed from that type. If no type is
|
25
|
+
# defined, the filter will be removed completely
|
26
|
+
def remove(filter, type=nil)
|
27
|
+
if(type.nil?)
|
28
|
+
@filters.each do |ar|
|
29
|
+
ar.delete_if do |key, value|
|
30
|
+
value == filter
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
type = Helpers.find_const(type)
|
35
|
+
if(@filters[type])
|
36
|
+
key = @filters[type].index(filter)
|
37
|
+
@filters[type].delete(key) if key
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# type:: type of message
|
43
|
+
# Return array of filters. Will only return
|
44
|
+
def filters(type=nil)
|
45
|
+
if(type.nil?)
|
46
|
+
return @filters.dup
|
47
|
+
else
|
48
|
+
type = Helpers.find_const(type)
|
49
|
+
return @filters[type] ? @filters[type].dup : nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# m:: message from pipeline
|
54
|
+
# Applies filters to messages from pipeline
|
55
|
+
def apply_filters(m)
|
56
|
+
@filters.keys.each do |type|
|
57
|
+
if(Helpers.type_of?(m, type))
|
58
|
+
@filters[type].each{|f| f.filter(m)}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/mod_spox/Helpers.rb
CHANGED
@@ -11,8 +11,8 @@ module ModSpox
|
|
11
11
|
# secs:: number of seconds
|
12
12
|
# Converts seconds into a human readable string
|
13
13
|
def Helpers.format_seconds(secs)
|
14
|
-
arg = {:year =>
|
15
|
-
:month =>
|
14
|
+
arg = {:year => 31536000,
|
15
|
+
:month => 2678400,
|
16
16
|
:week => 604800,
|
17
17
|
:day => 86400,
|
18
18
|
:hour => 3600,
|
@@ -44,29 +44,37 @@ module ModSpox
|
|
44
44
|
"Yotta" # 1024^8
|
45
45
|
]
|
46
46
|
def Helpers.format_size(bytes)
|
47
|
+
return "0 bytes" if bytes == 0
|
47
48
|
mag = (Math.log(bytes) / Math.log(1024)).floor
|
48
49
|
mag = [ Suff.length - 1, mag ].min
|
49
50
|
val = bytes.to_f / (1024 ** mag)
|
50
|
-
"
|
51
|
+
("%.3f %sbyte%s" % [ val, Suff[mag], val == 1 ? "" : "s" ]).strip
|
51
52
|
end
|
52
53
|
|
53
54
|
# command:: command to execute
|
54
55
|
# timeout:: maximum number of seconds to run
|
56
|
+
# maxbytes:: maximum number of result bytes to accept
|
55
57
|
# Execute a system command (use with care)
|
56
|
-
def Helpers.safe_exec(command, timeout=10)
|
58
|
+
def Helpers.safe_exec(command, timeout=10, maxbytes=500)
|
59
|
+
output = []
|
60
|
+
pro = nil
|
57
61
|
begin
|
58
62
|
Timeout::timeout(timeout) do
|
59
|
-
|
63
|
+
pro = IO.popen(command)
|
64
|
+
until(pro.closed? || pro.eof?)
|
65
|
+
output << pro.getc
|
66
|
+
raise IOError.new("Maximum allowed output bytes exceeded. (#{maxbytes} bytes)") unless output.count <= maxbytes
|
67
|
+
end
|
60
68
|
end
|
61
|
-
|
62
|
-
Logger.warn("Command execution exceeded allowed time (command: #{command} | timeout: #{timeout})")
|
63
|
-
raise boom
|
69
|
+
output = output.join('')
|
64
70
|
rescue Object => boom
|
65
|
-
Logger.warn("Command generated an exception (command: #{command} | error: #{boom})")
|
66
71
|
raise boom
|
72
|
+
ensure
|
73
|
+
Process.kill('KILL', pro.pid) if Process.waitpid2(pro.pid, Process::WNOHANG).nil? # make sure the process is dead
|
67
74
|
end
|
75
|
+
return output
|
68
76
|
end
|
69
|
-
|
77
|
+
|
70
78
|
# url:: URL to shorten
|
71
79
|
# Gets a tinyurl for given URL
|
72
80
|
def Helpers.tinyurl(url)
|
@@ -87,13 +95,13 @@ module ModSpox
|
|
87
95
|
# or channel name. If the string given does not match the required
|
88
96
|
# pattern for a channel or nick, the string is returned.
|
89
97
|
def Helpers.find_model(string, create=true)
|
90
|
-
result =
|
98
|
+
result = string
|
91
99
|
if(string =~ /^[A-Za-z\|\\\{\}\[\]\^\`~\_\-]+[A-Za-z0-9\|\\\{\}\[\]\^\`~\_\-]*$/)
|
92
100
|
result = Models::Nick.find_or_create(:nick => string.downcase)
|
93
101
|
elsif(['&', '#', '+', '!'].include?(string[0]))
|
94
102
|
result = Models::Channel.find_or_create(:name => string.downcase)
|
95
|
-
elsif(Models::Server.filter(:host => string
|
96
|
-
result = Models::Server.filter(:host => string
|
103
|
+
elsif(Models::Server.filter(:host => string).count > 0)
|
104
|
+
result = Models::Server.filter(:host => string).first
|
97
105
|
else
|
98
106
|
Logger.warn("Failed to match string to model: #{string} -> No match")
|
99
107
|
end
|
@@ -115,8 +123,106 @@ module ModSpox
|
|
115
123
|
# kind:: (:internal|:incoming|:outgoing)
|
116
124
|
# type:: message type (Example: :Privmsg)
|
117
125
|
# Easy loader for messages
|
118
|
-
def load_message(kind, type)
|
126
|
+
def Helpers.load_message(kind, type)
|
127
|
+
raise ArgumentError.new('Valid kind types: :internal, :incoming, :outgoing') unless [:internal, :incoming, :outgoing].include?(kind)
|
119
128
|
require "mod_spox/messages/#{kind}/#{type}"
|
120
129
|
end
|
130
|
+
|
131
|
+
# a:: object
|
132
|
+
# b:: type constant or string
|
133
|
+
# symbolize:: Symbolize and check (deprecated)
|
134
|
+
# Determines if a is a type of b. For example:
|
135
|
+
#
|
136
|
+
# a = Foo::Bar.new
|
137
|
+
# Helpers.type_of?(a, Foo) -> true
|
138
|
+
def Helpers.type_of?(a, b, symbolize=false)
|
139
|
+
return true if (b.is_a?(Class) || b.is_a?(Module)) && a.is_a?(b) # if only it were always this easy
|
140
|
+
checks = []
|
141
|
+
# first, we strip the front down
|
142
|
+
t = a.class.to_s
|
143
|
+
unless(t.index('ModSpox::Messages::').nil?)
|
144
|
+
t.slice!(t.index('ModSpox::Messages::'), 19)
|
145
|
+
checks << t
|
146
|
+
end
|
147
|
+
t = a.class.to_s
|
148
|
+
if(t.slice(0) == '<')
|
149
|
+
t.slice!(0, t.rindex('>'))
|
150
|
+
checks << t
|
151
|
+
end
|
152
|
+
checks << a.class.to_s
|
153
|
+
checks.each do |s|
|
154
|
+
until(s.index('::').nil?) do
|
155
|
+
s.slice!(s.rindex('::'), s.length - s.rindex('::'))
|
156
|
+
return true if s =~ /#{b}.*/
|
157
|
+
end
|
158
|
+
end
|
159
|
+
# one last check if we are allowed to symbolize
|
160
|
+
if(symbolize && b.is_a?(Symbol))
|
161
|
+
sym = a.class.to_s
|
162
|
+
sym.gsub!('::', '_')
|
163
|
+
return true if sym == b || b =~ /#{sym}.*/
|
164
|
+
sym.slice!(0, 17) if sym.index('ModSpox_Messages') == 0
|
165
|
+
sym.slice!(0, sym.index('>')+1) if sym.index('<') == 0 # this is for dynamic objects from plugins
|
166
|
+
return true if sym == b || b =~ /#{sym}.*/
|
167
|
+
end
|
168
|
+
return false
|
169
|
+
end
|
170
|
+
|
171
|
+
# c:: constant name (String)
|
172
|
+
# Finds a constant if it exists
|
173
|
+
# Example:: Foo::Bar
|
174
|
+
def Helpers.find_const(c)
|
175
|
+
return c unless c.is_a?(String)
|
176
|
+
const = nil
|
177
|
+
[Kernel, ModSpox, Messages].each do |base|
|
178
|
+
begin
|
179
|
+
c.split('::').each do |part|
|
180
|
+
const = const.nil? ? base.const_get(part) : const.const_get(part)
|
181
|
+
end
|
182
|
+
rescue NameError
|
183
|
+
const = nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
return const.nil? ? c : const
|
187
|
+
end
|
188
|
+
|
189
|
+
# IdealHumanRandomIterator - select "random" members of a population, favoring
|
190
|
+
# those least-recently selected, to appease silly humans who hate repeats
|
191
|
+
#
|
192
|
+
# Abstract:
|
193
|
+
# given a decently-sized set of items (say, 100 famous quotes), an
|
194
|
+
# average persons's idea of N "random" entries is not actually random.
|
195
|
+
# people don't want items to appear twice in a row, or too frequently
|
196
|
+
# (even though true randomness means this is just as likely as any other order).
|
197
|
+
#
|
198
|
+
# instead, design a scheme whereby LRU items are weighted more heavily,
|
199
|
+
# to "encourage" subsequent selections to not repeat.
|
200
|
+
#
|
201
|
+
# Author: Ryan "pizza_" Flynn
|
202
|
+
# - pulled from the algodict project
|
203
|
+
# - - http://github.com/pizza/algodict
|
204
|
+
class IdealHumanRandomIterator
|
205
|
+
|
206
|
+
def initialize(list)
|
207
|
+
raise ArgumentError.new("Array type required") unless list.is_a?(Array)
|
208
|
+
@items = list
|
209
|
+
end
|
210
|
+
|
211
|
+
# Given length L, generate a random number in the range [0,len-1), heavily
|
212
|
+
# weighted towards the low end.
|
213
|
+
def self.nexti(len)
|
214
|
+
len += 1 if len % 2 == 1
|
215
|
+
index = len > 2 ? rand(len/2) : 0
|
216
|
+
return index
|
217
|
+
end
|
218
|
+
|
219
|
+
# return a psuedo-random member of items. subsequent calls should never
|
220
|
+
# return the same item.
|
221
|
+
def next()
|
222
|
+
index = IdealHumanRandomIterator.nexti(@items.length)
|
223
|
+
@items.push @items.delete_at(index)
|
224
|
+
return @items.last
|
225
|
+
end
|
226
|
+
end
|
121
227
|
end
|
122
228
|
end
|
data/lib/mod_spox/Loader.rb
CHANGED
@@ -38,7 +38,7 @@ module ModSpox
|
|
38
38
|
Database.db = Sequel.connect("#{ModSpox.jdbc ? 'jdbc:' : ''}postgres://#{config[:db_username]}:#{config[:db_password]}@#{config[:db_host]}/#{config[:db_database]}")
|
39
39
|
Database.type = :pgsql
|
40
40
|
when 'sqlite'
|
41
|
-
Database.db = Sequel.
|
41
|
+
Database.db = Sequel.connect("#{ModSpox.jdbc ? 'jdbc:' : ''}sqlite://#{BotConfig[:userpath]}/mod_spox.db", :pool_timeout => 20, :timeout => 5000)
|
42
42
|
Database.type = :sqlite
|
43
43
|
end
|
44
44
|
end
|
@@ -21,6 +21,13 @@ module ModSpox
|
|
21
21
|
@sync = [:RPL_MOTDSTART, :RPL_MOTD, :RPL_ENDOFMOTD, :RPL_WHOREPLY, :RPL_ENDOFWHO,
|
22
22
|
:RPL_NAMREPLY, :RPL_ENDOFNAMES, :RPL_WHOISUSER, :RPL_WHOISSERVER, :RPL_WHOISOPERATOR,
|
23
23
|
:RPL_WHOISIDLE, :RPL_WHOISCHANNELS, :RPL_WHOISIDENTIFIED, :RPL_ENDOFWHOIS].map{|s| RFC[s][:value]}
|
24
|
+
@pipeline.hook(self, :proc_internal, ModSpox::Messages::Internal::Incoming)
|
25
|
+
end
|
26
|
+
|
27
|
+
# m:: ModSpox::Messages::Internal::Incoming
|
28
|
+
# Process internal raw message
|
29
|
+
def proc_internal(m)
|
30
|
+
self << m.message
|
24
31
|
end
|
25
32
|
|
26
33
|
# string:: server message to be parsed
|
@@ -76,10 +83,10 @@ module ModSpox
|
|
76
83
|
end
|
77
84
|
end
|
78
85
|
else
|
79
|
-
Logger.
|
86
|
+
Logger.warn("No handler was found to process message of type: #{key} Message: #{message}")
|
80
87
|
raise Exceptions::HandlerNotFound.new(key)
|
81
88
|
end
|
82
|
-
rescue Exceptions::HandlerNotFound => boom
|
89
|
+
rescue ModSpox::Exceptions::HandlerNotFound => boom
|
83
90
|
unless(loaded)
|
84
91
|
if(@available[boom.message_type])
|
85
92
|
@available[boom.message_type].each do|f|
|
@@ -96,6 +103,7 @@ module ModSpox
|
|
96
103
|
retry
|
97
104
|
end
|
98
105
|
end
|
106
|
+
Logger.error("Failed to find a handler for: #{boom.message_type}")
|
99
107
|
raise boom
|
100
108
|
rescue Object => boom
|
101
109
|
if(boom.class.to_s == 'SQLite3::BusyException' || boom.class.to_s == 'PGError')
|
data/lib/mod_spox/Pipeline.rb
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
'mod_spox/Logger',
|
3
3
|
'mod_spox/Exceptions',
|
4
4
|
'mod_spox/messages/incoming/Privmsg',
|
5
|
-
'mod_spox/messages/incoming/Notice'
|
5
|
+
'mod_spox/messages/incoming/Notice',
|
6
|
+
'mod_spox/FilterManager'].each{|f|require f}
|
6
7
|
module ModSpox
|
7
8
|
|
8
9
|
class Pipeline
|
@@ -16,8 +17,9 @@ module ModSpox
|
|
16
17
|
@populate_lock = Mutex.new
|
17
18
|
populate_triggers
|
18
19
|
populate_signatures
|
19
|
-
hook(self, :populate_triggers,
|
20
|
-
hook(self, :populate_signatures,
|
20
|
+
hook(self, :populate_triggers, ModSpox::Messages::Internal::TriggersUpdate)
|
21
|
+
hook(self, :populate_signatures, ModSpox::Messages::Internal::SignaturesUpdate)
|
22
|
+
@filters = FilterManager.new(self)
|
21
23
|
end
|
22
24
|
|
23
25
|
# message:: Message to send down pipeline
|
@@ -52,12 +54,12 @@ module ModSpox
|
|
52
54
|
# Hooks a plugin into the pipeline for a specific type of message
|
53
55
|
def hook(object, method, type)
|
54
56
|
Logger.info("Object #{object.class.to_s} hooking into messages of type: #{type}")
|
55
|
-
type =
|
57
|
+
type = Helpers.find_const(type)
|
56
58
|
method = method.to_sym unless method.is_a?(Symbol)
|
57
|
-
name = object.class
|
58
|
-
@hooks[type]
|
59
|
-
@hooks[type][name
|
60
|
-
@hooks[type][name
|
59
|
+
name = object.class
|
60
|
+
@hooks[type] ||= Hash.new
|
61
|
+
@hooks[type][name] ||= Array.new
|
62
|
+
@hooks[type][name] << {:object => object, :method => method}
|
61
63
|
end
|
62
64
|
|
63
65
|
# plugin:: Plugin to unhook from pipeline
|
@@ -65,8 +67,8 @@ module ModSpox
|
|
65
67
|
# This will remove the hook a plugin has for a specific message type
|
66
68
|
def unhook(object, method, type)
|
67
69
|
Logger.info("Object #{object.class.to_s} unhooking from messages of type: #{type}")
|
68
|
-
type =
|
69
|
-
name = object.class
|
70
|
+
type = Helpers.find_const(type)
|
71
|
+
name = object.class
|
70
72
|
raise Exceptions::InvalidValue.new("Unknown hook type given: #{type.to_s}") unless @hooks.has_key?(type)
|
71
73
|
raise Exceptions::InvalidValue.new("Unknown object hooked: #{name.to_s}") unless @hooks[type].has_key?(name)
|
72
74
|
@hooks[type][name].each{|hook|
|
@@ -100,7 +102,7 @@ module ModSpox
|
|
100
102
|
a.destroy
|
101
103
|
Models::Signature.all.each do |s|
|
102
104
|
c = s.signature[0].chr.downcase
|
103
|
-
if(c =~ /^[
|
105
|
+
if(c =~ /^[A-Za-z]$/)
|
104
106
|
type = c.to_sym
|
105
107
|
elsif(c =~ /^[0-9]$/)
|
106
108
|
type = :digit
|
@@ -119,39 +121,26 @@ module ModSpox
|
|
119
121
|
|
120
122
|
# Processes messages
|
121
123
|
def message_processor(message)
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
if(@hooks.has_key?(type))
|
130
|
-
@hooks[type].each_value do |objects|
|
124
|
+
@filters.apply_filters(message)
|
125
|
+
return if message.nil?
|
126
|
+
@hooks.keys.each do |type|
|
127
|
+
next unless Helpers.type_of?(message, type, true)
|
128
|
+
@hooks[type].each_value do |objects|
|
129
|
+
objects.each do |v|
|
130
|
+
@pool.process do
|
131
131
|
begin
|
132
|
-
|
133
|
-
@pool.process do
|
134
|
-
begin
|
135
|
-
v[:object].send(v[:method].to_s, message)
|
136
|
-
rescue Object => boom
|
137
|
-
if(boom.class.to_s == 'SQLite3::BusyException')
|
138
|
-
Database.reset_connections
|
139
|
-
retry
|
140
|
-
else
|
141
|
-
raise boom
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
132
|
+
v[:object].send(v[:method], message)
|
146
133
|
rescue Object => boom
|
147
|
-
|
134
|
+
if(boom.class.to_s == 'SQLite3::BusyException')
|
135
|
+
Database.reset_connections
|
136
|
+
end
|
137
|
+
raise boom
|
148
138
|
end
|
149
139
|
end
|
150
140
|
end
|
151
141
|
end
|
152
|
-
rescue Object => boom
|
153
|
-
Logger.warn("Pipeline encountered an exception while processing a message: #{boom}\n#{boom.backtrace.join("\n")}")
|
154
142
|
end
|
143
|
+
parse(message)
|
155
144
|
end
|
156
145
|
|
157
146
|
# message:: Message to parse
|
@@ -159,49 +148,65 @@ module ModSpox
|
|
159
148
|
# trigger signatures. If matches are found, they will be sent
|
160
149
|
# to the proper plugin for processing
|
161
150
|
def parse(message)
|
162
|
-
return unless message.
|
151
|
+
return unless message.is_a?(Messages::Incoming::Privmsg) || message.is_a?(Messages::Incoming::Notice)
|
163
152
|
trigger = nil
|
164
153
|
@triggers.each{|t| trigger = t if message.message[0..t.size-1] == t}
|
165
|
-
|
166
|
-
return if
|
167
|
-
Logger.info(
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
154
|
+
unless(trigger.nil? && !message.addressed?)
|
155
|
+
return if trigger && message.message.length == trigger.length
|
156
|
+
Logger.info('Messages has matched a known trigger')
|
157
|
+
# okay, so now that we know we are being asked to do something, lets find
|
158
|
+
# a signature that might match. Signatures are sorted by first character
|
159
|
+
# so once we have that we can get rolling
|
160
|
+
c = (message.addressed? && trigger.nil?) ? message.message[0].chr : message.message[trigger.length].chr
|
161
|
+
case c
|
162
|
+
when /[A-Za-z]/
|
163
|
+
type = c.to_sym
|
164
|
+
when /\d/
|
165
|
+
type = :digit
|
166
|
+
else
|
167
|
+
type = :other
|
175
168
|
end
|
176
|
-
sig_check = @signatures
|
177
|
-
sig_check
|
169
|
+
sig_check = @signatures[type] ? @signatures[type] : []
|
170
|
+
sig_check += @signatures[:other] if @signatures[:other] && type != :other # others are always checked because they are fickle shells of what they once were
|
178
171
|
sig_check.each do |sig|
|
179
172
|
Logger.info("Matching against: #{trigger}#{sig.signature}")
|
180
173
|
esc_trig = trigger.nil? ? '' : Regexp.escape(trigger)
|
181
|
-
|
182
|
-
if(
|
183
|
-
next unless
|
184
|
-
next if sig.requirement == 'private' && message.is_public?
|
185
|
-
next if sig.requirement == 'public' && message.is_private?
|
174
|
+
result = message.message.scan(/^#{esc_trig}#{sig.signature}$/)
|
175
|
+
if(result.size > 0 && @plugins[sig.plugin.to_sym])
|
176
|
+
next unless allowed?(message, sig)
|
186
177
|
params = Hash.new
|
178
|
+
# symbolize up the parameters for symbolic symbolism
|
187
179
|
sig.params.size.times do |i|
|
188
|
-
params[sig.params[i].to_sym] =
|
189
|
-
Logger.info("Signature params: #{sig.params[i]
|
180
|
+
params[sig.params[i].to_sym] = result[0][i]
|
181
|
+
Logger.info("Signature params: #{sig.params[i]} = #{result[0][i]}")
|
190
182
|
end
|
191
|
-
|
183
|
+
# throw it in the pool for processing
|
184
|
+
@pool.process do
|
192
185
|
begin
|
193
|
-
@
|
186
|
+
@plugins[sig.plugin.to_sym].send(sig.values[:method], message, params)
|
194
187
|
rescue Object => boom
|
195
|
-
|
188
|
+
if(boom.class.to_s == 'SQLite3::BusyException')
|
189
|
+
Database.reset_connections
|
190
|
+
end
|
191
|
+
raise boom
|
196
192
|
end
|
197
193
|
end
|
198
194
|
end
|
199
195
|
end
|
200
196
|
else
|
201
|
-
Logger.info(
|
197
|
+
Logger.info('Message failed to match any known trigger')
|
202
198
|
end
|
203
199
|
end
|
204
200
|
|
201
|
+
# message:: ModSpox::Messages::Incoming
|
202
|
+
# sig:: ModSpox::Models::Signature
|
203
|
+
# Check if the given message is allowed to be processed
|
204
|
+
def allowed?(message, sig)
|
205
|
+
return false if sig.requirement == 'private' && message.is_public?
|
206
|
+
return false if sig.requirement == 'public' && message.is_private?
|
207
|
+
return (message.source.in_group?(sig.group) || message.source.in_group?(@admin) || sig.group.nil?)
|
208
|
+
end
|
209
|
+
|
205
210
|
end
|
206
211
|
|
207
212
|
end
|