mod_spox 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +1 -1
- data/README +6 -2
- data/bin/mod_spox +15 -9
- data/data/mod_spox/extras/AOLSpeak.rb +271 -0
- data/data/mod_spox/extras/AutoKick.rb +119 -0
- data/data/mod_spox/extras/AutoRejoin.rb +14 -0
- data/data/mod_spox/extras/Bullshit.rb +19 -0
- data/data/mod_spox/extras/Confess.rb +166 -0
- data/data/mod_spox/extras/DevWatch.rb +154 -0
- data/data/mod_spox/extras/EightBall.rb +31 -0
- data/data/mod_spox/extras/Headers.rb +50 -0
- data/data/mod_spox/extras/Karma.rb +16 -17
- data/data/mod_spox/extras/LolSpeak.rb +22 -0
- data/data/mod_spox/extras/PhpCli.rb +146 -0
- data/data/mod_spox/extras/PhpFuncLookup.rb +261 -0
- data/data/mod_spox/extras/Quotes.rb +80 -0
- data/data/mod_spox/extras/Roulette.rb +24 -3
- data/data/mod_spox/extras/Talk.rb +41 -0
- data/data/mod_spox/extras/Translate.rb +95 -0
- data/data/mod_spox/extras/Weather.rb +55 -0
- data/data/mod_spox/plugins/Authenticator.rb +12 -0
- data/data/mod_spox/plugins/Banner.rb +3 -3
- data/data/mod_spox/plugins/Helper.rb +37 -0
- data/lib/mod_spox/Bot.rb +1 -1
- data/lib/mod_spox/ConfigurationWizard.rb +12 -5
- data/lib/mod_spox/MessageFactory.rb +1 -2
- data/lib/mod_spox/Monitors.rb +26 -8
- data/lib/mod_spox/Pipeline.rb +13 -13
- data/lib/mod_spox/PluginManager.rb +12 -1
- data/lib/mod_spox/Pool.rb +212 -29
- data/lib/mod_spox/Socket.rb +6 -6
- data/lib/mod_spox/Timer.rb +6 -8
- data/lib/mod_spox/handlers/Handler.rb +1 -1
- data/lib/mod_spox/handlers/Privmsg.rb +1 -0
- data/lib/mod_spox/handlers/Who.rb +1 -0
- data/lib/mod_spox/messages/internal/PluginRequest.rb +1 -1
- data/lib/mod_spox/messages/outgoing/Privmsg.rb +9 -1
- data/lib/mod_spox/models/Setting.rb +3 -3
- data/lib/mod_spox/models/Signature.rb +1 -1
- metadata +18 -20
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
|
6
|
+
# IMPORTANT NOTE: This plugin requires installation of the HTMLEntities gem
|
7
|
+
class Confess < ModSpox::Plugin
|
8
|
+
|
9
|
+
include Models
|
10
|
+
|
11
|
+
def initialize(pipeline)
|
12
|
+
super(pipeline)
|
13
|
+
begin
|
14
|
+
require 'htmlentities'
|
15
|
+
rescue Object => boom
|
16
|
+
Logger.log('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
|
17
|
+
raise Exceptions::BotException.new("Missing required HTMLEntities library")
|
18
|
+
end
|
19
|
+
Confession.create_table unless Confession.table_exists?
|
20
|
+
Signature.find_or_create(:signature => 'confess ?(.+)?', :plugin => name, :method => 'confess',
|
21
|
+
:description => 'Print a confession').params = [:term]
|
22
|
+
Signature.find_or_create(:signature => 'confess(\+\+|\-\-) ?(\d+)?', :plugin => name, :method => 'score',
|
23
|
+
:description => 'Score a confession').params = [:score, :id]
|
24
|
+
Signature.find_or_create(:signature => 'confess score (\d+)', :plugin => name, :method => 'show_score',
|
25
|
+
:description => 'Show a confession\'s score').params = [:id]
|
26
|
+
Signature.find_or_create(:signature => 'confess count', :plugin => name, :method => 'count',
|
27
|
+
:description => 'Current count of cached confessions')
|
28
|
+
Signature.find_or_create(:signature => 'confess fetcher (start|stop)', :plugin => name, :method => 'fetcher',
|
29
|
+
:description => 'Turn confession fetcher on or off', :group_id => Group.filter(:name => 'admin').first.pk).params = [:status]
|
30
|
+
Config[:confess] = 'nofetch' if Config[:confess].nil?
|
31
|
+
@last_confession = {}
|
32
|
+
@fetch = false
|
33
|
+
@mutex = Mutex.new
|
34
|
+
@coder = HTMLEntities.new
|
35
|
+
start_fetcher if Config[:confess] == 'fetch'
|
36
|
+
end
|
37
|
+
|
38
|
+
def confess(message, params)
|
39
|
+
c = nil
|
40
|
+
reg = false
|
41
|
+
if(params[:term])
|
42
|
+
if(params[:term] =~ /^\d+$/)
|
43
|
+
c = Confession[params[:term].to_i]
|
44
|
+
else
|
45
|
+
c = Confession.filter(:confession => Regexp.new(params[:term])).first
|
46
|
+
reg = true
|
47
|
+
end
|
48
|
+
else
|
49
|
+
ids = Confession.map(:id)
|
50
|
+
c = Confession[ids[rand(ids.size - 1)].to_i]
|
51
|
+
end
|
52
|
+
if(c)
|
53
|
+
reply message.replyto, "\2[#{c.pk}]\2: #{reg ? c.confession.gsub(/(#{params[:term]})/, "\2\\1\2") : c.confession}"
|
54
|
+
@last_confession[message.target.pk] = c.pk
|
55
|
+
else
|
56
|
+
reply message.replyto, "\2Error:\2 Failed to find confession"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def show_score(message, params)
|
61
|
+
c = Confession[params[:id].to_i]
|
62
|
+
if(c)
|
63
|
+
reply message.replyto, "\2[#{c.pk}]:\2 #{c.score.to_i}% of raters gave this confession a positive score"
|
64
|
+
else
|
65
|
+
reply message.replyto, "\2Error:\2 Failed to find confession with ID: #{params[:id]}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def score(message, params)
|
70
|
+
if(params[:id])
|
71
|
+
c = Confession[params[:id].to_i]
|
72
|
+
else
|
73
|
+
c = Confession[@last_confession[message.target.pk]] if @last_confession.has_key?(message.target.pk)
|
74
|
+
end
|
75
|
+
if(c)
|
76
|
+
if(params[:score] == '++')
|
77
|
+
c.set(:positive => c.positive.to_i + 1)
|
78
|
+
else
|
79
|
+
c.set(:negative => c.negative.to_i + 1)
|
80
|
+
end
|
81
|
+
c.set(:score => ((c.positive.to_f) / (c.positive.to_f + c.negative.to_f)) * 100.0)
|
82
|
+
else
|
83
|
+
reply message.replyto, "\2Error:\2 Failed to find confession to score"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def count(message, params)
|
88
|
+
reply message.replyto, "Current number of stored confessions: #{Confession.all.size}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def fetcher(message, params)
|
92
|
+
if(params[:status] == 'start')
|
93
|
+
if(Config[:confess] == 'fetch')
|
94
|
+
reply message.replyto, 'Confession fetcher is already running'
|
95
|
+
else
|
96
|
+
Config[:confess] = 'fetch'
|
97
|
+
reply message.replyto, 'Confession fetcher is now running'
|
98
|
+
start_fetcher
|
99
|
+
end
|
100
|
+
else
|
101
|
+
if(Config[:confess] == 'fetch')
|
102
|
+
Config[:confess] = 'nofetch'
|
103
|
+
reply message.replyto, 'Confession fetcher has been stopped'
|
104
|
+
else
|
105
|
+
reply message.replyto, 'Confession fetcher is not currently running'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def grab_page
|
111
|
+
begin
|
112
|
+
connection = Net::HTTP.new('beta.grouphug.us', 80)
|
113
|
+
response = connection.request_get('/random', nil)
|
114
|
+
response.value
|
115
|
+
page = response.body.gsub(/[\r\n]/, ' ')
|
116
|
+
Logger.log("Processing matches")
|
117
|
+
page.scan(/<div class="content">\s*<p>\s*(.+?)\s*<\/p>\s*<\/div>/).each{|match|
|
118
|
+
Logger.log("Match found: #{match[0]}")
|
119
|
+
conf = CGI::unescapeHTML(match[0])
|
120
|
+
conf = conf.gsub(/<.+?>/, ' ').gsub(/[\r\n]/, '').gsub(/\s+/, ' ')
|
121
|
+
conf = @coder.decode(conf)
|
122
|
+
Logger.log("Match turned into: #{conf}")
|
123
|
+
if conf.length < 300
|
124
|
+
begin
|
125
|
+
Confession.new(:confession => conf, :hash => Digest::MD5.hexdigest(conf)).save
|
126
|
+
rescue Object => boom
|
127
|
+
Logger.log 'Warning: Fetched confession already found in database'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
}
|
131
|
+
rescue Object => boom
|
132
|
+
Logger.log "Error fetching data: #{boom}"
|
133
|
+
end
|
134
|
+
if(Config[:confess] == 'fetch')
|
135
|
+
@pipeline << Messages::Internal::TimerAdd.new(self, rand(500), nil, true){ grab_page }
|
136
|
+
else
|
137
|
+
stop_fetcher
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def start_fetcher
|
144
|
+
@mutex.synchronize do
|
145
|
+
grab_page unless @fetch
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def stop_fetcher
|
150
|
+
@mutex.synchronize do
|
151
|
+
@fetch = false
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class Confession < Sequel::Model
|
156
|
+
set_schema do
|
157
|
+
text :confession, :null => false
|
158
|
+
text :hash, :null => false, :unique => true
|
159
|
+
integer :positive, :null => false, :default => 0
|
160
|
+
integer :negative, :null => false, :default => 0
|
161
|
+
float :score, :null => false, :default => 0
|
162
|
+
primary_key :id
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
class DevWatch < ModSpox::Plugin
|
5
|
+
|
6
|
+
include ModSpox::Models
|
7
|
+
|
8
|
+
def initialize(pipeline)
|
9
|
+
super(pipeline)
|
10
|
+
admin = Group.filter(:name => 'admin').first
|
11
|
+
Signature.find_or_create(:signature => 'devwatch (on|off) (\S+)', :plugin => name, :method => 'enable_watch', :group_id => admin.pk,
|
12
|
+
:description => 'Turn development watcher on/off in given channel').params = [:status, :channel]
|
13
|
+
Signature.find_or_create(:signature => 'devwatch list', :plugin => name, :method => 'watch_list', :group_id => admin.pk,
|
14
|
+
:description => 'List all channels on the development watch list')
|
15
|
+
Signature.find_or_create(:signature => 'devwatch url ?(\S+)?', :plugin => name, :method => 'set_url', :group_id => admin.pk,
|
16
|
+
:description => 'Set URL for development RSS feed').params = [:url]
|
17
|
+
Signature.find_or_create(:signature => 'devwatch interval ?(\d+)?', :plugin => name, :method => 'set_interval', :group_id => admin.pk,
|
18
|
+
:description => 'Set time interval for notifications').params = [:time]
|
19
|
+
if(Setting[:devwatch].nil?)
|
20
|
+
Setting.find_or_create(:name => 'devwatch').value = {:channels => [], :interval => 300}
|
21
|
+
end
|
22
|
+
@pipeline.hook(self, :timer_response, :Internal_TimerResponse)
|
23
|
+
@original = nil
|
24
|
+
@new = nil
|
25
|
+
@timer = nil
|
26
|
+
@lock = Mutex.new
|
27
|
+
run
|
28
|
+
end
|
29
|
+
|
30
|
+
def enable_watch(message, params)
|
31
|
+
channel = Channel.filter(:name => params[:channel]).first
|
32
|
+
if(channel)
|
33
|
+
vals = Setting[:devwatch]
|
34
|
+
if(params[:status] == 'on')
|
35
|
+
vals[:channels] << channel.pk unless vals[:channels].include?(channel.pk)
|
36
|
+
reply(message.replyto, "#{channel.name} is now on the development watch list")
|
37
|
+
else
|
38
|
+
vals[:channels].delete(channel.pk) if vals[:channels].include?(channel.pk)
|
39
|
+
reply(message.replyto, "#{channel.name} has been removed from the development watch list")
|
40
|
+
end
|
41
|
+
Setting.filter(:name => 'devwatch').first.value = vals
|
42
|
+
run
|
43
|
+
else
|
44
|
+
reply(message.replyto, "\2Error:\2 I have no record of #{params[:channel]}.")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def watch_list(message, params)
|
49
|
+
if(Setting[:devwatch][:channels].empty?)
|
50
|
+
reply(message.replyto, "No channels currently on the development watch list")
|
51
|
+
else
|
52
|
+
chans = []
|
53
|
+
Setting[:devwatch][:channels].each{|id| chans << Channel[id].name}
|
54
|
+
reply(message.replyto, "Channels on development watch list: #{chans.join(', ')}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_url(message, params)
|
59
|
+
if(params[:url])
|
60
|
+
vals = Setting[:devwatch]
|
61
|
+
vals[:url] = params[:url]
|
62
|
+
reply(message.replyto, "OK")
|
63
|
+
Setting.filter(:name => 'devwatch').first.value = vals
|
64
|
+
run
|
65
|
+
else
|
66
|
+
if(Setting[:devwatch].has_key?(:url))
|
67
|
+
reply(message.replyto, "\2Devwatch URL:\2 #{Setting[:devwatch][:url]}")
|
68
|
+
else
|
69
|
+
reply(message.replyto, "\2Error:\2 No URL set for devwatch")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_interval(message, params)
|
75
|
+
if(params[:time])
|
76
|
+
vals = Setting[:devwatch]
|
77
|
+
vals[:interval] = params[:time].to_i
|
78
|
+
Setting.filter(:name => 'devwatch').first.value = vals
|
79
|
+
@timer.reset_period(params[:time].to_i) unless @timer.nil?
|
80
|
+
reply(message.replyto, "Devwatch announcement interval reset to: #{Helpers.format_seconds(params[:time].to_i)}")
|
81
|
+
else
|
82
|
+
reply(message.replyto, "Devwatch announcement interval set to: #{Helpers.format_seconds(Setting[:devwatch][:interval].to_i)}")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def run
|
87
|
+
@lock.synchronize do
|
88
|
+
check_updates
|
89
|
+
if(Setting[:devwatch].has_key?(:url) && Setting[:devwatch][:channels].size > 0)
|
90
|
+
if(@timer.nil?)
|
91
|
+
@pipeline << ModSpox::Messages::Internal::TimerAdd.new(self, Setting[:devwatch][:interval].to_i){check_updates}
|
92
|
+
sleep(0.01) while @timer.nil?
|
93
|
+
end
|
94
|
+
else
|
95
|
+
if(@timer)
|
96
|
+
@pipeline << ModSpox::Messages::Internal::TimerRemove.new(@timer)
|
97
|
+
sleep(0.01) until @timer.nil?
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def timer_response(message)
|
104
|
+
if(message.origin == self && message.action_added?)
|
105
|
+
@timer = message.action
|
106
|
+
elsif(message.action == @timer && message.action_removed?)
|
107
|
+
@timer = nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_updates
|
112
|
+
if(Setting[:devwatch].has_key?(:url) && Setting[:devwatch][:channels].size > 0)
|
113
|
+
src = open(Setting[:devwatch][:url])
|
114
|
+
doc = REXML::Document.new(src.read)
|
115
|
+
if @original.nil?
|
116
|
+
doc.elements.each('rss/channel/item') do |item|
|
117
|
+
@original = item.elements['title'].text
|
118
|
+
break
|
119
|
+
end
|
120
|
+
Logger.log("Initialized development watch RSS feed: #{@original}")
|
121
|
+
else
|
122
|
+
@new = doc
|
123
|
+
print_new
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def print_new
|
129
|
+
new_items = Array.new
|
130
|
+
# run through the list until we hit a duplicate #
|
131
|
+
i = 1
|
132
|
+
new_orig = nil
|
133
|
+
@new.elements.each('rss/channel/item') do |item|
|
134
|
+
if item.elements['title'].text == @original
|
135
|
+
break
|
136
|
+
else
|
137
|
+
new_orig = item.elements['title'].text if new_orig.nil?
|
138
|
+
new_items << "#{item.elements['title'].text}: #{item.elements['link'].text}"
|
139
|
+
end
|
140
|
+
i += 1
|
141
|
+
end
|
142
|
+
@original = new_orig.nil? ? @original : new_orig
|
143
|
+
if new_items.size > 0
|
144
|
+
new_items.reverse!
|
145
|
+
Setting[:devwatch][:channels].each do |id|
|
146
|
+
channel = Channel[id]
|
147
|
+
new_items.each do |item|
|
148
|
+
reply(channel, item)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class EightBall < ModSpox::Plugin
|
2
|
+
|
3
|
+
include Models
|
4
|
+
|
5
|
+
def initialize(pipeline)
|
6
|
+
super
|
7
|
+
Signature.find_or_create(:signature => '8ball .+\?$', :plugin => name, :method => 'eightball', :description => 'Ask the magic eightball a question')
|
8
|
+
@responses = ['Ask Again Later',
|
9
|
+
'Better Not Tell You Now',
|
10
|
+
'Concentrate and Ask Again',
|
11
|
+
'Don\'t Count on It',
|
12
|
+
'It Is Certain',
|
13
|
+
'Most Likely',
|
14
|
+
'My Reply is No',
|
15
|
+
'My Sources Say No',
|
16
|
+
'No',
|
17
|
+
'Outlook Good',
|
18
|
+
'Outlook Not So Good',
|
19
|
+
'Reply Hazy, Try Again',
|
20
|
+
'Signs Point to Yes',
|
21
|
+
'Yes',
|
22
|
+
'Yes, Definitely',
|
23
|
+
'You May Rely On It']
|
24
|
+
end
|
25
|
+
|
26
|
+
def eightball(message, params)
|
27
|
+
@pipeline << Messages::Outgoing::Privmsg.new(message.replyto, 'shakes magic 8 ball...', true)
|
28
|
+
reply message.replyto, "#{message.source.nick}: #{@responses[rand(@responses.size) - 1]}"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
|
4
|
+
class Headers < ModSpox::Plugin
|
5
|
+
|
6
|
+
def initialize(pipeline)
|
7
|
+
super(pipeline)
|
8
|
+
Models::Signature.find_or_create(:signature => 'headers (https?:\/\/\S+)', :plugin => name, :method => 'fetch_headers',
|
9
|
+
:description => 'Fetch HTTP headers').params = [:url]
|
10
|
+
@lock = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch_headers(message, params)
|
14
|
+
@lock.synchronize do
|
15
|
+
secure = false
|
16
|
+
if(params[:url] =~ /^http:/)
|
17
|
+
port = 80
|
18
|
+
else
|
19
|
+
port = 443
|
20
|
+
secure = true
|
21
|
+
end
|
22
|
+
params[:url].gsub!(/^https?:\/\//, '')
|
23
|
+
if(params[:url] =~ /:(\d+)/)
|
24
|
+
port = $1.to_i
|
25
|
+
params[:url].gsub!(/:(\d+)/, '')
|
26
|
+
end
|
27
|
+
if(params[:url] =~ /(.+?[a-zA-Z]{2,4})(\/.+)$/)
|
28
|
+
location = $1
|
29
|
+
page = $2
|
30
|
+
else
|
31
|
+
location = params[:url]
|
32
|
+
page = '/'
|
33
|
+
end
|
34
|
+
begin
|
35
|
+
reply message.replyto, "Connecting to: #{location} on port: #{port} retrieving: #{page}"
|
36
|
+
con = Net::HTTP.new(location, port)
|
37
|
+
con.use_ssl = secure
|
38
|
+
response = con.get(page, nil)
|
39
|
+
reply message.replyto, "Response code: #{response.code}"
|
40
|
+
response.each{|key,val|
|
41
|
+
reply message.replyto, "#{key}: #{val}"
|
42
|
+
}
|
43
|
+
reply message.replyto, "Header listing complete"
|
44
|
+
rescue Object => boom
|
45
|
+
reply message.replyto, "Error retrieving headers: #{boom}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -4,7 +4,7 @@ class Karma < ModSpox::Plugin
|
|
4
4
|
|
5
5
|
def initialize(pipeline)
|
6
6
|
super(pipeline)
|
7
|
-
|
7
|
+
Datatype::Karma.create_table unless Datatype::Karma.table_exists?
|
8
8
|
Models::Signature.find_or_create(:signature => 'karma (\S+)', :plugin => name, :method => 'score', :description => 'Returns karma for given thing').params = [:thing]
|
9
9
|
Models::Signature.find_or_create(:signature => 'karma reset (\S+)', :plugin => name, :method => 'reset',
|
10
10
|
:group_id => Models::Group.filter(:name => 'admin').first.pk, :description => 'Reset a karma score').params = [:thing]
|
@@ -20,7 +20,7 @@ class Karma < ModSpox::Plugin
|
|
20
20
|
thing.downcase!
|
21
21
|
thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..1] == ')'
|
22
22
|
adj = adj == '++' ? +1 : -1
|
23
|
-
karma =
|
23
|
+
karma = Datatype::Karma.find_or_create(:thing => thing, :channel_id => message.target.pk)
|
24
24
|
karma.set(:score => karma.score + adj)
|
25
25
|
end
|
26
26
|
end
|
@@ -29,7 +29,7 @@ class Karma < ModSpox::Plugin
|
|
29
29
|
def score(message, params)
|
30
30
|
params[:thing].downcase!
|
31
31
|
return unless message.is_public?
|
32
|
-
karma =
|
32
|
+
karma = Datatype::Karma.filter(:thing => params[:thing], :channel_id => message.target.pk).first
|
33
33
|
if(karma)
|
34
34
|
@pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 is #{karma.score}")
|
35
35
|
else
|
@@ -40,7 +40,7 @@ class Karma < ModSpox::Plugin
|
|
40
40
|
def reset(message, params)
|
41
41
|
params[:thing].downcase!
|
42
42
|
return unless message.is_public?
|
43
|
-
karma =
|
43
|
+
karma = Datatype::Karma.filter(:thing => params[:thing], :channel_id => message.target.pk).first
|
44
44
|
if(karma)
|
45
45
|
karma.set(:score => 0)
|
46
46
|
@pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 has been reset")
|
@@ -49,19 +49,18 @@ class Karma < ModSpox::Plugin
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
ModSpox::Models::Channel[channel_id]
|
52
|
+
module Datatype
|
53
|
+
class Karma < Sequel::Model
|
54
|
+
set_schema do
|
55
|
+
primary_key :id
|
56
|
+
text :thing, :null => false, :unique => true
|
57
|
+
integer :score, :null => false, :default => 0
|
58
|
+
foreign_key :channel_id, :table => :channels
|
59
|
+
end
|
60
|
+
|
61
|
+
def channel
|
62
|
+
ModSpox::Models::Channel[channel_id]
|
63
|
+
end
|
65
64
|
end
|
66
65
|
end
|
67
66
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# IMPORTANT NOTE: This plugin requires installation of the LOLSpeak gem
|
2
|
+
class LolSpeak < ModSpox::Plugin
|
3
|
+
|
4
|
+
include Models
|
5
|
+
|
6
|
+
def initialize(pipeline)
|
7
|
+
super
|
8
|
+
begin
|
9
|
+
require 'lolspeak'
|
10
|
+
rescue Object => boom
|
11
|
+
Logger.log('Error: This plugins requires the lolspeak gem. Please install gem and reload plugin.')
|
12
|
+
raise BotException.new("Failed to initialize plugin. Missing lolspeak gem.")
|
13
|
+
end
|
14
|
+
Signature.find_or_create(:signature => 'lolspeak (.+)', :plugin => name, :method => 'translate',
|
15
|
+
:description => 'Translate text to lolspeak').params = [:text]
|
16
|
+
end
|
17
|
+
|
18
|
+
def translate(message, params)
|
19
|
+
reply message.replyto, "\2lulz:\2 #{params[:text].to_lolspeak}"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# IMPORTANT NOTE: This plugin will only function if the PHP executable can be located
|
2
|
+
class PhpCli < ModSpox::Plugin
|
3
|
+
|
4
|
+
include Models
|
5
|
+
include Messages::Outgoing
|
6
|
+
|
7
|
+
def initialize(pipeline)
|
8
|
+
super(pipeline)
|
9
|
+
@path = Config[:plugin_directory] + '/phpcli'
|
10
|
+
@botini = @path + '/bot.ini'
|
11
|
+
unless(File.directory?(@path))
|
12
|
+
FileUtils.mkdir_p(@path)
|
13
|
+
end
|
14
|
+
result = Helpers.safe_exec('which php')
|
15
|
+
raise NoInterpreter.new if result.empty?
|
16
|
+
unless File.exists?(@botini)
|
17
|
+
ini = File.new(@botini, 'w')
|
18
|
+
ini.write($ini)
|
19
|
+
ini.close
|
20
|
+
end
|
21
|
+
php = Group.find_or_create(:name => 'PHP')
|
22
|
+
admin = Group.filter(:name => 'admin').first
|
23
|
+
Signature.find_or_create(:signature => 'php (on|off)', :plugin => name, :method => 'set_channel', :group_id => admin.pk,
|
24
|
+
:description => 'Add or remove channel from allowing PHP command').params = [:action]
|
25
|
+
Signature.find_or_create(:signature => 'php (?!on|off)(.+)', :plugin => name, :method => 'execute_php', :group_id => php.pk,
|
26
|
+
:description => 'Execute PHP code').params = [:code]
|
27
|
+
Setting[:phpcli] = '' if Setting[:phpcli].nil?
|
28
|
+
@channels = Setting[:phpcli].split('|')
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_channel(message, params)
|
32
|
+
return unless message.is_public?
|
33
|
+
if(params[:action] == 'on')
|
34
|
+
unless(@channels.include?(message.target.pk))
|
35
|
+
@channels << message.target.pk
|
36
|
+
Setting[:phpcli] = @channels.join('|')
|
37
|
+
end
|
38
|
+
reply message.replyto, 'PHP command now active'
|
39
|
+
else
|
40
|
+
unless(@channels.include?(message.target.pk))
|
41
|
+
reply message.replyto, 'PHP command is not currently active in this channel'
|
42
|
+
else
|
43
|
+
@channels.delete(message.target.pk)
|
44
|
+
Setting[:phpcli] = @channels.join('|')
|
45
|
+
reply message.replyto, 'PHP command is now disabled'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def execute_php(message, params)
|
51
|
+
return unless @channels.include?(message.target.pk)
|
52
|
+
filepath = @path + "/#{rand(99999)}.bot.php"
|
53
|
+
file = File.open(filepath, 'w')
|
54
|
+
file.write("<? $_SERVER = $_ENV = array(); #{params[:code]} ?>")
|
55
|
+
file.close
|
56
|
+
begin
|
57
|
+
output = Helpers.safe_exec("php -c #{@path}/bot.ini -d max_execution_time=10 #{filepath} 2>&1 | head -n 4")
|
58
|
+
if(output =~ /^sh: line [0-9]+:(.*)$/)
|
59
|
+
output = $1
|
60
|
+
end
|
61
|
+
if(output =~ /^(Fatal error|Warning|Parse error): (.+?) in .*? on line [0-9]+[\n|\r]*(.*)$/)
|
62
|
+
warning = $2
|
63
|
+
type = $1
|
64
|
+
output = $3
|
65
|
+
end
|
66
|
+
if(output.length > 300)
|
67
|
+
reply message.replyto, "#{message.source.nick}: Your result has been truncated. Don't print so much."
|
68
|
+
output = output.slice(0, 300)
|
69
|
+
end
|
70
|
+
if(!warning.nil?)
|
71
|
+
reply message.replyto, "PHP #{type}: "+warning
|
72
|
+
end
|
73
|
+
if(warning.nil? || type !~ /(Fatal|Parse)/)
|
74
|
+
reply message.replyto, "Result: "+output
|
75
|
+
end
|
76
|
+
File.delete(filepath)
|
77
|
+
rescue
|
78
|
+
reply message.replyto, "\2Error:\2 Timeout reached. Script execution terminated"
|
79
|
+
File.delete(filepath)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class NoInterpreter < Exceptions::BotException
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
$ini = <<EOF
|
89
|
+
[PHP]
|
90
|
+
engine = On
|
91
|
+
zend.ze1_compatibility_mode = Off
|
92
|
+
short_open_tag = On
|
93
|
+
asp_tags = Off
|
94
|
+
precision = 12
|
95
|
+
y2k_compliance = On
|
96
|
+
output_buffering = Off
|
97
|
+
zlib.output_compression = Off
|
98
|
+
implicit_flush = Off
|
99
|
+
unserialize_callback_func=
|
100
|
+
serialize_precision = 100
|
101
|
+
allow_call_time_pass_reference = On
|
102
|
+
safe_mode = On
|
103
|
+
safe_mode_gid = On
|
104
|
+
safe_mode_include_dir = /tmp/mod_spox/php
|
105
|
+
safe_mode_exec_dir = /tmp/mod_spox/php
|
106
|
+
safe_mode_allowed_env_vars = PHP_
|
107
|
+
safe_mode_protected_env_vars = LD_LIBRARY_PATH
|
108
|
+
open_basedir = /tmp/mod_spox
|
109
|
+
disable_functions = fscanf fputs chown chmod copy delete fflush file flock ftell glob link fseek lstat move_uploaded_file rename realpath set_file_buffer touch fprintf chgrp fgetss readfile dio_close dio_fnctl dio_open dio_read dio_seek dio_stat dio_tcsetattr dio_truncate dio_write chdir chroot dir closedir getcwd opendir readdir rewinddir scandir posix_kill posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid posix_getpwnam posix_getpwuid posix_getwuid posix_getrlimit posix_getsid posix_getuid posix_isatty posix_mkfifo posix_mknod posix_setegid posix_setgid posix_setpgid posix_setsid posix_setuid posix_strerror posix_times posix_ttyname posix_uname expect_expectl expect_popen sleep time_sleep_until usleep pfsockopen fsockopen openlog debugger_on proc_open pclose popen fsockopen fread set_time_limit ini_set ini_alter ini_restore exec system passthru proc_close proc_nice proc_open proc_terminiate shell_exec sleep usleep pcntl_fork pcntl_exec pcntl_alarm pcntl_getpriority pcntl_setpriority pcntl_waitpid pcntl_wexitstatus pcntl_wifexited pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig readline_add_history readline_callback_handler_install readline_callback_handler_remove readline_callback_read_char readline_clear_history readline_completion_function readline_info readline_list_history readline_on_new_line readline_read_history readline_redisplay readline_write_history readline dl set_include_path set_magic_quotes_runtime file_put_contents fwrite fputs copy fputcsv tmpfile symlink tempnam mysql_connect unlink putenv ftp_connect socket_create socket_create socket_close socket_accept socket_bind socket_close socket_connect socket_create_listen socket_create_pair socket_get_option socket_listen socket_read socket_recv socket_select socket_send socket_sendto shmop_close shmop_open shmop_delete shmop_read shmop_size shmop_write msg_get_queue msg_receive msg_remove_queue msg_send msg_set_queue msg_stat_queue msg_acquire sem_aquire sem_release sem_get sem_remove mail time_nanosleep usleep
|
110
|
+
disable_classes = dir
|
111
|
+
expose_php = On
|
112
|
+
max_execution_time = 10
|
113
|
+
max_input_time = 20
|
114
|
+
memory_limit = 4M
|
115
|
+
error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT
|
116
|
+
display_errors = On
|
117
|
+
display_startup_errors = Off
|
118
|
+
log_errors = Off
|
119
|
+
log_errors_max_len = 1024
|
120
|
+
ignore_repeated_errors = Off
|
121
|
+
ignore_repeated_source = Off
|
122
|
+
report_memleaks = On
|
123
|
+
track_errors = Off
|
124
|
+
variables_order = "EGPCS"
|
125
|
+
register_globals = Off
|
126
|
+
register_long_arrays = On
|
127
|
+
register_argc_argv = On
|
128
|
+
post_max_size = 8M
|
129
|
+
magic_quotes_gpc = On
|
130
|
+
magic_quotes_runtime = Off
|
131
|
+
magic_quotes_sybase = Off
|
132
|
+
auto_prepend_file =
|
133
|
+
auto_append_file =
|
134
|
+
default_mimetype = "text/html"
|
135
|
+
include_path = ".:/usr/share/php"
|
136
|
+
doc_root = /tmp/mod_spox/php
|
137
|
+
user_dir = /tmp/mod_spox/php
|
138
|
+
enable_dl = On
|
139
|
+
file_uploads = Off
|
140
|
+
allow_url_fopen = Off
|
141
|
+
default_socket_timeout = 10
|
142
|
+
define_syslog_variables = Off
|
143
|
+
sendmail_path = /dev/null
|
144
|
+
[Sockets]
|
145
|
+
sockets.use_system_read = On
|
146
|
+
EOF
|