butler 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. data/CHANGELOG +4 -0
  2. data/GPL.txt +340 -0
  3. data/LICENSE.txt +52 -0
  4. data/README +37 -0
  5. data/Rakefile +334 -0
  6. data/bin/botcontrol +230 -0
  7. data/data/butler/config_template.yaml +4 -0
  8. data/data/butler/dialogs/backup.rb +19 -0
  9. data/data/butler/dialogs/botcontrol.rb +4 -0
  10. data/data/butler/dialogs/config.rb +1 -0
  11. data/data/butler/dialogs/create.rb +53 -0
  12. data/data/butler/dialogs/delete.rb +3 -0
  13. data/data/butler/dialogs/en/backup.yaml +6 -0
  14. data/data/butler/dialogs/en/botcontrol.yaml +5 -0
  15. data/data/butler/dialogs/en/create.yaml +11 -0
  16. data/data/butler/dialogs/en/delete.yaml +2 -0
  17. data/data/butler/dialogs/en/help.yaml +17 -0
  18. data/data/butler/dialogs/en/info.yaml +13 -0
  19. data/data/butler/dialogs/en/list.yaml +4 -0
  20. data/data/butler/dialogs/en/notyetimplemented.yaml +2 -0
  21. data/data/butler/dialogs/en/rename.yaml +3 -0
  22. data/data/butler/dialogs/en/start.yaml +3 -0
  23. data/data/butler/dialogs/en/sync_plugins.yaml +3 -0
  24. data/data/butler/dialogs/en/uninstall.yaml +5 -0
  25. data/data/butler/dialogs/en/unknown_command.yaml +2 -0
  26. data/data/butler/dialogs/help.rb +11 -0
  27. data/data/butler/dialogs/info.rb +27 -0
  28. data/data/butler/dialogs/interactive.rb +1 -0
  29. data/data/butler/dialogs/list.rb +10 -0
  30. data/data/butler/dialogs/notyetimplemented.rb +1 -0
  31. data/data/butler/dialogs/rename.rb +4 -0
  32. data/data/butler/dialogs/selectbot.rb +2 -0
  33. data/data/butler/dialogs/start.rb +5 -0
  34. data/data/butler/dialogs/sync_plugins.rb +30 -0
  35. data/data/butler/dialogs/uninstall.rb +17 -0
  36. data/data/butler/dialogs/unknown_command.rb +1 -0
  37. data/data/butler/plugins/core/logout.rb +41 -0
  38. data/data/butler/plugins/core/plugins.rb +134 -0
  39. data/data/butler/plugins/core/privilege.rb +103 -0
  40. data/data/butler/plugins/core/user.rb +166 -0
  41. data/data/butler/plugins/dev/eval.rb +64 -0
  42. data/data/butler/plugins/dev/nometa.rb +14 -0
  43. data/data/butler/plugins/dev/onhandlers.rb +93 -0
  44. data/data/butler/plugins/dev/raw.rb +36 -0
  45. data/data/butler/plugins/dev/rawlog.rb +77 -0
  46. data/data/butler/plugins/games/eightball.rb +54 -0
  47. data/data/butler/plugins/games/mastermind.rb +174 -0
  48. data/data/butler/plugins/irc/action.rb +36 -0
  49. data/data/butler/plugins/irc/join.rb +38 -0
  50. data/data/butler/plugins/irc/notice.rb +36 -0
  51. data/data/butler/plugins/irc/part.rb +38 -0
  52. data/data/butler/plugins/irc/privmsg.rb +36 -0
  53. data/data/butler/plugins/irc/quit.rb +36 -0
  54. data/data/butler/plugins/operator/deop.rb +41 -0
  55. data/data/butler/plugins/operator/devoice.rb +41 -0
  56. data/data/butler/plugins/operator/limit.rb +47 -0
  57. data/data/butler/plugins/operator/op.rb +41 -0
  58. data/data/butler/plugins/operator/voice.rb +41 -0
  59. data/data/butler/plugins/public/help.rb +69 -0
  60. data/data/butler/plugins/public/login.rb +72 -0
  61. data/data/butler/plugins/public/usage.rb +49 -0
  62. data/data/butler/plugins/service/clones.rb +56 -0
  63. data/data/butler/plugins/service/define.rb +47 -0
  64. data/data/butler/plugins/service/log.rb +183 -0
  65. data/data/butler/plugins/service/svn.rb +91 -0
  66. data/data/butler/plugins/util/cycle.rb +98 -0
  67. data/data/butler/plugins/util/load.rb +41 -0
  68. data/data/butler/plugins/util/pong.rb +29 -0
  69. data/data/butler/strings/random/acknowledge.en.yaml +5 -0
  70. data/data/butler/strings/random/gratitude.en.yaml +3 -0
  71. data/data/butler/strings/random/hello.en.yaml +4 -0
  72. data/data/butler/strings/random/ignorance.en.yaml +7 -0
  73. data/data/butler/strings/random/ignorance_about.en.yaml +3 -0
  74. data/data/butler/strings/random/insult.en.yaml +3 -0
  75. data/data/butler/strings/random/rejection.en.yaml +12 -0
  76. data/data/man/botcontrol.1 +17 -0
  77. data/lib/access.rb +187 -0
  78. data/lib/access/admin.rb +16 -0
  79. data/lib/access/privilege.rb +122 -0
  80. data/lib/access/role.rb +102 -0
  81. data/lib/access/savable.rb +18 -0
  82. data/lib/access/user.rb +180 -0
  83. data/lib/access/yamlbase.rb +126 -0
  84. data/lib/butler.rb +188 -0
  85. data/lib/butler/bot.rb +247 -0
  86. data/lib/butler/control.rb +93 -0
  87. data/lib/butler/dialog.rb +64 -0
  88. data/lib/butler/initialvalues.rb +40 -0
  89. data/lib/butler/irc/channel.rb +135 -0
  90. data/lib/butler/irc/channels.rb +96 -0
  91. data/lib/butler/irc/client.rb +351 -0
  92. data/lib/butler/irc/hostmask.rb +53 -0
  93. data/lib/butler/irc/message.rb +184 -0
  94. data/lib/butler/irc/parser.rb +125 -0
  95. data/lib/butler/irc/parser/commands.rb +83 -0
  96. data/lib/butler/irc/parser/generic.rb +343 -0
  97. data/lib/butler/irc/socket.rb +378 -0
  98. data/lib/butler/irc/string.rb +186 -0
  99. data/lib/butler/irc/topic.rb +15 -0
  100. data/lib/butler/irc/user.rb +265 -0
  101. data/lib/butler/irc/users.rb +112 -0
  102. data/lib/butler/plugin.rb +249 -0
  103. data/lib/butler/plugin/configproxy.rb +35 -0
  104. data/lib/butler/plugin/mapper.rb +85 -0
  105. data/lib/butler/plugin/matcher.rb +55 -0
  106. data/lib/butler/plugin/onhandlers.rb +70 -0
  107. data/lib/butler/plugin/trigger.rb +58 -0
  108. data/lib/butler/plugins.rb +147 -0
  109. data/lib/butler/version.rb +17 -0
  110. data/lib/cloptions.rb +217 -0
  111. data/lib/cloptions/adapters.rb +24 -0
  112. data/lib/cloptions/switch.rb +132 -0
  113. data/lib/configuration.rb +223 -0
  114. data/lib/dialogline.rb +296 -0
  115. data/lib/dialogline/localizations.rb +24 -0
  116. data/lib/durations.rb +57 -0
  117. data/lib/event.rb +295 -0
  118. data/lib/event/at.rb +64 -0
  119. data/lib/event/every.rb +56 -0
  120. data/lib/event/timed.rb +112 -0
  121. data/lib/installer.rb +75 -0
  122. data/lib/iterator.rb +34 -0
  123. data/lib/log.rb +68 -0
  124. data/lib/log/comfort.rb +85 -0
  125. data/lib/log/converter.rb +23 -0
  126. data/lib/log/entry.rb +152 -0
  127. data/lib/log/fakeio.rb +55 -0
  128. data/lib/log/file.rb +54 -0
  129. data/lib/log/filereader.rb +81 -0
  130. data/lib/log/forward.rb +49 -0
  131. data/lib/log/methods.rb +39 -0
  132. data/lib/log/nolog.rb +18 -0
  133. data/lib/log/splitter.rb +26 -0
  134. data/lib/ostructfixed.rb +26 -0
  135. data/lib/ruby/array/columnize.rb +38 -0
  136. data/lib/ruby/dir/mktree.rb +28 -0
  137. data/lib/ruby/enumerable/join.rb +13 -0
  138. data/lib/ruby/exception/detailed.rb +24 -0
  139. data/lib/ruby/file/append.rb +11 -0
  140. data/lib/ruby/file/write.rb +11 -0
  141. data/lib/ruby/hash/zip.rb +15 -0
  142. data/lib/ruby/kernel/bench.rb +15 -0
  143. data/lib/ruby/kernel/daemonize.rb +42 -0
  144. data/lib/ruby/kernel/non_verbose.rb +17 -0
  145. data/lib/ruby/kernel/safe_fork.rb +18 -0
  146. data/lib/ruby/range/stepped.rb +11 -0
  147. data/lib/ruby/string/arguments.rb +72 -0
  148. data/lib/ruby/string/chunks.rb +15 -0
  149. data/lib/ruby/string/post_arguments.rb +44 -0
  150. data/lib/ruby/string/unescaped.rb +17 -0
  151. data/lib/scheduler.rb +164 -0
  152. data/lib/scriptfile.rb +101 -0
  153. data/lib/templater.rb +86 -0
  154. data/test/cloptions.rb +134 -0
  155. data/test/cv.rb +28 -0
  156. data/test/irc/client.rb +85 -0
  157. data/test/irc/client_login.txt +53 -0
  158. data/test/irc/client_subscribe.txt +8 -0
  159. data/test/irc/message.rb +30 -0
  160. data/test/irc/messages.txt +64 -0
  161. data/test/irc/parser.rb +13 -0
  162. data/test/irc/profile_parser.rb +12 -0
  163. data/test/irc/users.rb +28 -0
  164. metadata +256 -0
@@ -0,0 +1,72 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ #extend OnHandlers
10
+ trigger "login"
11
+
12
+ # FIXME, requires working OnHandlers
13
+ # FIXME, requires Butler::IRC::Message#answer to work with :JOIN
14
+ def on_join
15
+ if @message.from.user[0,1] == "i" then
16
+ # check nick->user mappings
17
+ if user = plugin.config["nickmap"][@message.from.nick] then
18
+ @message.from.
19
+ answer(:success)
20
+ end
21
+ end
22
+ end
23
+
24
+ # FIXME, log events
25
+ # FIXME, accept plain login, using IDENT_CAPAB
26
+ def on_trigger
27
+ return answer(usage) unless [3].include?(@message.arguments.length)
28
+
29
+ if access = @butler.access.login(*@message.arguments[1,2]) then
30
+ @message.from.access = access
31
+ answer(:success)
32
+ if @message.public? then
33
+ @message.from.access.credentials = nil
34
+ answer(:public_success)
35
+ end
36
+ else
37
+ answer(:failure)
38
+ answer(:public_failure) if @message.public?
39
+ end
40
+ end
41
+
42
+ __END__
43
+ ---
44
+ :revision:
45
+ :plugin: 1
46
+ :summary:
47
+ en: Authenticate to the bot
48
+ :about:
49
+ :mail: "apeiros@gmx.net"
50
+ :version: "1.0.0"
51
+ :author: "Stefan Rusterholz"
52
+ :strings:
53
+ :success:
54
+ en: You are now authenticated.
55
+ :failure:
56
+ en: Could not authenticate you.
57
+ :public_success:
58
+ en: |
59
+ You authenticated yourself in public. Your password has been deleted.
60
+ Please set a new one immediatly using 'access password ![c(blue)]password![o]'
61
+ :public_failure:
62
+ en: |
63
+ You tried to authenticate yourself in public. Be aware that a public login will result in a reset password.
64
+ If this was similar to your real password, then please login and set a new one immediatly using 'access password ![(blue)]password![r]'
65
+ :usage:
66
+ en: |
67
+ ![b]login![o] ![c(blue)]username password![o]
68
+ :help:
69
+ en:
70
+ "": |
71
+ Using 'login ![c(blue)]username password![o]' you can Authenticate to the bot.
72
+ Be aware that the bot will delete your password if you authenticate in public as a protection measure.
@@ -0,0 +1,49 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ trigger "usage"
10
+
11
+ def on_trigger
12
+ if @message.arguments.length != 2 then
13
+ answer(usage)
14
+ elsif plugin = @butler.plugins.identify(@message.arguments[1]) then
15
+ answer(@butler.plugins[plugin].plugin_usage(@message))
16
+ else
17
+ answer(:no_plugin, :name => @message.arguments[1])
18
+ end
19
+ end
20
+
21
+ __END__
22
+ ---
23
+ :revision:
24
+ :plugin: 1
25
+ :summary:
26
+ en: Give information about elementary usage of a plugin
27
+ :about:
28
+ :mail: "apeiros@gmx.net"
29
+ :version: "1.0.0"
30
+ :author: "Stefan Rusterholz"
31
+ :strings:
32
+ :no_plugin:
33
+ en: |
34
+ No plugin named <%= name %> loaded.
35
+ :usage:
36
+ en: |
37
+ ![b]usage![o] <![c(green)]plugin![o]>
38
+ :help:
39
+ en:
40
+ "": |
41
+ Usage provides you with elementary information on how to use a plugin-command.
42
+ If you need more information, use the help command.
43
+ "keyword": |
44
+ Arguments in green and embraced by <angle brackets> are keyword arguments.
45
+ Keyword arguments require a specific format.
46
+ "keyword nick": |
47
+ A <nick> argument must be a valid (not necessary online) IRC nickname.
48
+ "keyword channel": |
49
+ A <channel> argument must be a valid (not necessary existing) IRC channelname.
@@ -0,0 +1,56 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ trigger "clones"
10
+
11
+ def on_trigger
12
+ strong = @message.arguments.last != "weak"
13
+ if (@message.arguments.length == 2 && @message.arguments[1].valid_channelname?) then
14
+ all_clones = @butler.channels[message.arguments[1]].clones(strong)
15
+ answer(:clones_in_channel, :channel => message.arguments[1], :count => all_clones.length)
16
+ answer_clones(all_clones)
17
+ else
18
+ all_clones = @butler.users.clones(strong)
19
+ answer(:all_clones, :count => all_clones.length)
20
+ answer_clones(all_clones)
21
+ end
22
+ end
23
+
24
+ def answer_clones(all_clones)
25
+ all_clones.each { |common, clones|
26
+ answer(:clonelist, :common => common, :clones => clones)
27
+ }
28
+ end
29
+
30
+ __END__
31
+ ---
32
+ :revision:
33
+ :plugin: 1
34
+ :summary:
35
+ en: Let butler send a notice to a user or channel
36
+ :about:
37
+ :mail: "apeiros@gmx.net"
38
+ :version: "1.0.0"
39
+ :author: "Stefan Rusterholz"
40
+ :strings:
41
+ :clones_in_channel:
42
+ en: |
43
+ Clones in channel <%= channel %> (<%= count %>):
44
+ :all_clones:
45
+ en: |
46
+ All clones (<%= count %>):
47
+ :clonelist:
48
+ en: |
49
+ <%= common %>: <%= clones.map { |u| "#{u.nick}" }.join(", ") %>
50
+ :usage:
51
+ en: |
52
+ ![b]notice![o] (![c(green)]nick![o] | ![c(green)]channel![o])
53
+ :help:
54
+ en:
55
+ "": |
56
+ Let butler send a notice to a user or channel.
@@ -0,0 +1,47 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'open-uri'
10
+ require 'hpricot'
11
+ require 'cgi'
12
+
13
+ Query = "http://www.google.com/search?client=butler&rls=%s&q=define:+%s&ie=UTF-8&oe=UTF-8"
14
+
15
+ trigger "define"
16
+
17
+ def on_trigger
18
+ word = @message.post_arguments[1]
19
+ doc = Hpricot(open(Query%[@message.language, CGI.escape(word)]))
20
+ see_also = (doc/"//div[@id='res']/font[1]/p/a")[5..-1].map { |e| e.inner_text }
21
+ found = (doc/"//div[@id='res']/ul/font/li").find { |e| (e/"//a").inner_text.include?("wikipedia.org") }
22
+ if found then
23
+ answer(found.inner_text.sub(%r{\w+\.wikipedia\.org/wiki/.*?$}, ''))
24
+ else
25
+ answer(:not_found, :search_string => word)
26
+ end
27
+ end
28
+
29
+ __END__
30
+ ---
31
+ :revision:
32
+ :plugin: 1
33
+ :configuration: 1
34
+ :summary:
35
+ en: "Use googles define: to find the definition of words."
36
+ :about:
37
+ :mail: "apeiros@gmx.net"
38
+ :version: "1.0.0"
39
+ :author: "Stefan Rusterholz"
40
+ :usage:
41
+ en: "![b]define![o] *search_string"
42
+ :help:
43
+ en:
44
+ "": "Use googles define: to find the definition of words."
45
+ :strings:
46
+ :not_found:
47
+ en: No search result for '<%= search_string %>'.
@@ -0,0 +1,183 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'sequel/sqlite'
10
+
11
+ class <<self
12
+ attr_reader :log_db
13
+ attr_reader :log_table
14
+ end
15
+
16
+ @log_db = Sequel.sqlite @butler.path.log+'/log.sqlite'
17
+
18
+ configuration(
19
+ "channels" => []
20
+ )
21
+ @log_db.create_table(:log) {
22
+ primary_key :oid, :integer
23
+ int :time
24
+ str :channel, :size => 255
25
+ str :nick, :size => 48
26
+ int :type
27
+ text :text
28
+ } unless @log_db.table_exists?(:log)
29
+ @log_table = @log_db[:log]
30
+
31
+ MessageTypes = [:PRIVMSG, :NOTICE, :JOIN, :PART, :QUIT, :KICK, :KILL]
32
+
33
+ trigger "log"
34
+
35
+ def on_trigger
36
+ case @message.arguments[1]
37
+ when "list"
38
+ answer(:list, :channels => plugin.config["channels"])
39
+ when "on"
40
+ plugin.config["channels"] |= message.arguments[2..-1]
41
+ answer(:activated, :channels => message.arguments[2..-1])
42
+ when "off"
43
+ plugin.config["channels"] -= message.arguments[2..-1]
44
+ answer(:deactivated, :channels => message.arguments[2..-1])
45
+ when "search"
46
+ text, channel, from = @message.text.match(/search (.*)(?: in channel (#\w+))?(?: from (\w+))?$/).captures
47
+ text = "%#{text}%" if text
48
+ filtered = plugin.log_table #.filter { :type == 0 || :type == 1 }
49
+ filtered = filtered.filter { :nick == from } if from
50
+ filtered = filtered.filter { :nick == channel } if channel
51
+ filtered = filtered.filter { :text =~ text } if text
52
+ count = filtered.count
53
+ if count.zero? then
54
+ answer(:no_match)
55
+ else
56
+ upper = [5,count].min
57
+ answer("Found (1-#{upper} of #{count}):")
58
+ filtered.order(:time.DESC).first(5).each_with_index { |row, index|
59
+ answer(
60
+ "#{index+1}: " \
61
+ "[#{Time.at(row[:time]).strftime('%Y-%m-%d %H:%M')}, " \
62
+ "#{row[:from]} in #{row[:channel]}] " \
63
+ "#{row[:text]}"
64
+ )
65
+ }
66
+ end
67
+ when "dump"
68
+ n = @message.arguments[2].to_i
69
+ n = 5 if n.zero?
70
+ data = plugin.log_table.order(:time.DESC).first(n)
71
+ answer("Dump(#{data.length}):")
72
+ data.each_with_index { |row, index|
73
+ answer(
74
+ "#{index+1}: " \
75
+ "[#{Time.at(row[:time]).strftime('%Y-%m-%d %H:%M')}, " \
76
+ "#{row[:from]} in #{row[:channel]}] " \
77
+ "#{row[:text]}"
78
+ )
79
+ }
80
+ else
81
+ answer(usage)
82
+ end
83
+ end
84
+
85
+ subscribe(:PRIVMSG, -10, nil, MessageTypes.index(:PRIVMSG)) { |listener, message, type|
86
+ next unless @config["channels"].include?(message.channel.to_str)
87
+ @log_table << {
88
+ :time => Time.now.to_i,
89
+ :channel => message.channel.to_str,
90
+ :nick => message.from.nick,
91
+ :type => type,
92
+ :text => message.text
93
+ }
94
+ }
95
+ subscribe(:NOTICE, -10, nil, MessageTypes.index(:NOTICE)) { |listener, message, type|
96
+ next unless @config["channels"].include?(message.channel.to_str)
97
+ @log_table << {
98
+ :time => Time.now.to_i,
99
+ :channel => message.channel.to_str,
100
+ :nick => message.from.nick,
101
+ :type => type,
102
+ :text => message.text
103
+ }
104
+ }
105
+ subscribe(:JOIN, -10, nil, MessageTypes.index(:JOIN)) { |listener, message, type|
106
+ next unless @config["channels"].include?(message.channel.to_str)
107
+ @log_table << {
108
+ :time => Time.now.to_i,
109
+ :channel => message.channel.to_str,
110
+ :nick => message.from.nick,
111
+ :type => type,
112
+ :text => nil
113
+ }
114
+ }
115
+ subscribe(:PART, -10, nil, MessageTypes.index(:PART)) { |listener, message, type|
116
+ next unless @config["channels"].include?(message.channel.to_str)
117
+ @log_table << {
118
+ :time => Time.now.to_i,
119
+ :channel => message.channel.to_str,
120
+ :nick => message.from.nick,
121
+ :type => type,
122
+ :text => message.text
123
+ }
124
+ }
125
+ subscribe(:QUIT, -10, nil, MessageTypes.index(:QUIT)) { |listener, message, type|
126
+ next unless @config["channels"].include?(message.channel.to_str)
127
+ @log_table << {
128
+ :time => Time.now.to_i,
129
+ :channel => message.channel.to_str,
130
+ :nick => message.from.nick,
131
+ :type => type,
132
+ :text => message.text
133
+ }
134
+ }
135
+ subscribe(:KICK, -10, nil, MessageTypes.index(:KICK)) { |listener, message, type|
136
+ next unless @config["channels"].include?(message.channel.to_str)
137
+ @log_table << {
138
+ :time => Time.now.to_i,
139
+ :channel => message.channel.to_str,
140
+ :nick => message.from.nick,
141
+ :type => type,
142
+ :text => message.text
143
+ }
144
+ }
145
+ subscribe(:KILL, -10, nil, MessageTypes.index(:KILL)) { |listener, message, type|
146
+ next unless @config["channels"].include?(message.channel.to_str)
147
+ @log_table << {
148
+ :time => Time.now.to_i,
149
+ :channel => message.channel.to_str,
150
+ :nick => message.from.nick,
151
+ :type => type,
152
+ :text => message.text
153
+ }
154
+ }
155
+
156
+ __END__
157
+ ---
158
+ :revision:
159
+ :plugin: 1
160
+ :configuration: 1
161
+ :summary:
162
+ en: Log channel messages
163
+ :about:
164
+ :mail: "apeiros@gmx.net"
165
+ :version: "1.0.0"
166
+ :author: "Stefan Rusterholz"
167
+ :usage:
168
+ en: "![b]log![o] 'list'"
169
+ :help:
170
+ en:
171
+ "": Log channel messages.
172
+ :strings:
173
+ :no_match:
174
+ en: "No match found."
175
+ :list:
176
+ en: |
177
+ Logging is active for: <%= channels.join(', ') %>.
178
+ :activated:
179
+ en: |
180
+ Logging activated in: <%= channels.join(', ') %>.
181
+ :deactivated:
182
+ en: |
183
+ Logging deactivated in: <%= channels.join(', ') %>.
@@ -0,0 +1,91 @@
1
+ #--
2
+ # Copyright 2007 by Stefan Rusterholz.
3
+ # All rights reserved.
4
+ # See LICENSE.txt for permissions.
5
+ #++
6
+
7
+
8
+
9
+ require 'open-uri'
10
+ require 'hpricot'
11
+ require 'cgi'
12
+
13
+ configuration(
14
+ "frequency" => 900,
15
+ "repositories" => {}
16
+ )
17
+
18
+ def self.current_revision(repo)
19
+ (Hpricot.XML(`svn info --xml #{repo}`)/"info/entry").first.attributes["revision"].to_i
20
+ end
21
+
22
+ def self.changes(repo, from, to=nil)
23
+ range = to ? "#{from}:#{to}" : from.to_s
24
+ doc = Hpricot.XML(`svn log -r #{range} --xml #{repo}`)
25
+ (doc/"log/logentry").map { |entry|
26
+ "#{(entry/'author').inner_text}, " \
27
+ "r#{entry.attributes['revision']}: " \
28
+ "#{(entry/'msg').inner_text.gsub("\n", ' ')}"
29
+ }
30
+ end
31
+
32
+ every(@config["frequency"]) do
33
+ repositories = @config["repositories"]
34
+ repositories.each { |repo, data|
35
+ cr, lr = current_revision(repo), data[:revision]
36
+ if cr > lr then
37
+ data[:revision] = cr
38
+ @config["repositories"] = repositories
39
+ changed = changes(repo, lr+1, cr).join("\n")
40
+ @butler.irc.privmsg(changed, *data[:channels])
41
+ end
42
+ }
43
+ end
44
+
45
+ trigger "svn"
46
+
47
+ def on_trigger
48
+ repos = plugin.config["repositories"]
49
+ case arguments(1)
50
+ when "add"
51
+ repo = @message.arguments[2]
52
+ repos[repo] = {
53
+ :revision => plugin.current_revision(repo),
54
+ :channels => @message.arguments[3..-1]
55
+ }
56
+ plugin.config["repositories"] = repos
57
+ answer(:added, :repository => repo)
58
+
59
+ when "remove"
60
+ repo = @message.arguments[2]
61
+ repos.delete(repo)
62
+ plugin.config["repositories"] = repos
63
+ answer(:removed, :repository => repo)
64
+
65
+ else
66
+ answer(usage)
67
+ end
68
+ #
69
+ end
70
+
71
+ __END__
72
+ ---
73
+ :revision:
74
+ :plugin: 1
75
+ :configuration: 1
76
+ :summary:
77
+ en: "Poll repositories for changes and publicate them."
78
+ :about:
79
+ :mail: "apeiros@gmx.net"
80
+ :version: "1.0.0"
81
+ :author: "Stefan Rusterholz"
82
+ :usage:
83
+ en: "![b]svn![o] 'add' repository channel ..."
84
+ :help:
85
+ en:
86
+ "": "Poll repositories for changes and publicate them."
87
+ :strings:
88
+ :added:
89
+ en: Added repository <%= repository %>.
90
+ :removed:
91
+ en: Added repository <%= repository %>.