zmb 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +17 -2
- data/VERSION +1 -1
- data/lib/zmb.rb +1 -0
- data/lib/zmb/timer.rb +8 -4
- data/lib/zmb/utils.rb +144 -0
- data/plugins/alias.rb +11 -3
- data/plugins/announce.rb +10 -2
- data/plugins/commands.rb +76 -34
- data/plugins/countdown.rb +46 -0
- data/plugins/dns.rb +1 -5
- data/plugins/gcalc.rb +1 -4
- data/plugins/idle.rb +5 -16
- data/plugins/irc.rb +57 -38
- data/plugins/quote.rb +1 -5
- data/plugins/random.rb +2 -20
- data/plugins/relay.rb +8 -4
- data/plugins/security.rb +5 -25
- data/plugins/sed.rb +18 -0
- data/plugins/url.rb +7 -42
- data/plugins/usermodes.rb +7 -3
- data/plugins/users.rb +309 -68
- data/plugins/vouch.rb +94 -0
- data/plugins/weather.rb +48 -0
- data/zmb.gemspec +7 -2
- metadata +7 -2
data/README.markdown
CHANGED
@@ -26,12 +26,27 @@ You can run zmb in a shell mode to test plugins without even connecting to any i
|
|
26
26
|
|
27
27
|
### Included plugins
|
28
28
|
|
29
|
-
- IRC
|
30
|
-
- Quote
|
29
|
+
- IRC - Connect to a IRC server
|
30
|
+
- Quote - Quotes
|
31
|
+
- Poll - Voting system
|
31
32
|
- Relay - Relay between servers and/or channels
|
32
33
|
- Users - User management
|
34
|
+
- Log - Log everything said in a channel
|
35
|
+
- GCalc - Execute a expression using google calculator
|
36
|
+
- Announce - Send message to a channel automatically in a certain amount of time
|
37
|
+
- DNS - Perform DNS, RDNS and whois lookups
|
38
|
+
- NickServ - Log into NickServ
|
39
|
+
- Security - Hashes, rot13, and morse code
|
40
|
+
- Random - Pick a random value from a list, yes or no, coinflip
|
41
|
+
- URL - Dpaste, pastie, bitly, tinyurl, isgd
|
33
42
|
- Bank - Points system
|
34
43
|
|
44
|
+
#### Other features
|
45
|
+
|
46
|
+
- Piping commands together
|
47
|
+
|
48
|
+
.help | pastie
|
49
|
+
|
35
50
|
### Support
|
36
51
|
|
37
52
|
You can find support at #zmb @ efnet.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/zmb.rb
CHANGED
data/lib/zmb/timer.rb
CHANGED
@@ -14,10 +14,14 @@ class Timer
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def fire(sender)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
begin
|
18
|
+
if @data then
|
19
|
+
@delegate.send @symbol, @data
|
20
|
+
else
|
21
|
+
@delegate.send @symbol
|
22
|
+
end
|
23
|
+
rescue Exception
|
24
|
+
|
21
25
|
end
|
22
26
|
|
23
27
|
if not @repeat
|
data/lib/zmb/utils.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
class String
|
2
|
+
def self.random(len=8)
|
3
|
+
characters = ('a'..'z').to_a + ('1'..'9').to_a
|
4
|
+
(1..len).map{ characters[rand(characters.size)] }.join
|
5
|
+
end
|
6
|
+
|
7
|
+
def split_seperators
|
8
|
+
if include?("\n") then
|
9
|
+
split("\n").map{ |arg| arg.strip }
|
10
|
+
elsif include?(',') then
|
11
|
+
split(',').map{ |arg| arg.strip }
|
12
|
+
elsif include?(' ') then
|
13
|
+
split(' ')
|
14
|
+
else
|
15
|
+
[self]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def truncate_words(num)
|
20
|
+
return [self] if size <= num
|
21
|
+
|
22
|
+
lines = Array.new
|
23
|
+
line = Array.new
|
24
|
+
len = 0
|
25
|
+
|
26
|
+
split(' ').each do |word|
|
27
|
+
len += 1 unless len == 0
|
28
|
+
len += word.size
|
29
|
+
|
30
|
+
if not len <= num then
|
31
|
+
lines << line.join(' ')
|
32
|
+
line = Array.new
|
33
|
+
len = word.size
|
34
|
+
end
|
35
|
+
|
36
|
+
line << word
|
37
|
+
end
|
38
|
+
|
39
|
+
lines << line.join(' ') if lines.size != 0
|
40
|
+
|
41
|
+
lines
|
42
|
+
end
|
43
|
+
|
44
|
+
def plural(amount=2)
|
45
|
+
if amount == 1 then
|
46
|
+
self
|
47
|
+
else
|
48
|
+
self + 's'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def http(type, q=nil)
|
53
|
+
u = URI.parse(self)
|
54
|
+
|
55
|
+
http = Net::HTTP.new(u.host, u.port)
|
56
|
+
q = q.to_query_string if q.class == Hash
|
57
|
+
q = u.query unless q
|
58
|
+
|
59
|
+
http.start do |h|
|
60
|
+
case type
|
61
|
+
when 'get' then h.get(u.path + '?' + q)
|
62
|
+
when 'post' then h.post(u.path, q)
|
63
|
+
when 'head' then h.head(u.path + '?' + q)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def get(q={})
|
69
|
+
http('get', q)
|
70
|
+
end
|
71
|
+
|
72
|
+
def post(q={})
|
73
|
+
http('post', q)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class Array
|
78
|
+
def split_seperators
|
79
|
+
self
|
80
|
+
end
|
81
|
+
|
82
|
+
def word_count(seperator='')
|
83
|
+
join(seperator).size
|
84
|
+
end
|
85
|
+
|
86
|
+
def list_join
|
87
|
+
(size > 2 ? [slice(0..-2).join(', '), last] : self).join(' and ')
|
88
|
+
end
|
89
|
+
|
90
|
+
def list_count
|
91
|
+
items = {}
|
92
|
+
|
93
|
+
each do |i|
|
94
|
+
items[i] = 0 unless items.has_key?(i)
|
95
|
+
items[i] += 1
|
96
|
+
end
|
97
|
+
|
98
|
+
items.map{ |i, c| c == 1 ? i : "#{i} (#{c})" }.join(', ')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Hash
|
103
|
+
def to_query_string
|
104
|
+
map { |k, v|
|
105
|
+
if v.instance_of?(Hash)
|
106
|
+
v.map { |sk, sv|
|
107
|
+
"#{k}[#{sk}]=#{sv}"
|
108
|
+
}.join('&')
|
109
|
+
else
|
110
|
+
"#{k}=#{v}"
|
111
|
+
end
|
112
|
+
}.join('&')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class Time
|
117
|
+
def since
|
118
|
+
Time.now - self
|
119
|
+
end
|
120
|
+
|
121
|
+
def since_words
|
122
|
+
s = since
|
123
|
+
m = Array.new
|
124
|
+
s = s * -1 if future = (s < 0) # Is the time in the future?
|
125
|
+
|
126
|
+
[
|
127
|
+
['year', 60 * 60 * 24 * 365],
|
128
|
+
['month', 60 * 60 * 24 * 30],
|
129
|
+
['week', 60 * 60 * 24 * 7],
|
130
|
+
['day', 60 * 60 * 24],
|
131
|
+
['hour', 60 * 60],
|
132
|
+
['minute', 60],
|
133
|
+
['second', 1],
|
134
|
+
].each do |word, t|
|
135
|
+
amount = (s/t).floor
|
136
|
+
s -= amount * t
|
137
|
+
m << "#{amount} #{word.plural(amount)}" unless amount == 0
|
138
|
+
end
|
139
|
+
|
140
|
+
m << 'now' if m.size == 0
|
141
|
+
|
142
|
+
m.list_join + (future ? ' left' : '')
|
143
|
+
end
|
144
|
+
end
|
data/plugins/alias.rb
CHANGED
@@ -12,9 +12,17 @@ class Alias
|
|
12
12
|
|
13
13
|
def commands
|
14
14
|
{
|
15
|
-
'alias' => [:add, 2, {
|
16
|
-
|
17
|
-
|
15
|
+
'alias' => [:add, 2, {
|
16
|
+
:permission => 'admin',
|
17
|
+
:help => 'Create a alias',
|
18
|
+
:example => 'hello? .echo Hello!' }],
|
19
|
+
'unalias' => [:del, 1, {
|
20
|
+
:permission => 'admin',
|
21
|
+
:help => 'Remove a alias',
|
22
|
+
:usage => 'hello?' }],
|
23
|
+
'aliases' => [:aliases, 0, {
|
24
|
+
:permission => 'admin',
|
25
|
+
:help => 'List all aliases' }],
|
18
26
|
}
|
19
27
|
end
|
20
28
|
|
data/plugins/announce.rb
CHANGED
@@ -55,13 +55,21 @@ class Announce
|
|
55
55
|
'announcements' => [:announcements, 0, {
|
56
56
|
:permission => 'admin',
|
57
57
|
:help => 'List all the id\'s for' }],
|
58
|
-
'announcement' => [:announcement, 1, {
|
58
|
+
'announcement' => [:announcement, 1, {
|
59
|
+
:permission => 'admin',
|
60
|
+
:help => 'Display infomation about a announcement',
|
61
|
+
:usage => 'id',
|
62
|
+
:example => '1' }],
|
59
63
|
'announce' => [:announce, 4, {
|
60
64
|
:permission => 'admin',
|
61
65
|
:help => 'Add a announcement',
|
62
66
|
:usage => 'instance location interval message',
|
63
67
|
:example => 'efnet #zmb 600 Check github for the latest updates!' }],
|
64
|
-
'announce-del' => [:announce_del, 1, {
|
68
|
+
'announce-del' => [:announce_del, 1, {
|
69
|
+
:permission => 'admin',
|
70
|
+
:help => 'Delete a announcement',
|
71
|
+
:usage => 'id',
|
72
|
+
:example => '1' }],
|
65
73
|
}
|
66
74
|
end
|
67
75
|
|
data/plugins/commands.rb
CHANGED
@@ -21,22 +21,47 @@ class Commands
|
|
21
21
|
}
|
22
22
|
end
|
23
23
|
|
24
|
+
def escape
|
25
|
+
{
|
26
|
+
'"' => "\000d\000",
|
27
|
+
"'" => "\000s\000",
|
28
|
+
'|' => "\000p\000",
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
24
32
|
def event(sender, e)
|
25
33
|
return if not e.message?
|
26
34
|
|
27
35
|
if e.message[0, @cc.length] == @cc then
|
28
36
|
line = e.message[@cc.length..-1].clone
|
37
|
+
elsif e.delegate.respond_to?('nick') and e.message[0, (e.delegate.nick.length+2)] == (e.delegate.nick + ': ') then
|
38
|
+
line = e.message[(e.delegate.nick.length+2)..-1].clone
|
29
39
|
elsif e.private? then
|
30
40
|
line = e.message.clone
|
41
|
+
else
|
42
|
+
return
|
31
43
|
end
|
32
44
|
|
45
|
+
return if e.name[0..0] == '*'
|
46
|
+
|
47
|
+
line.sub!('{time}', Time.now.strftime('%H:%M:%S'))
|
48
|
+
line.sub!('{day}', Time.now.strftime('%d'))
|
49
|
+
line.sub!('{weekday}', Time.now.strftime('%A'))
|
50
|
+
line.sub!('{timezone}', Time.now.strftime('%Z'))
|
51
|
+
line.sub!('{month}', Time.now.strftime('%B'))
|
52
|
+
line.sub!('{year}', Time.now.strftime('%Y'))
|
53
|
+
line.sub!('{username}', e.user.username) if e.respond_to?('user') and e.user.respond_to?('username')
|
54
|
+
line.sub!('{points}', "#{e.bank.balance}") if e.respond_to?('bank') and e.bank.respond_to?('balance')
|
55
|
+
line.sub!('{channel}', e.channel) if e.respond_to?('channel')
|
56
|
+
line.sub!('{name}', e.name) if e.respond_to?('name')
|
57
|
+
line.sub!('{userhost}', e.userhost) if e.respond_to?('userhost')
|
58
|
+
line.sub!('{rand}', String.random)
|
59
|
+
|
33
60
|
# Encode escaped quotation marks and pipes
|
34
|
-
line.gsub!(
|
35
|
-
line.gsub!("\\'", "\000s\000")
|
36
|
-
line.gsub!('\|', "\000p\000")
|
61
|
+
escape.each{ |k,v| line.gsub!("\\" + k, v) }
|
37
62
|
|
38
63
|
# Check there are a even amount of "" and ''
|
39
|
-
if ((line.count("'") % 2) == 1) and ((line.count('"
|
64
|
+
if ((line.count("'") % 2) == 1) and ((line.count('"') % 2) == 1) then
|
40
65
|
return e.reply('Incorrect amount of quotation marks\'s')
|
41
66
|
end
|
42
67
|
|
@@ -51,11 +76,7 @@ class Commands
|
|
51
76
|
args = command.split(/"([^"]*)"|'([^']*)'|\s/).reject{ |x| x.empty? }
|
52
77
|
|
53
78
|
# Decode escape quotation marks and pipes inside the args
|
54
|
-
args.each
|
55
|
-
arg.gsub!("\000d\000", '"')
|
56
|
-
arg.gsub!("\000s\000", "'")
|
57
|
-
arg.gsub!("\000p\000", '|')
|
58
|
-
end
|
79
|
+
args.each{ |arg| escape.each{ |k,v| arg.gsub!(v, k) } }
|
59
80
|
|
60
81
|
cmd = args.delete_at(0)
|
61
82
|
args << input if input
|
@@ -65,8 +86,8 @@ class Commands
|
|
65
86
|
e.reply(input) if input
|
66
87
|
end
|
67
88
|
|
68
|
-
def execute(cmd, e, args)
|
69
|
-
return if not @cmds.has_key?(cmd)
|
89
|
+
def execute(cmd, e, args=[])
|
90
|
+
return "#{cmd}: command not found" if not @cmds.has_key?(cmd)
|
70
91
|
|
71
92
|
c = @cmds[cmd]
|
72
93
|
|
@@ -90,7 +111,13 @@ class Commands
|
|
90
111
|
end
|
91
112
|
|
92
113
|
begin
|
93
|
-
c[
|
114
|
+
if c[1].class == Symbol then
|
115
|
+
c[0].send(c[1], e, *args)
|
116
|
+
elsif c[1].class == Proc then
|
117
|
+
c[1].call(e, *args)
|
118
|
+
else
|
119
|
+
"Bad command definition"
|
120
|
+
end
|
94
121
|
rescue ArgumentError
|
95
122
|
'incorrect arguments'
|
96
123
|
rescue Exception
|
@@ -117,18 +144,6 @@ class Commands
|
|
117
144
|
@cmds = @cmds.reject{ |k,v| v[0] == instance }
|
118
145
|
end
|
119
146
|
|
120
|
-
def split_seperators(data)
|
121
|
-
if data.include?("\n") then
|
122
|
-
data.split("\n").map{ |arg| arg.strip }
|
123
|
-
elsif data.include?(',') then
|
124
|
-
data.split(',').map{ |arg| arg.strip }
|
125
|
-
elsif data.include?(' ') then
|
126
|
-
data.split(' ')
|
127
|
-
else
|
128
|
-
data
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
147
|
def commands
|
133
148
|
{
|
134
149
|
'help' => :help,
|
@@ -136,12 +151,27 @@ class Commands
|
|
136
151
|
'which' => [:which, 1, { :help => 'Find which plugin handles a command' }],
|
137
152
|
'cc' => [:control_command, 1, { :permission => 'admin' }],
|
138
153
|
'eval' => [:evaluate, 1, { :permission => 'admin' }],
|
139
|
-
'
|
154
|
+
'ieval' => [:instance_evaluate, 2, { :permission => 'admin' }],
|
155
|
+
'count' => lambda { |e, data| "#{data.split_seperators.size}" },
|
140
156
|
'grep' => [:grep, 2],
|
141
157
|
'not' => [:not_command, 2],
|
142
158
|
'tail' => :tail,
|
143
|
-
'echo' => :echo,
|
144
|
-
'reverse' =>
|
159
|
+
'echo' => [:echo, 1, { :example => 'Hello, {username}' }],
|
160
|
+
'reverse' => lambda { |e, data| data.reverse },
|
161
|
+
'first' => lambda { |e, data| data.split_seperators.first },
|
162
|
+
'last' => lambda { |e, data| data.split_seperators.last },
|
163
|
+
'sub' => [:sub, 3, {
|
164
|
+
:help => 'Replace all occurances of a pattern',
|
165
|
+
:usage => 'pattern replacement data',
|
166
|
+
:example => 'l * Hello World!' }],
|
167
|
+
'tr' => [:tr, 3, {
|
168
|
+
:help => 'Returns a copy of str with the characters in from_str replaced by the corresponding characters in to_str',
|
169
|
+
:usage => 'from_str to_str data',
|
170
|
+
:example => 'aeiou * hello' }],
|
171
|
+
'downcase' => lambda { |e, data| data.downcase },
|
172
|
+
'upcase' => lambda { |e, data| data.upcase },
|
173
|
+
'swapcase' => lambda { |e, data| data.swapcase },
|
174
|
+
'capitalize' => lambda { |e, data| data.capitalize },
|
145
175
|
}
|
146
176
|
end
|
147
177
|
|
@@ -209,28 +239,40 @@ class Commands
|
|
209
239
|
end
|
210
240
|
end
|
211
241
|
|
212
|
-
def
|
213
|
-
|
242
|
+
def instance_evaluate(e, inst, string)
|
243
|
+
begin
|
244
|
+
if @delegate.instances.has_key?(inst) then
|
245
|
+
"#{@delegate.instances[inst].instance_eval string}"
|
246
|
+
else
|
247
|
+
"#{inst}: No such instance"
|
248
|
+
end
|
249
|
+
rescue Exception
|
250
|
+
"#{$!.message}\n#{$!.inspect}"
|
251
|
+
end
|
214
252
|
end
|
215
253
|
|
216
254
|
def grep(e, search, data)
|
217
|
-
|
255
|
+
data.split_seperators.reject{ |d| not d.include?(search) }.join(', ')
|
218
256
|
end
|
219
257
|
|
220
258
|
def not_command(e, search, data)
|
221
|
-
|
259
|
+
data.split_seperators.reject{ |d| d.include?(search) }.join(', ')
|
222
260
|
end
|
223
261
|
|
224
262
|
def tail(e, data)
|
225
|
-
|
263
|
+
data.split_seperators.reverse[0..2].join(', ')
|
226
264
|
end
|
227
265
|
|
228
266
|
def echo(e, data)
|
229
267
|
"#{data}"
|
230
268
|
end
|
231
269
|
|
232
|
-
def
|
233
|
-
data.
|
270
|
+
def sub(e, pattern, replacement, data)
|
271
|
+
data.gsub(pattern, replacement)
|
272
|
+
end
|
273
|
+
|
274
|
+
def tr(e, from_str, to_str, data)
|
275
|
+
data.tr(from_str, to_str)
|
234
276
|
end
|
235
277
|
end
|
236
278
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
class Countdown
|
4
|
+
attr_accessor :settings
|
5
|
+
|
6
|
+
def initialize(sender, settings)
|
7
|
+
@settings = { 'countdown' => {} }
|
8
|
+
settings['countdown'].each{ |k,v| @settings['countdown'][k] = Time.parse(v) } if settings.has_key?('countdown')
|
9
|
+
end
|
10
|
+
|
11
|
+
def commands
|
12
|
+
{
|
13
|
+
'countdown' => [:countdown, 1, { :usage => 'key' }],
|
14
|
+
'countdowns' => [:countdowns, 0],
|
15
|
+
'add-countdown' => [:add, 2, { :permission => 'countdown', :usage => 'key date/time', :example => 'xmas 25-12-2010' }],
|
16
|
+
'rm-countdown' => [:remove, 1, { :permission => 'countdown', :usage => 'key' }]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def countdown(e, key)
|
21
|
+
if @settings['countdown'].has_key?(key) then
|
22
|
+
@settings['countdown'][key].since_words
|
23
|
+
else
|
24
|
+
"No such countdown"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def countdowns(e)
|
29
|
+
@settings['countdown'].keys.join(', ')
|
30
|
+
end
|
31
|
+
|
32
|
+
def add(e, key, time)
|
33
|
+
@settings['countdown'][key] = Time.parse(time)
|
34
|
+
"Countdown #{key} added"
|
35
|
+
end
|
36
|
+
|
37
|
+
def remove(e, key)
|
38
|
+
@settings['countdown'].delete(key)
|
39
|
+
"Countdown #{key} removed"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Plugin.define do
|
44
|
+
name 'countdown'
|
45
|
+
object Countdown
|
46
|
+
end
|