butler 1.8.2 → 1.8.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/bin/botcontrol +1 -1
- data/data/butler/dialogs/create_config.rb +2 -2
- data/data/butler/dialogs/quickcreate.rb +6 -4
- data/data/butler/dialogs/uninstall.rb +4 -3
- data/data/butler/plugins/core/access.rb +10 -10
- data/data/butler/plugins/dev/bleakhouse.rb +19 -8
- data/data/butler/plugins/operator/deop.rb +10 -1
- data/data/butler/plugins/operator/devoice.rb +9 -0
- data/data/butler/plugins/operator/limit.rb +12 -0
- data/data/butler/plugins/operator/op.rb +9 -0
- data/data/butler/plugins/operator/voice.rb +10 -0
- data/data/butler/plugins/util/calculator.rb +11 -0
- data/data/butler/services/org.rubyforge.butler/calculator/1/calculator.rb +68 -0
- data/data/butler/services/org.rubyforge.butler/log/1/service.rb +198 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/acknowledge.yaml +8 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/gratitude.yaml +3 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/hello.yaml +6 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/ignorance.yaml +7 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/ignorance_about.yaml +3 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/insult.yaml +3 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/data/en/rejection.yaml +12 -0
- data/data/butler/services/org.rubyforge.butler/strings/1/service.rb +50 -0
- data/lib/access.rb +6 -3
- data/lib/access/privilege.rb +9 -78
- data/lib/access/privilegelist.rb +75 -0
- data/lib/access/role.rb +14 -94
- data/lib/access/role/base.rb +40 -0
- data/lib/access/rolelist.rb +99 -0
- data/lib/access/savable.rb +6 -3
- data/lib/access/user.rb +21 -19
- data/lib/access/version.rb +17 -0
- data/lib/access/yamlbase.rb +64 -48
- data/lib/butler.rb +1 -0
- data/lib/butler/bot.rb +8 -2
- data/lib/butler/control.rb +3 -1
- data/lib/butler/initialvalues.rb +1 -1
- data/lib/butler/irc/client.rb +6 -0
- data/lib/butler/irc/message.rb +14 -9
- data/lib/butler/irc/parser.rb +8 -5
- data/lib/butler/irc/parser/generic.rb +33 -1
- data/lib/butler/irc/parser/rfc2812.rb +5 -2
- data/lib/butler/plugin.rb +22 -2
- data/lib/butler/plugins.rb +2 -7
- data/lib/butler/service.rb +73 -0
- data/lib/butler/services.rb +65 -0
- data/lib/butler/version.rb +1 -1
- data/lib/ruby/array/random.rb +17 -0
- data/lib/ruby/string/camelcase.rb +14 -0
- data/test/test_access.rb +164 -59
- data/test/test_access/privilege/banners.statistics.yaml +3 -0
- data/test/test_access/privilege/banners.yaml +3 -0
- data/test/test_access/privilege/news.create.yaml +3 -0
- data/test/test_access/privilege/news.delete.yaml +3 -0
- data/test/test_access/privilege/news.edit.yaml +3 -0
- data/test/test_access/privilege/news.read.yaml +3 -0
- data/test/test_access/privilege/news.yaml +3 -0
- data/test/test_access/privilege/paid_content.yaml +3 -0
- data/test/test_access/privilege/statistics.ftp.yaml +3 -0
- data/test/test_access/privilege/statistics.web.yaml +3 -0
- data/test/test_access/privilege/statistics.yaml +3 -0
- data/test/test_access/role/chiefeditor.yaml +7 -0
- data/test/test_access/role/editor.yaml +9 -0
- data/test/test_access/user/test.yaml +12 -0
- metadata +51 -5
- data/data/butler/plugins/core/user.rb +0 -166
- data/data/butler/plugins/dev/onhandlers.rb +0 -93
- data/data/butler/plugins/service/log.rb +0 -183
data/Rakefile
CHANGED
@@ -62,7 +62,7 @@ LOCAL_PATHS['plugins'] = "#{LOCAL_PATHS['data']}/plugins"
|
|
62
62
|
#LOCAL_PATHS['config'] = "#{Config::CONFIG['sysconfdir']}/butler"
|
63
63
|
LOCAL_PATHS['pids'] = "#{Config::CONFIG['localstatedir']}/run/butler"
|
64
64
|
CHANGES = "See CHANGELOG.txt"
|
65
|
-
DESC = "Butler 1.8.
|
65
|
+
DESC = "Butler 1.8.3, 4th alpha release of butler2."
|
66
66
|
|
67
67
|
GemSpec = Gem::Specification.new do |s|
|
68
68
|
s.homepage = HOMEPATH
|
data/bin/botcontrol
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
begin
|
2
|
-
user = variables.user || variables.botcontrol.user
|
2
|
+
user = variables.user || variables.botcontrol.user # can be nil
|
3
3
|
variables.botcontrol.configure_user(user) unless variables.botcontrol.configured?(user)
|
4
|
-
Butler.path = variables.botcontrol.butler_path
|
4
|
+
Butler.path = variables.botcontrol.butler_path(user)
|
5
5
|
rescue Errno::EACCES
|
6
6
|
say :cant_configure, :user => user, :app => $0
|
7
7
|
exit
|
@@ -35,15 +35,17 @@ user = ask(:user, nil, String, :min => 3)
|
|
35
35
|
pass = ask(:pass, nil, String, :min => 3)
|
36
36
|
admin = bot.access.user.create(user, pass, nil, true, :active => true)
|
37
37
|
role = bot.access.role.create("default_role", "This role is applied to every user")
|
38
|
-
|
38
|
+
%w[
|
39
39
|
plugin/public
|
40
40
|
plugin/core/login
|
41
41
|
plugin/core/logout
|
42
42
|
plugin/core/help
|
43
43
|
plugin/core/usage
|
44
|
-
])
|
45
|
-
|
46
|
-
|
44
|
+
].each { |priv| role.privileges.add_oid(priv) }
|
45
|
+
default_user = bot.access.user.create("default_user", nil, nil, false, :active => true)
|
46
|
+
%w[default_role].each { |role|
|
47
|
+
default_user.roles.add_oid(role)
|
48
|
+
}
|
47
49
|
|
48
50
|
puts
|
49
51
|
say(:how_to_start, :botname => nick, :user => user, :pass => pass)
|
@@ -1,7 +1,8 @@
|
|
1
|
-
|
1
|
+
# botcontrol must run as sudo in order to uninstall all stuff
|
2
|
+
unless ENV["SUDO_USER"] || Process.uid.zero? # *NIX
|
2
3
|
say(:must_run_as_sudo)
|
3
4
|
else
|
4
|
-
variables.config
|
5
|
+
variables.botcontrol.config[:users].sort.each { |user, conf|
|
5
6
|
if prompt(:uninstall_user, false, :name => user) then
|
6
7
|
FileUtils.rm_r(conf[:bots])
|
7
8
|
FileUtils.rm_r(conf[:run])
|
@@ -12,6 +13,6 @@ else
|
|
12
13
|
else
|
13
14
|
say(:uninstalling_botcontrol)
|
14
15
|
File.delete($0)
|
15
|
-
File.delete(variables.path
|
16
|
+
File.delete(variables.botcontrol.path[:config])
|
16
17
|
end
|
17
18
|
end
|
@@ -35,7 +35,7 @@ def on_create_user(params)
|
|
35
35
|
false,
|
36
36
|
:active => !!params.active
|
37
37
|
)
|
38
|
-
user[params.username].roles.
|
38
|
+
user[params.username].roles.add_oid("default_role")
|
39
39
|
answer(:user_created, :username => params.username)
|
40
40
|
end
|
41
41
|
end
|
@@ -44,7 +44,7 @@ end
|
|
44
44
|
def on_delete_user(params)
|
45
45
|
params.username.downcase!
|
46
46
|
if user.exists?(params.username) then
|
47
|
-
user.
|
47
|
+
user.delete_oid(params.username)
|
48
48
|
answer(:user_deleted, :username => params.username)
|
49
49
|
else
|
50
50
|
answer(:user_doesnt_exist, :username => params.username)
|
@@ -61,7 +61,7 @@ end
|
|
61
61
|
def on_delete_role(params)
|
62
62
|
params.rolename.downcase!
|
63
63
|
return answer(:role_doesnt_exist, :rolename => params.rolename) unless role.exists?(params.rolename)
|
64
|
-
role.
|
64
|
+
role.delete_oid(params.rolename)
|
65
65
|
answer(:role_deleted, :rolename => params.rolename)
|
66
66
|
end
|
67
67
|
|
@@ -69,7 +69,7 @@ end
|
|
69
69
|
def on_grant_privilege_to_user(params)
|
70
70
|
params.username.downcase!
|
71
71
|
return answer(:user_doesnt_exist, :username => params.username) unless user.exists?(params.username)
|
72
|
-
user[params.username].privileges.
|
72
|
+
user[params.username].privileges.add_oid(params.privilege)
|
73
73
|
answer(:privilege_granted_to_user, :username => params.username, :privilege => params.privilege)
|
74
74
|
end
|
75
75
|
|
@@ -77,7 +77,7 @@ end
|
|
77
77
|
def on_revoke_privilege_from_user(params)
|
78
78
|
params.username.downcase!
|
79
79
|
return answer(:user_doesnt_exist, :username => params.username) unless user.exists?(params.username)
|
80
|
-
user[params.username].privileges.
|
80
|
+
user[params.username].privileges.remove_oid(params.privilege)
|
81
81
|
answer(:privilege_revoked_from_user, :username => params.username, :privilege => params.privilege)
|
82
82
|
end
|
83
83
|
|
@@ -85,7 +85,7 @@ end
|
|
85
85
|
def on_grant_privilege_to_role(params)
|
86
86
|
params.rolename.downcase!
|
87
87
|
return answer(:role_doesnt_exist, :rolename => params.rolename) unless role.exists?(params.rolename)
|
88
|
-
role[params.rolename].privileges.
|
88
|
+
role[params.rolename].privileges.add_oid(params.privilege)
|
89
89
|
answer(:privilege_granted_to_role, :rolename => params.rolename, :privilege => params.privilege)
|
90
90
|
end
|
91
91
|
|
@@ -93,7 +93,7 @@ end
|
|
93
93
|
def on_revoke_privilege_from_role(params)
|
94
94
|
params.rolename.downcase!
|
95
95
|
return answer(:role_doesnt_exist, :rolename => params.rolename) unless role.exists?(params.rolename)
|
96
|
-
role[params.rolename].privileges.
|
96
|
+
role[params.rolename].privileges.remove_oid(params.privilege)
|
97
97
|
answer(:privilege_revoked_from_role, :rolename => params.rolename, :privilege => params.privilege)
|
98
98
|
end
|
99
99
|
|
@@ -103,7 +103,7 @@ def on_add_role_to_user(params)
|
|
103
103
|
params.rolename.downcase!
|
104
104
|
return answer(:user_doesnt_exist, :username => params.username) unless user.exists?(params.username)
|
105
105
|
return answer(:role_doesnt_exist, :username => params.rolename) unless role.exists?(params.rolename)
|
106
|
-
user[params.username].roles.
|
106
|
+
user[params.username].roles.add_oid(params.rolename)
|
107
107
|
answer(:role_added_to_user, :username => params.username, :rolename => params.rolename)
|
108
108
|
end
|
109
109
|
|
@@ -113,7 +113,7 @@ def on_remove_role_from_user(params)
|
|
113
113
|
params.rolename.downcase!
|
114
114
|
return answer(:user_doesnt_exist, :username => params.username) unless user.exists?(params.username)
|
115
115
|
return answer(:role_doesnt_exist, :username => params.rolename) unless role.exists?(params.rolename)
|
116
|
-
user[params.username].roles.
|
116
|
+
user[params.username].roles.remove_oid(params.rolename)
|
117
117
|
answer(:role_removed_from_user, :username => params.username, :rolename => params.rolename)
|
118
118
|
end
|
119
119
|
|
@@ -139,7 +139,7 @@ __END__
|
|
139
139
|
:on_create_user:
|
140
140
|
en: "create user :username [with password :password] [:active{active}]"
|
141
141
|
:on_delete_user:
|
142
|
-
en: "delete user :
|
142
|
+
en: "delete user :username"
|
143
143
|
:on_create_role:
|
144
144
|
en: "create role :rolename [with description +description]"
|
145
145
|
:on_delete_role:
|
@@ -4,14 +4,19 @@
|
|
4
4
|
# See LICENSE.txt for permissions.
|
5
5
|
#++
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
|
8
|
+
$BLEAK_HOUSE ||= false
|
9
|
+
|
10
|
+
plugin_attribute :logfile
|
11
|
+
plugin_attribute :active
|
10
12
|
|
11
13
|
def self.on_load
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
if $BLEAK_HOUSE then
|
15
|
+
@logfile = @butler.path.log+'/bleakhouse.log'
|
16
|
+
@bl_logger = BleakHouse::Logger.new
|
17
|
+
@active = true
|
18
|
+
File.delete(@logfile) if File.exist?(@logfile)
|
19
|
+
end
|
15
20
|
end
|
16
21
|
|
17
22
|
def self.snapshot(*args)
|
@@ -19,8 +24,12 @@ def self.snapshot(*args)
|
|
19
24
|
end
|
20
25
|
|
21
26
|
def on_trigger
|
22
|
-
plugin.
|
23
|
-
|
27
|
+
if plugin.active then
|
28
|
+
plugin.snapshot('plugin', false)
|
29
|
+
answer(:done, :file => plugin.logfile)
|
30
|
+
else
|
31
|
+
answer(:inactive)
|
32
|
+
end
|
24
33
|
end
|
25
34
|
|
26
35
|
__END__
|
@@ -37,6 +46,8 @@ __END__
|
|
37
46
|
:strings:
|
38
47
|
:done:
|
39
48
|
en: "Snapshot taken. The file is in <%= file %>."
|
49
|
+
:inactive:
|
50
|
+
en: "Bleak house is not activated for this bot."
|
40
51
|
:summary:
|
41
52
|
en: Inspect butlers memory usage.
|
42
53
|
:trigger:
|
@@ -20,17 +20,26 @@ __END__
|
|
20
20
|
:mail: "apeiros@gmx.net"
|
21
21
|
:version: "1.0.0"
|
22
22
|
:author: "Stefan Rusterholz"
|
23
|
+
:translation:
|
24
|
+
es: "Rafael George, <george.rafael@gmail.com>"
|
23
25
|
:help:
|
24
26
|
en:
|
25
27
|
"": |
|
26
|
-
Revoke a users op via butler
|
28
|
+
Revoke a users op via butler
|
29
|
+
es:
|
30
|
+
"": |
|
31
|
+
Revoca a un usuario los privilegios de operador atravez de butler
|
27
32
|
:map:
|
28
33
|
:on_deop:
|
29
34
|
en: "deop [*user@Nick] [in :channel@Channel]"
|
35
|
+
es: "deop [*user@Nick] [en :channel@Channel]"
|
30
36
|
:revision:
|
31
37
|
:plugin: 1
|
32
38
|
:summary:
|
33
39
|
en: Revoke a users op via butler.
|
40
|
+
es: Revoca a un usuario los privilegios de operador atravez de butler
|
34
41
|
:usage:
|
35
42
|
en: |
|
36
43
|
![b]deop![o] [![c(green)]nick![o] ...] [in ![c(green)]channel![o]]
|
44
|
+
es: |
|
45
|
+
![b]deop![o] [![c(green)]nick![o] ...] [en ![c(green)]canal![o]]
|
@@ -19,17 +19,26 @@ __END__
|
|
19
19
|
:mail: "apeiros@gmx.net"
|
20
20
|
:version: "1.0.0"
|
21
21
|
:author: "Stefan Rusterholz"
|
22
|
+
:translation:
|
23
|
+
es: "Rafael George, <george.rafael@gmail.com>"
|
22
24
|
:help:
|
23
25
|
en:
|
24
26
|
"": |
|
25
27
|
Revoke a users voice via butler.
|
28
|
+
es:
|
29
|
+
"": |
|
30
|
+
Revoca la voz de un usuario atravez de butler.
|
26
31
|
:map:
|
27
32
|
:on_devoice:
|
28
33
|
en: "devoice [*user@Nick] [in :channel@Channel]"
|
34
|
+
es: "desvoz [*user@Nick] [en :channel@Channel]"
|
29
35
|
:revision:
|
30
36
|
:plugin: 1
|
31
37
|
:summary:
|
32
38
|
en: Revoke a users voice via butler.
|
39
|
+
es: Revoca la voz de un usuario atravez de butler.
|
33
40
|
:usage:
|
34
41
|
en: |
|
35
42
|
![b]devoice![o] [![c(green)]nick![o] ...] [![c(green)]channel![o] ...]
|
43
|
+
es: |
|
44
|
+
![b]desvoz![o] [![c(green)]nick![o] ...] [![c(green)]canal![o] ...]
|
@@ -59,24 +59,36 @@ __END__
|
|
59
59
|
:mail: "apeiros@gmx.net"
|
60
60
|
:version: "1.0.0"
|
61
61
|
:author: "Stefan Rusterholz"
|
62
|
+
:translation:
|
63
|
+
es: "Rafael George, <george.rafael@gmail.com>"
|
62
64
|
:help:
|
63
65
|
en:
|
64
66
|
"": |
|
65
67
|
A slowly shifting channel-limit to avoid join-floods.
|
68
|
+
es:
|
69
|
+
"": |
|
70
|
+
Maneja los excesos de ingresos al canal.
|
66
71
|
:map:
|
67
72
|
:on_limit:
|
68
73
|
en: limit *channels@Channel
|
74
|
+
es: limita *channels@Channel
|
69
75
|
:on_unlimit:
|
70
76
|
en: unlimit *channels@Channel
|
77
|
+
es: deslimita *channels@Channel
|
71
78
|
:revision:
|
72
79
|
:plugin: 1
|
73
80
|
:strings:
|
74
81
|
:limiting:
|
75
82
|
en: Limiting channels <%= channels.join(', ') %>.
|
83
|
+
es: Limita canales <%= channels.join(', ') %>.
|
76
84
|
:unlimiting:
|
77
85
|
en: No longer limiting channels <%= channels.join(', ') %>.
|
86
|
+
es: No sigue limitando canales <%= channels.join(', ') %>.
|
78
87
|
:summary:
|
79
88
|
en: A slowly shifting channel-limit to avoid join-floods.
|
89
|
+
es: Maneja los excesos de ingresos al canal.
|
80
90
|
:usage:
|
81
91
|
en: |
|
82
92
|
(![b]limit![o]|![b]unlimit![o]) ![c(green)]channel![o] ...
|
93
|
+
es: |
|
94
|
+
(![b]limita![o]|![b]deslimita![o]) ![c(green)]canales![o] ...
|
@@ -19,18 +19,27 @@ __END__
|
|
19
19
|
:mail: "apeiros@gmx.net"
|
20
20
|
:version: "1.0.0"
|
21
21
|
:author: "Stefan Rusterholz"
|
22
|
+
:translation:
|
23
|
+
es: "Rafael George, <george.rafael@gmail.com>"
|
22
24
|
:help:
|
23
25
|
en:
|
24
26
|
"": |
|
25
27
|
Grant a user op via butler.
|
28
|
+
es:
|
29
|
+
"": |
|
30
|
+
Otorga privilegios de operador a un usuario atravez de butler.
|
26
31
|
:map:
|
27
32
|
:on_op:
|
28
33
|
en: "op [*user@Nick] [in :channel@Channel]"
|
34
|
+
es: "op [*user@Nick] [en :channel@Channel]"
|
29
35
|
:revision:
|
30
36
|
:plugin: 1
|
31
37
|
:strings:
|
32
38
|
:summary:
|
33
39
|
en: Grant users op via butler.
|
40
|
+
es: Otorga privilegios de operador a un usuario atravez de butler.
|
34
41
|
:usage:
|
35
42
|
en: |
|
36
43
|
![b]op![o] [![c(green)]nick![o] ...] [in ![c(green)]channel![o]]
|
44
|
+
es: |
|
45
|
+
![b]op![o] [![c(green)]nick![o] ...] [in ![c(green)]canal![o]]
|
@@ -19,18 +19,28 @@ __END__
|
|
19
19
|
:mail: "apeiros@gmx.net"
|
20
20
|
:version: "1.0.0"
|
21
21
|
:author: "Stefan Rusterholz"
|
22
|
+
:translation:
|
23
|
+
es: "Rafael George, <george.rafael@gmail.com>"
|
22
24
|
:help:
|
23
25
|
en:
|
24
26
|
"": |
|
25
27
|
Grant a user voice via butler.
|
28
|
+
es:
|
29
|
+
"": |
|
30
|
+
Otorga voz a un usuario atravez de butler.
|
26
31
|
:map:
|
27
32
|
:on_voice:
|
28
33
|
en:
|
29
34
|
"voice [*user@Nick] [in :channel@Channel]"
|
35
|
+
es:
|
36
|
+
"voz [*user@Nick] [en :channel@Channel]"
|
30
37
|
:revision:
|
31
38
|
:plugin: 1
|
32
39
|
:summary:
|
33
40
|
en: Grant a user voice via butler.
|
41
|
+
es: Otorga voz a un usuario atravez de butler.
|
34
42
|
:usage:
|
35
43
|
en: |
|
36
44
|
![b]voice![o] [![c(green)]nick![o] ...] [in ![c(green)]channel![o]]
|
45
|
+
es: |
|
46
|
+
![b]voice![o] [![c(green)]nick![o] ...] [in ![c(green)]canal![o]]
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'blank'
|
2
|
+
|
3
|
+
class Calculator < Blank('inspect', 'binding', 'method_missing')
|
4
|
+
class Functions
|
5
|
+
def initialize
|
6
|
+
@functions = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](name)
|
10
|
+
@functions[name.to_s]
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(name, definition)
|
14
|
+
@functions[name.to_s] = definition
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(m, *args)
|
18
|
+
@functions[m.to_s].call(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to?(m, *a)
|
22
|
+
super || @functions.has_key?(m.to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(m, *args)
|
26
|
+
super unless @functions.has_key?(m.to_s)
|
27
|
+
@functions[m.to_s].call(*args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
include Math
|
32
|
+
|
33
|
+
attr_reader :term
|
34
|
+
|
35
|
+
def initialize(term, delegate=nil)
|
36
|
+
@term = term.scan(/\s+|,|[a-z]*\(|\)|-?\d(?:\.\d+)?|[a-z]+|[*\/%+-]/).join
|
37
|
+
@variables = {}
|
38
|
+
@delegate = delegate
|
39
|
+
@results = []
|
40
|
+
end
|
41
|
+
|
42
|
+
def result(variables={})
|
43
|
+
@variables=variables
|
44
|
+
@results.unshift Thread.new {
|
45
|
+
$SAFE = 3
|
46
|
+
Kernel.eval(@term, binding)
|
47
|
+
}.value
|
48
|
+
@results.pop if @results.length > 10
|
49
|
+
@results.first
|
50
|
+
end
|
51
|
+
alias call result
|
52
|
+
|
53
|
+
def load(result)
|
54
|
+
@results[result]
|
55
|
+
end
|
56
|
+
|
57
|
+
def method_missing(m, *a)
|
58
|
+
if a.empty? && @variables.has_key?(m) then
|
59
|
+
@variables[m]
|
60
|
+
elsif @delegate.respond_to?(m) then
|
61
|
+
@delegate.call(m, *a)
|
62
|
+
else
|
63
|
+
super
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
register_service("org.rubyforge.butler.calculator", Calculator)
|
@@ -0,0 +1,198 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
require 'sqlite3'
|
10
|
+
require 'thread'
|
11
|
+
require 'ruby/file/write'
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
MessageTypes = [:PRIVMSG, :NOTICE, :JOIN, :PART, :QUIT, :KICK, :KILL]
|
16
|
+
Row = Struct.new(:oid, :time, :channel, :nick, :type, :text)
|
17
|
+
def Row.from_row(row)
|
18
|
+
oid, time, channel, nick, type, text = *row
|
19
|
+
new(oid.to_i, Time.at(oid.to_i), channel, nick, MessageTypes[type.to_i], text)
|
20
|
+
end
|
21
|
+
|
22
|
+
class IRCLogger
|
23
|
+
def initialize(db, channels)
|
24
|
+
@db_file = db
|
25
|
+
@db = SQLite3::Database.new(db)
|
26
|
+
@db.execute %q{
|
27
|
+
CREATE TABLE IF NOT EXISTS messages(
|
28
|
+
oid INTEGER PRIMARY KEY AUTOINCREMENT,
|
29
|
+
time INTEGER,
|
30
|
+
channel TEXT,
|
31
|
+
nick TEXT,
|
32
|
+
type INTEGER,
|
33
|
+
text TEXT
|
34
|
+
)
|
35
|
+
}
|
36
|
+
@insert = @db.prepare %q{
|
37
|
+
INSERT INTO messages
|
38
|
+
(time, channel, nick, type, text)
|
39
|
+
VALUES (:time, :channel, :nick, :type, :text)
|
40
|
+
}
|
41
|
+
File.write(channels, {}.to_yaml) unless File.exist?(channels)
|
42
|
+
@channels = YAML.load_file(channels)
|
43
|
+
@config_file = channels
|
44
|
+
@lock = Mutex.new
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_logging(channel)
|
48
|
+
@lock.synchronize {
|
49
|
+
@channels[channel] = true
|
50
|
+
File.write(@config_file, @channels.to_yaml)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop_logging(channel)
|
55
|
+
@lock.synchronize {
|
56
|
+
@channels.delete(channel)
|
57
|
+
File.write(@config_file, @channels.to_yaml)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def logged?(channel)
|
62
|
+
@channels.has_key?(channel)
|
63
|
+
end
|
64
|
+
|
65
|
+
def insert(values)
|
66
|
+
@insert.execute(values)
|
67
|
+
end
|
68
|
+
|
69
|
+
def select(statement=nil, *values)
|
70
|
+
query = "SELECT * FROM messages #{statement}"
|
71
|
+
if block_given? then
|
72
|
+
@db.execute(query, *values) { |row|
|
73
|
+
yield(Row.from_row(row))
|
74
|
+
}
|
75
|
+
else
|
76
|
+
@db.execute(query, *values).map { |row|
|
77
|
+
Row.from_row(row)
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def find(args={}, &block)
|
83
|
+
where = []
|
84
|
+
if nick = args[:nick] then
|
85
|
+
where << field_equals_values('nick', nick)
|
86
|
+
end
|
87
|
+
if channel = args[:channel] then
|
88
|
+
where << field_equals_values('channel', channel)
|
89
|
+
end
|
90
|
+
if time = args[:time] then
|
91
|
+
where << "time >= #{SQLite3::Database.quote(time.begin.to_i)} AND time <= #{SQLite3::Database.quote(time.end.to_i)}"
|
92
|
+
end
|
93
|
+
if types = args[:type] then
|
94
|
+
where << field_equals_values('type', types)
|
95
|
+
end
|
96
|
+
if text = args[:text] then
|
97
|
+
field_contains_all_values('text', text)
|
98
|
+
end
|
99
|
+
select(where.empty? ? nil : 'WHERE '+where.join(' AND '), &block)
|
100
|
+
end
|
101
|
+
|
102
|
+
def field_equals_values(field, values)
|
103
|
+
if Array === values then
|
104
|
+
values.map { |e| "#{field} LIKE '#{SQLite3::Database.quote(e)}'" }.join(" AND ")
|
105
|
+
else
|
106
|
+
"#{field} LIKE '#{SQLite3::Database.quote(values)}'"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def field_equals_values(field, values)
|
111
|
+
if Array === values then
|
112
|
+
is_in(field, values)
|
113
|
+
else
|
114
|
+
"#{field} = '#{SQLite3::Database.quote(values)}'"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def is_in(field, values)
|
119
|
+
"#{field} IN ('#{values.map { |e| SQLite3::Database.quote(text) }.join('\', \'') }')"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.on_load
|
124
|
+
logger = IRCLogger.new(@path.base+'/log.sqlite', @path.base+'/channels.yaml')
|
125
|
+
|
126
|
+
subscribe(:PRIVMSG, -10, MessageTypes.index(:PRIVMSG)) { |listener, message, type|
|
127
|
+
next unless logger.logged?(message.channel.to_str)
|
128
|
+
logger.insert(
|
129
|
+
:time => Time.now.to_i,
|
130
|
+
:channel => message.channel.to_str,
|
131
|
+
:nick => message.from.nick,
|
132
|
+
:type => type,
|
133
|
+
:text => message.text
|
134
|
+
)
|
135
|
+
}
|
136
|
+
subscribe(:NOTICE, -10, MessageTypes.index(:NOTICE)) { |listener, message, type|
|
137
|
+
next unless logger.logged?(message.channel.to_str)
|
138
|
+
logger.insert(
|
139
|
+
:time => Time.now.to_i,
|
140
|
+
:channel => message.channel.to_str,
|
141
|
+
:nick => message.from.nick,
|
142
|
+
:type => type,
|
143
|
+
:text => message.text
|
144
|
+
)
|
145
|
+
}
|
146
|
+
subscribe(:JOIN, -10, MessageTypes.index(:JOIN)) { |listener, message, type|
|
147
|
+
next unless logger.logged?(message.channel.to_str)
|
148
|
+
logger.insert(
|
149
|
+
:time => Time.now.to_i,
|
150
|
+
:channel => message.channel.to_str,
|
151
|
+
:nick => message.from.nick,
|
152
|
+
:type => type,
|
153
|
+
:text => nil
|
154
|
+
)
|
155
|
+
}
|
156
|
+
subscribe(:PART, -10, MessageTypes.index(:PART)) { |listener, message, type|
|
157
|
+
next unless logger.logged?(message.channel.to_str)
|
158
|
+
logger.insert(
|
159
|
+
:time => Time.now.to_i,
|
160
|
+
:channel => message.channel.to_str,
|
161
|
+
:nick => message.from.nick,
|
162
|
+
:type => type,
|
163
|
+
:text => message.text
|
164
|
+
)
|
165
|
+
}
|
166
|
+
subscribe(:QUIT, -10, MessageTypes.index(:QUIT)) { |listener, message, type|
|
167
|
+
next unless logger.logged?(message.channel.to_str)
|
168
|
+
logger.insert(
|
169
|
+
:time => Time.now.to_i,
|
170
|
+
:channel => message.channel.to_str,
|
171
|
+
:nick => message.from.nick,
|
172
|
+
:type => type,
|
173
|
+
:text => message.text
|
174
|
+
)
|
175
|
+
}
|
176
|
+
subscribe(:KICK, -10, MessageTypes.index(:KICK)) { |listener, message, type|
|
177
|
+
next unless logger.logged?(message.channel.to_str)
|
178
|
+
logger.insert(
|
179
|
+
:time => Time.now.to_i,
|
180
|
+
:channel => message.channel.to_str,
|
181
|
+
:nick => message.from.nick,
|
182
|
+
:type => type,
|
183
|
+
:text => message.text
|
184
|
+
)
|
185
|
+
}
|
186
|
+
subscribe(:KILL, -10, MessageTypes.index(:KILL)) { |listener, message, type|
|
187
|
+
next unless logger.logged?(message.channel.to_str)
|
188
|
+
logger.insert(
|
189
|
+
:time => Time.now.to_i,
|
190
|
+
:channel => message.channel.to_str,
|
191
|
+
:nick => message.from.nick,
|
192
|
+
:type => type,
|
193
|
+
:text => message.text
|
194
|
+
)
|
195
|
+
}
|
196
|
+
|
197
|
+
register(logger)
|
198
|
+
end
|