zmb 0.2.1 → 0.3.0
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/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
|