zmb 0.1.1

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/plugins/irc.rb ADDED
@@ -0,0 +1,230 @@
1
+ require 'socket'
2
+
3
+ require 'zmb/timer'
4
+
5
+ class Event
6
+ attr_accessor :delegate, :command, :args, :name, :userhost, :message
7
+
8
+ def initialize(sender, line)
9
+ puts line
10
+
11
+ if line[0,1] == ':' then
12
+ line = line[1..-1] # Remove the :
13
+ hostname, command, args = line.split(' ', 3)
14
+ args = "#{hostname} #{args}"
15
+ else
16
+ command, args = line.split(' ', 3)
17
+ end
18
+
19
+ @delegate = sender
20
+ @command = command.downcase
21
+ @args = args
22
+
23
+ case @command
24
+ when 'privmsg'
25
+ @userhost, @channel, @message = args.split(' ', 3)
26
+ @name, @userhost = @userhost.split('!', 2)
27
+ @message = @message[1..-1]
28
+ end
29
+ end
30
+
31
+ def private?
32
+ @channel == @delegate.nick
33
+ end
34
+
35
+ def sender
36
+ private? ? @name : @channel
37
+ end
38
+
39
+ def message?
40
+ @message != nil
41
+ end
42
+
43
+ def reply(m)
44
+ if message? then
45
+ m = m.split("\n") if not m.respond_to?('each')
46
+ m.each{ |mess| @delegate.message(sender, mess) }
47
+ else
48
+ @delegate.write m
49
+ end
50
+ end
51
+ end
52
+
53
+ class IrcConnection
54
+ attr_accessor :host, :port, :channels, :nick, :name, :realname, :password, :throttle
55
+
56
+ def initialize(sender, settings={})
57
+ @delegate = sender
58
+
59
+ @host = settings['host'] if settings.has_key?('host')
60
+ begin
61
+ @port = Integer(settings['port']) if settings.has_key?('port')
62
+ rescue Exception
63
+ @port = 6667
64
+ end
65
+
66
+ @channels = Array.new
67
+ @channels = settings['channels'] if settings.has_key?('channels')
68
+
69
+ @nick = settings['nick'] if settings.has_key?('nick')
70
+ @name = settings['name'] if settings.has_key?('name')
71
+ @realname = settings['realname'] if settings.has_key?('realname')
72
+ @password = settings['password'] if settings.has_key?('password')
73
+
74
+ @throttle = 10
75
+ @throttle = settings['throttle'] if settings.has_key?('throttle')
76
+
77
+ sender.timer_add(Timer.new(self, :connect, 0.1, false)) if sender.running?
78
+ end
79
+
80
+ def socket=(value)
81
+ @socket = value
82
+ end
83
+
84
+ def to_json(*a)
85
+ {
86
+ 'host' => @host,
87
+ 'port' => @port,
88
+
89
+ 'channels' => @channels,
90
+
91
+ 'nick' => @nick,
92
+ 'name' => @name,
93
+ 'realname' => @realname,
94
+ 'password' => @password,
95
+
96
+ 'throttle' => @throttle,
97
+ 'plugin' => 'irc',
98
+ }.to_json(*a)
99
+ end
100
+
101
+ def self.wizard
102
+ {
103
+ 'host' => { 'help' => 'Hostname', 'default' => 'localhost' },
104
+ 'port' => { 'help' => 'Port', 'default' => 6667 },
105
+ 'nick' => { 'help' => 'Nickname', 'default' => 'zmb' },
106
+ 'name' => { 'help' => 'Name', 'default' => 'zmb' },
107
+ 'realname' => { 'help' => 'Realname', 'default' => 'zmb' },
108
+ 'password' => { 'help' => 'If the ircd requires a password, enter this here.', 'default' => nil },
109
+ }
110
+ end
111
+
112
+ def commands
113
+ require 'zmb/commands'
114
+ {
115
+ 'join' => PermCommand.new('admin', self, :join_command),
116
+ 'part' => PermCommand.new('admin', self, :part_command),
117
+ 'raw' => PermCommand.new('admin', self, :raw_command),
118
+ 'tell' => PermCommand.new('admin', self, :tell_command, 2),
119
+ }
120
+ end
121
+
122
+ def unloaded
123
+ write "Quit :ZMB"
124
+ @socket.close if @socket
125
+ end
126
+
127
+ def nick=(value)
128
+ @nick = value
129
+ write "NICK #{@nick}"
130
+ end
131
+
132
+ def connected?
133
+ @socket != nil
134
+ end
135
+
136
+ def connect
137
+ if @host and @port and not connected? then
138
+ Thread.new do
139
+ @socket = TCPSocket.new(@host, @port)
140
+ @delegate.socket_add(self, @socket)
141
+ perform
142
+ end
143
+ end
144
+ end
145
+
146
+ def disconnected(sender, socket)
147
+ @socket = nil
148
+ sender.timer_add(Timer.new(self, :connect, @throttle))
149
+ end
150
+
151
+ def perform
152
+ write "PASS #{@password}" if @password
153
+ write "NICK #{@nick}" if @nick
154
+ write "USER #{@name} 0 0 :#{@realname}" if @name and @realname
155
+ end
156
+
157
+ def write(line)
158
+ @socket.write line + "\r\n" if @socket
159
+ end
160
+
161
+ def message(recipient, msg)
162
+ write "PRIVMSG #{recipient} :#{msg}"
163
+ end
164
+
165
+ def join(channel)
166
+ @channels << channel if not @channels.include?(channel)
167
+ write "JOIN #{channel}"
168
+ end
169
+
170
+ def part(channel)
171
+ @channels.delete(channel) if @channels.include?(channel)
172
+ write "PART #{channel}"
173
+ end
174
+
175
+ def received(sender, socket, data)
176
+ @buffer = '' if @buffer == nil
177
+ @buffer += data
178
+ line, @buffer = @buffer.split("\r\n", 2)
179
+ @buffer = '' if @buffer == nil
180
+
181
+ while line != nil do
182
+ e = Event.new(self, line)
183
+
184
+ # Catch some events
185
+ case e.command
186
+ when 'ping' then write "PONG #{e.args[1..-1]}"
187
+ when '001' then @channels.each{ |channel| write "JOIN #{channel}" }
188
+ when 'nick' then tmp, @nick = e.args.split(' :', 2)
189
+ when '433' then
190
+ @nick="#{@nick}_"
191
+ write "NICK #{@nick}"
192
+ end
193
+
194
+ @delegate.event(self, e)
195
+ line, @buffer = @buffer.split("\r\n", 2)
196
+ end
197
+ end
198
+
199
+ def join_command(e, channel)
200
+ join channel
201
+ "#{channel} joined"
202
+ end
203
+
204
+ def part_command(e, channel)
205
+ part channel
206
+ "left #{channel}"
207
+ end
208
+
209
+ def raw_command(e, line)
210
+ write line
211
+ nil
212
+ end
213
+
214
+ def tell_command(e, to, message)
215
+ msg = msg.split("\n") if not msg.respond_to?('each')
216
+ msg.each{ |m| message(to, m) }
217
+ nil
218
+ end
219
+
220
+ def running(sender)
221
+ connect
222
+ end
223
+ end
224
+
225
+ Plugin.define do
226
+ name "irc"
227
+ description "A plugin which allows you to connect to irc servers."
228
+ object IrcConnection
229
+ multi_instances true
230
+ end
data/plugins/quote.rb ADDED
@@ -0,0 +1,100 @@
1
+ class Quote
2
+ attr_accessor :quotes, :autoindex
3
+
4
+ def initialize(sender, settings={})
5
+ @quotes = Hash.new
6
+ @quotes = settings['quotes'] if settings.has_key?('quotes')
7
+ @autoindex = 1
8
+ @autoindex = settings['autoindex'] if settings.has_key?('autoindex')
9
+ end
10
+
11
+ def to_json(*a)
12
+ {
13
+ 'plugin' => 'quote',
14
+ 'quotes' => @quotes,
15
+ 'autoindex' => @autoindex,
16
+ }.to_json(*a)
17
+ end
18
+
19
+ def add(quote, username=nil)
20
+ @quotes["#{@autoindex}"] = {
21
+ 'quote' => quote,
22
+ 'time' => Time.now,
23
+ 'username' => username,
24
+ }
25
+
26
+ @autoindex += 1
27
+ @autoindex - 1
28
+ end
29
+
30
+ def count
31
+ @quotes.keys.count
32
+ end
33
+
34
+ def commands
35
+ require 'zmb/commands'
36
+ {
37
+ 'quote' => Command.new(self, :quote_command, 1, 'Show a random quote or the quote with matching id'),
38
+ 'quote-add' => Command.new(self, :add_command, 1, 'Add a quote'),
39
+ 'quote-del' => PermCommand.new('quote', self, :del_command, 1, 'Delete a quote by id'),
40
+ 'quote-count' => Command.new(self, :count_command, 0, 'Show amount of quotes'),
41
+ 'quote-last' => Command.new(self, :last_command, 0, 'Show the last quote'),
42
+ 'quote-search' => Command.new(self, :search_command, 1, 'Search to find a quote'),
43
+ }
44
+ end
45
+
46
+ def quote_command(e, id=nil)
47
+ return "quote \##{id} not found" if id and not @quotes.has_key?(id)
48
+ return "\"#{@quotes[id]['quote']}\" by #{@quotes[id]['username']} at #{@quotes[id]['time']}" if id
49
+ return "no quotes" if count < 1
50
+
51
+ id = "#{rand(autoindex - 1) + 1}"
52
+ while not @quotes.has_key?(id)
53
+ id = "#{rand(autoindex - 1) + 1}"
54
+ end
55
+
56
+ "\"#{@quotes[id]['quote']}\" by #{@quotes[id]['username']} at #{@quotes[id]['time']}"
57
+ end
58
+
59
+ def add_command(e, quote)
60
+ if e.user and e.user.respond_to?('authenticated?') and e.user.authenticated? then
61
+ "quote added \##{add(quote, e.user.username)}"
62
+ else
63
+ 'permission denied'
64
+ end
65
+ end
66
+
67
+ def del_command(e, id)
68
+ if @quotes.has_key?(id) then
69
+ @quotes.delete id
70
+ "quote #{id} deleted"
71
+ else
72
+ "no quote found with id=#{id}"
73
+ end
74
+ end
75
+
76
+ def count_command(e)
77
+ "#{count} quotes"
78
+ end
79
+
80
+ def last_command(e)
81
+ return "no quotes" if count < 1
82
+ quote_command(e, @quotes.keys.sort.reverse[0])
83
+ end
84
+
85
+ def search_command(e, search)
86
+ result = @quotes.map{ |id, quote| "#{id}: #{quote['quote']}" if quote['quote'].include?(search) }.reject{ |q| not q }
87
+
88
+ if result.count then
89
+ result.join("\n")
90
+ else
91
+ "no quotes found"
92
+ end
93
+ end
94
+ end
95
+
96
+ Plugin.define do
97
+ name "quote"
98
+ description "quote database"
99
+ object Quote
100
+ end
data/plugins/relay.rb ADDED
@@ -0,0 +1,70 @@
1
+ class Relay
2
+ attr_accessor :relays
3
+
4
+ def initialize(sender, settings={})
5
+ @relays = settings['relays'] if settings.has_key?('relays')
6
+ @relays = Hash.new if not @relays
7
+
8
+ @delegate = sender
9
+ end
10
+
11
+ def to_json(*a)
12
+ { 'relays' => @relays, 'plugin' => 'relay' }.to_json(*a)
13
+ end
14
+
15
+ def event(sender, e)
16
+ if e.message? and @delegate.instances.has_value?(sender) then
17
+ relay = "#{@delegate.instances.invert[sender]}:#{e.sender}"
18
+
19
+ if @relays.has_key?(relay) then
20
+ instance, recipient = @relays[relay].split(':', 2)
21
+ @delegate.instances[instance].message(recipient, "<#{e.name}> #{e.message}") if @delegate.instances.has_key?(instance)
22
+ end
23
+ end
24
+ end
25
+
26
+ def commands
27
+ require 'zmb/commands'
28
+ {
29
+ 'relays' => PermCommand.new('admin', self, :relays_command, 0, 'Show all relays'),
30
+ 'relay-add' => PermCommand.new('admin', self, :add_command, 2, 'Add a relay'),
31
+ 'relay-del' => PermCommand.new('admin', self, :del_command, 1, 'Delete a relay'),
32
+ }
33
+ end
34
+
35
+ def relays_command(e)
36
+ if @relays.count < 1 then
37
+ "no relays"
38
+ else
39
+ @relays.map{ |relay, location| "#{relay} > #{location}"}.join("\n")
40
+ end
41
+ end
42
+
43
+ def add_command(e, relay, location)
44
+ if relay.include? ':' and location.include? ':' then
45
+ if @relays.has_key?(relay) then
46
+ "relays must be unique"
47
+ else
48
+ @relays[relay] = location
49
+ "relay setup #{relay} => #{location}"
50
+ end
51
+ else
52
+ "relays must be in the format: plugin:location, example (efnet:\#zmb)"
53
+ end
54
+ end
55
+
56
+ def del_command(e, relay)
57
+ if @relays.has_key?(relay) then
58
+ @relays.delete(relay)
59
+ "#{relay}: relay deleted"
60
+ else
61
+ "no such relay"
62
+ end
63
+ end
64
+ end
65
+
66
+ Plugin.define do
67
+ name "relay"
68
+ description "This plugin allows you to relay messages from one channel/server to another."
69
+ object Relay
70
+ end
data/plugins/users.rb ADDED
@@ -0,0 +1,280 @@
1
+ class Event
2
+ attr_accessor :user
3
+ end
4
+
5
+ class User
6
+ require 'digest/sha1'
7
+
8
+ attr_accessor :username, :password, :userhosts, :permissions, :seen
9
+
10
+ def to_json(*a)
11
+ {'username' => @username, 'password' => @password, 'userhosts' => @userhosts, 'permissions' => @permissions, 'seen' => @seen}.to_json(*a)
12
+ end
13
+
14
+ def self.create_settings(data)
15
+ require 'time'
16
+ user = new(data['username'], data['password'])
17
+ user.userhosts = data['userhosts'] if data.has_key?('userhosts')
18
+ user.permissions = data['permissions'] if data.has_key?('permissions')
19
+ user.seen = Time.parse(data['seen']) if data.has_key?('seen') and data['seen']
20
+ user
21
+ end
22
+
23
+ def initialize(username=nil, password=nil, userhost=nil)
24
+ @username = username
25
+ @password = Digest::SHA1.hexdigest(password) if password
26
+ @userhosts = Array.new
27
+ @userhosts << userhost if userhost
28
+ @permissions = Array.new
29
+ end
30
+
31
+ def concat(other_user)
32
+ @permissions += other_user.permissions
33
+ @userhosts += other_user.userhosts
34
+ end
35
+
36
+ def password=(new_password)
37
+ @password = Digest::SHA1.hexdigest(new_password)
38
+ end
39
+
40
+ def password?(check_password)
41
+ @password != nil and @password == Digest::SHA1.hexdigest(check_password)
42
+ end
43
+
44
+ def authenticated?
45
+ true
46
+ end
47
+
48
+ def admin?
49
+ @permissions.include?("owner") or @permissions.include?("admin")
50
+ end
51
+
52
+ def permission?(permission)
53
+ admin? or @permissions.include?(permission)
54
+ end
55
+
56
+ def permit(permission)
57
+ @permissions << permission
58
+ end
59
+
60
+ def deny(permission)
61
+ @permissions.delete(permission)
62
+ end
63
+ end
64
+
65
+ class AnonymousUser
66
+ def authenticated?
67
+ false
68
+ end
69
+
70
+ def permission?(permission)
71
+ false
72
+ end
73
+
74
+ def admin?
75
+ false
76
+ end
77
+ end
78
+
79
+ class Users
80
+ attr_accessor :users
81
+
82
+ def initialize(sender, settings={})
83
+ @delegate = sender
84
+ @users = settings['users'].map{ |user| User.create_settings(user) } if settings.has_key?('users')
85
+ @users = Array.new if not @users
86
+ end
87
+
88
+ def to_json(*a)
89
+ {'users' => @users, 'plugin' => 'users'}.to_json(*a)
90
+ end
91
+
92
+ def user!(search)
93
+ @users.find{|user| user.userhosts.include?(search) or user.username == search}
94
+ end
95
+
96
+ def user(search)
97
+ user!(search) or AnonymousUser.new
98
+ end
99
+
100
+ def pre_event(sender, e)
101
+ e.user = user(e.userhost) if e.respond_to?('userhost') and not e.user
102
+ e.user.seen = Time.now if e.user.respond_to?('seen')
103
+ end
104
+
105
+ def create_user(username, password=nil, userhost=nil)
106
+ user = User.new(username, password, userhost)
107
+ @users << user
108
+ user
109
+ end
110
+
111
+ def commands
112
+ require 'zmb/commands'
113
+ {
114
+ 'meet' => Command.new(self, :meet, 1, 'Meet a new user'),
115
+ 'forget' => AuthCommand.new(self, :forget, 0, "Forget about a user"),
116
+ 'permit' => PermCommand.new('admin', self, :permit, 2),
117
+ 'deny' => PermCommand.new('admin', self, :deny, 2),
118
+ 'perms' => AuthCommand.new(self, :perms, 1, 'List all permissions a user has.'),
119
+ 'merge' => PermCommand.new('admin', self, :merge, 2, 'Merge two users together'),
120
+ 'password' => AuthCommand.new(self, :password, 1, 'Set the password for your account'),
121
+ 'login' => Command.new(self, :login, 2, 'Add your current host to the username and password provided.'),
122
+ 'logout' => AuthCommand.new(self, :logout, 0, 'Remove your current host from your account.'),
123
+ 'whoami' => Command.new(self, :whoami, 0, 'Who are you logged in as?'),
124
+ 'userhosts' => AuthCommand.new(self, :userhosts, 0, 'List all the hosts associated with your account'),
125
+ 'adduserhost' => AuthCommand.new(self, :adduserhost, 1, 'Add a host to your account'),
126
+ 'deluserhost' => AuthCommand.new(self, :deluserhost, 1, 'Remove a host to your account'),
127
+ 'names' => Command.new(self, :names, 1, 'List all the users'),
128
+ 'seen' => Command.new(self, :seen, 1, 'When was a user last seen'),
129
+ 'sudo' => PermCommand.new('admin', self, :sudo, 2, 'Execute a command as another user.'),
130
+ }
131
+ end
132
+
133
+ def meet(e, username=nil)
134
+ if e.user.admin? and username then
135
+ return "#{username} already exists" if user!(username)
136
+ user = create_user(username)
137
+ "Hello #{username}"
138
+ elsif not e.user.authenticated? then
139
+ return "#{e.sender} already exists" if user!(e.sender)
140
+ if e.respond_to?('userhost') and e.respond_to?('user') then
141
+ user = create_user(e.name, nil, e.userhost)
142
+ end
143
+ "Hello #{user.username}"
144
+ else
145
+ "You already have an account #{e.user.username}"
146
+ end
147
+ end
148
+
149
+ def forget(e)
150
+ "user #{@e.users.delete(e.user).username} deleted"
151
+ end
152
+
153
+ def permit(e, username, permission)
154
+ if user = user!(username) then
155
+ user.permit(permission)
156
+ "permission added"
157
+ else
158
+ "#{username} does not exist"
159
+ end
160
+ end
161
+
162
+ def deny(e, username, permission)
163
+ if user = user!(username) then
164
+ user.deny(permission)
165
+ 'permission removed'
166
+ else
167
+ "#{username} does not exist"
168
+ end
169
+ end
170
+
171
+ def perms(e, username=nil)
172
+ e.user.permissions.empty? ? "#{e.user.username} has no permissions" : e.user.permissions.join(', ')
173
+ end
174
+
175
+ def merge(e, username, other_username)
176
+ user = user!(username)
177
+ other_user = user!(other_username)
178
+
179
+ if user and other_user then
180
+ user.concat other_user
181
+ @users.delete other_user
182
+ "#{other_user.username} now merged into #{user.username}"
183
+ else
184
+ 'User(s) do not exist'
185
+ end
186
+ end
187
+
188
+ def password(e, password)
189
+ e.user.password = password
190
+ "#{e.user.username} password has been set to #{password}"
191
+ end
192
+
193
+ def login(e, username, password)
194
+ user = user!(username)
195
+
196
+ if e.user.authenticated? then
197
+ 'already logged in'
198
+ elsif user and user.password?(password) then
199
+ user.hosts << e.userhost
200
+ "#{request.hostname} added to your account #{user.username}"
201
+ else
202
+ 'user and/or password is incorrect'
203
+ end
204
+ end
205
+
206
+ def logout(e)
207
+ e.user.hosts.delete(e.userhost)
208
+ "userhost #{e.hostname} removed from your account."
209
+ end
210
+
211
+ def whoami(e)
212
+ e.user.authenticated? ? "#{e.user.username}" : 'nobody'
213
+ end
214
+
215
+ def userhosts(e)
216
+ e.user.userhosts.empty? ? "#{e.user.username} has no userhosts" : e.user.userhosts.join(', ')
217
+ end
218
+
219
+ def adduserhost(e, userhost)
220
+ e.user.userhosts << userhost
221
+ "#{userhost} added to #{e.user.username}"
222
+ end
223
+
224
+ def deluserhost(e, userhost)
225
+ if e.user.userhosts.delete(userhost) then
226
+ "#{userhost} deleted from #{e.user.username}"
227
+ else
228
+ "#{e.user.username} doesn't have #{userhost}"
229
+ end
230
+ end
231
+
232
+ def names(e, search=nil)
233
+ users = @users.map{|user| user.username}
234
+ users = users.grep(/#{search}/i) if search
235
+
236
+ if users.empty? then
237
+ "no users found"
238
+ else
239
+ users.join(', ')
240
+ end
241
+ end
242
+
243
+ def seen(e, username=nil)
244
+ if user = user!(username) and user.seen then
245
+ diff = Time.now - user.seen
246
+
247
+ if diff < 60 then
248
+ msg = "#{Integer(diff)} seconds ago"
249
+ elsif diff < 3600 then
250
+ msg = "#{Integer(diff/60)} minutes ago"
251
+ elsif diff < 86400 then
252
+ msg = "about #{Integer(diff/3600)} hours ago"
253
+ else
254
+ msg = "#{Integer(diff/86400)} days ago"
255
+ end
256
+
257
+ "#{username} last seen #{msg}"
258
+ else
259
+ "#{username} has never been seen"
260
+ end
261
+ end
262
+
263
+ def sudo(e, search, command)
264
+ if user = user!(search) then
265
+ new_event = e.clone
266
+ new_event.user = user
267
+ new_event.message = @delegate.instances['commands'].cc + command
268
+ @delegate.event(self, new_event)
269
+ nil
270
+ else
271
+ "#{search}: Username or userhost not found"
272
+ end
273
+ end
274
+ end
275
+
276
+ Plugin.define do
277
+ name "users"
278
+ description "users manager"
279
+ object Users
280
+ end