nadoka 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/.gitignore +5 -0
  2. data/ChangeLog.old +1553 -0
  3. data/Gemfile +4 -0
  4. data/README.org +31 -0
  5. data/Rakefile +1 -0
  6. data/bin/nadoka +13 -0
  7. data/lib/rss_check.rb +206 -0
  8. data/lib/tagparts.rb +206 -0
  9. data/nadoka.gemspec +29 -0
  10. data/nadoka.rb +123 -0
  11. data/nadokarc +267 -0
  12. data/ndk/bot.rb +241 -0
  13. data/ndk/client.rb +288 -0
  14. data/ndk/config.rb +571 -0
  15. data/ndk/error.rb +61 -0
  16. data/ndk/logger.rb +311 -0
  17. data/ndk/server.rb +784 -0
  18. data/ndk/server_state.rb +324 -0
  19. data/ndk/version.rb +44 -0
  20. data/plugins/autoawaybot.nb +66 -0
  21. data/plugins/autodumpbot.nb +227 -0
  22. data/plugins/autoop.nb +56 -0
  23. data/plugins/backlogbot.nb +88 -0
  24. data/plugins/checkbot.nb +64 -0
  25. data/plugins/cronbot.nb +20 -0
  26. data/plugins/dictbot.nb +53 -0
  27. data/plugins/drbcl.rb +39 -0
  28. data/plugins/drbot.nb +93 -0
  29. data/plugins/evalbot.nb +49 -0
  30. data/plugins/gonzuibot.nb +41 -0
  31. data/plugins/googlebot.nb +345 -0
  32. data/plugins/identifynickserv.nb +43 -0
  33. data/plugins/mailcheckbot.nb +0 -0
  34. data/plugins/marldiabot.nb +99 -0
  35. data/plugins/messagebot.nb +96 -0
  36. data/plugins/modemanager.nb +150 -0
  37. data/plugins/opensearchbot.nb +156 -0
  38. data/plugins/opshop.nb +23 -0
  39. data/plugins/pastebot.nb +46 -0
  40. data/plugins/roulettebot.nb +33 -0
  41. data/plugins/rss_checkbot.nb +121 -0
  42. data/plugins/samplebot.nb +24 -0
  43. data/plugins/sendpingbot.nb +17 -0
  44. data/plugins/shellbot.nb +59 -0
  45. data/plugins/sixamobot.nb +77 -0
  46. data/plugins/tenkibot.nb +111 -0
  47. data/plugins/timestampbot.nb +62 -0
  48. data/plugins/titlebot.nb +226 -0
  49. data/plugins/translatebot.nb +301 -0
  50. data/plugins/twitterbot.nb +138 -0
  51. data/plugins/weba.nb +209 -0
  52. data/plugins/xibot.nb +113 -0
  53. data/rice/irc.rb +780 -0
  54. metadata +102 -0
@@ -0,0 +1,324 @@
1
+ #
2
+ # Copyright (c) 2004-2005 SASADA Koichi <ko1 at atdot.net>
3
+ #
4
+ # This program is free software with ABSOLUTELY NO WARRANTY.
5
+ # You can re-distribute and/or modify this program under
6
+ # the same terms of the Ruby's license.
7
+ #
8
+ #
9
+ # $Id$
10
+ # Create : K.S. 04/04/20 10:42:27
11
+ #
12
+
13
+ module Nadoka
14
+ class NDK_State
15
+ class ChannelState
16
+ def initialize name
17
+ @name = name
18
+ @topic = nil
19
+ @member= {}
20
+
21
+ # member data
22
+ # { "nick" => "mode", ... }
23
+ end
24
+
25
+ attr_accessor :topic
26
+ attr_reader :member, :name
27
+
28
+ # get members nick array
29
+ def members
30
+ @member.keys
31
+ end
32
+
33
+ # get user's mode
34
+ def mode nick
35
+ @member[nick]
36
+ end
37
+
38
+ def names
39
+ @member.map{|nick, mode|
40
+ prefix = if /o/ =~ mode
41
+ '@'
42
+ elsif /v/ =~ mode
43
+ '+'
44
+ else
45
+ ''
46
+ end
47
+ prefix + nick
48
+ }
49
+ end
50
+
51
+ def state
52
+ '='
53
+ end
54
+
55
+ def clear_members
56
+ @member = {}
57
+ end
58
+
59
+ #####################################
60
+
61
+ def on_join nick, mode=''
62
+ @member[nick] = mode
63
+ end
64
+
65
+ def on_part nick
66
+ @member.delete nick
67
+ end
68
+
69
+ def on_nick nick, newnick
70
+ if @member.has_key? nick
71
+ @member[newnick] = @member[nick]
72
+ @member.delete nick
73
+ end
74
+ end
75
+
76
+ def on_kick nick
77
+ if @member.has_key? nick
78
+ @member.delete nick
79
+ end
80
+ end
81
+
82
+ MODE_WITH_NICK_ARG = 'ov'
83
+ MODE_WITH_ARGS = 'klbeI'
84
+ MODE_WITHOUT_ARGS = 'aimnqpsrt'
85
+
86
+ def on_mode nick, args
87
+ while mode = args.shift
88
+ modes = mode.split(//)
89
+ flag = modes.shift
90
+ modes.each{|m|
91
+ if MODE_WITH_NICK_ARG.include? m
92
+ chg_mode args.shift, flag, m
93
+ elsif MODE_WITH_ARGS.include? m
94
+ args.shift
95
+ elsif MODE_WITHOUT_ARGS.include? m
96
+ # ignore
97
+ end
98
+ }
99
+ end
100
+ end
101
+
102
+ def chg_mode nick, flag, mode
103
+ if @member.has_key? nick
104
+ if flag == '+'
105
+ @member[nick] += mode
106
+ elsif flag == '-'
107
+ @member[nick].gsub!(mode, '')
108
+ end
109
+ end
110
+ end
111
+
112
+ def to_s
113
+ str = ''
114
+ @member.each{|k, v|
115
+ str << "#{k}: #{v}, "
116
+ }
117
+ str
118
+ end
119
+ end
120
+
121
+ def initialize manager
122
+ @manager = manager
123
+ @config = nil
124
+ @logger = nil
125
+
126
+ @current_nick = nil
127
+ @original_nick = nil
128
+ @try_nick = nil
129
+
130
+ @current_channels = {}
131
+ end
132
+ attr_reader :current_channels
133
+ attr_reader :current_nick
134
+ attr_accessor :original_nick
135
+ attr_writer :logger, :config
136
+
137
+ def nick=(n)
138
+ @try_nick = nil
139
+ @current_nick = n
140
+ end
141
+
142
+ def nick
143
+ @current_nick
144
+ end
145
+
146
+ def nick_succ fail_nick
147
+ if @try_nick
148
+ if @try_nick.length == fail_nick
149
+ @try_nick.succ!
150
+ else
151
+ @try_nick = fail_nick[0..-2] + '0'
152
+ end
153
+ else
154
+ @try_nick = fail_nick + '0'
155
+ end
156
+ end
157
+
158
+ def channels
159
+ @current_channels.keys
160
+ end
161
+
162
+ def channel_raw_names
163
+ @current_channels.map{|k, cs| cs.name}
164
+ end
165
+
166
+ # need canonicalized channel name
167
+ def channel_users ch
168
+ if @current_channels.has_key? ch
169
+ @current_channels[ch].members
170
+ else
171
+ []
172
+ end
173
+ end
174
+
175
+ # need canonicalized channel name
176
+ def channel_user_mode ch, user
177
+ if channel_users(ch).include?(user)
178
+ @current_channels[ch].mode(user)
179
+ else
180
+ ''
181
+ end
182
+ end
183
+
184
+ def canonical_channel_name ch
185
+ @config.canonical_channel_name ch
186
+ end
187
+
188
+ def clear_channels_member
189
+ @current_channels.each{|ch, cs|
190
+ cs.clear_members
191
+ }
192
+ end
193
+
194
+ #
195
+ def on_join user, rch
196
+ ch = canonical_channel_name(rch)
197
+ if user == nick
198
+ chs = @current_channels[ch] = ChannelState.new(rch)
199
+ else
200
+ if @current_channels.has_key? ch
201
+ @current_channels[ch].on_join(user)
202
+ end
203
+ end
204
+ end
205
+
206
+ def on_part user, rch
207
+ ch = canonical_channel_name(rch)
208
+ if user == nick
209
+ @current_channels.delete ch
210
+ else
211
+ if @current_channels.has_key? ch
212
+ @current_channels[ch].on_part user
213
+ end
214
+ end
215
+ end
216
+
217
+ def on_nick user, newnick, msg
218
+ if user == nick
219
+ @current_nick = newnick
220
+ @try_nick = nil
221
+ end
222
+ # logging
223
+ @current_channels.each{|ch, chs|
224
+ if chs.on_nick user, newnick
225
+ @config.logger.logging_nick ch, chs.name, user, newnick, msg
226
+ end
227
+ }
228
+ end
229
+
230
+ def on_quit user, qmsg, msg
231
+ if user == nick
232
+ @current_channels = {} # clear
233
+ else
234
+ # logging
235
+ @current_channels.each{|ch, chs|
236
+ if chs.on_part(user)
237
+ @config.logger.logging_quit ch, chs.name, user, qmsg, msg
238
+ @manager.invoke_event :invoke_bot, :quit_from_channel, chs.name, user, qmsg
239
+ end
240
+ }
241
+ end
242
+ end
243
+
244
+ def on_mode user, rch, args
245
+ ch = canonical_channel_name(rch)
246
+ if @current_channels.has_key? ch
247
+ @current_channels[ch].on_mode user, args
248
+ end
249
+ end
250
+
251
+ def on_kick kicker, rch, user, comment
252
+ ch = canonical_channel_name(rch)
253
+ if user == nick
254
+ @current_channels.delete ch
255
+ else
256
+ if @current_channels.has_key? ch
257
+ @current_channels[ch].on_kick user
258
+ end
259
+ end
260
+ end
261
+
262
+ def on_topic user, rch, topic
263
+ ch = canonical_channel_name(rch)
264
+
265
+ if @current_channels.has_key? ch
266
+ @current_channels[ch].topic = topic
267
+ end
268
+ end
269
+
270
+ def on_332 rch, topic
271
+ ch = canonical_channel_name(rch)
272
+
273
+ if @current_channels.has_key? ch
274
+ @current_channels[ch].topic = topic
275
+ end
276
+ end
277
+
278
+ # RPL_NAMREPLY
279
+ # ex) :lalune 353 test_ndk = #nadoka :test_ndk ko1_nmdk
280
+ #
281
+ def on_353 rch, users
282
+ ch = canonical_channel_name(rch)
283
+
284
+ if @current_channels.has_key? ch
285
+ chs = @current_channels[ch]
286
+ users.split(/ /).each{|e|
287
+ /^([\@\+])?(.+)/ =~ e
288
+ case $1
289
+ when '@'
290
+ mode = 'o'
291
+ when '+'
292
+ mode = 'v'
293
+ else
294
+ mode = ''
295
+ end
296
+ chs.on_join $2, mode
297
+ }
298
+
299
+ # change initial mode
300
+ if @config.channel_info[ch] &&
301
+ (im = @config.channel_info[ch][:initial_mode]) &&
302
+ chs.members.size == 1
303
+ @manager.send_to_server Cmd.mode(rch, im)
304
+ end
305
+ end
306
+ end
307
+
308
+ def safe_channel? ch
309
+ ch[0] == ?!
310
+ end
311
+
312
+ # ERR_NOSUCHCHANNEL
313
+ # ex) :NadokaProgram 403 simm !hoge :No such channel
314
+ def on_403 ch
315
+ if safe_channel?(ch) && ch[1] != ?!
316
+ if @config.channel_info[ch] && @config.channel_info[ch][:auto_create]
317
+ @manager.join_to_channel( "!" + ch)
318
+ end
319
+ end
320
+ end
321
+
322
+ end
323
+ end
324
+
@@ -0,0 +1,44 @@
1
+ #
2
+ # Copyright (c) 2004-2005 SASADA Koichi <ko1 at atdot.net>
3
+ #
4
+ # This program is free software with ABSOLUTELY NO WARRANTY.
5
+ # You can re-distribute and/or modify this program under
6
+ # the same terms of the Ruby's license.
7
+ #
8
+ #
9
+ # $Id$
10
+ # Create : K.S. 04/04/27 16:35:40
11
+ #
12
+
13
+ module Nadoka
14
+ VERSION = '0.8.0'
15
+ NDK_Version = VERSION.dup
16
+ NDK_Created = Time.now
17
+
18
+ if File.directory?(File.expand_path('../../.git', __FILE__))
19
+ NDK_Version.concat("+git")
20
+ end
21
+ if /trunk/ =~ '$HeadURL$'
22
+ NDK_Version.concat('-trunk')
23
+ rev = '-'
24
+ $LOAD_PATH.each{|path|
25
+ path = path + '/ChangeLog'
26
+ if FileTest.exist?(path)
27
+ if /^\# ChangeLog of Nadoka\(\$Rev: (\d+) \$\)$/ =~ open(path){|f| s = f.gets}
28
+ rev = "rev: #{$1}"
29
+ break
30
+ end
31
+ end
32
+ }
33
+ NDK_Version.concat(" (#{rev})")
34
+ end
35
+
36
+ def self.version
37
+ "Nadoka Ver.#{NDK_Version}" +
38
+ " with Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
39
+ end
40
+ end
41
+
42
+ if __FILE__ == $0
43
+ puts Nadoka::NDK_Version
44
+ end
@@ -0,0 +1,66 @@
1
+ # -*-ruby-*-
2
+ #
3
+ # Copyright (c) 2004-2005 SASADA Koichi <ko1 at atdot.net>
4
+ #
5
+ # This program is free software with ABSOLUTELY NO WARRANTY.
6
+ # You can re-distribute and/or modify this program under
7
+ # the same terms of the Ruby's license.
8
+ #
9
+ #
10
+ # This bot is created by
11
+ # akira yamada <akira at arika.org>
12
+ #
13
+ # $Id$
14
+ #
15
+
16
+ =begin
17
+
18
+ == Abstract
19
+
20
+ Auto away if no action
21
+
22
+ == Configuration
23
+
24
+ BotConfig = [
25
+ {
26
+ :name => :AutoAwayBot,
27
+ :threshold => 15*60, # sec
28
+ :message => 'Away',
29
+ }
30
+ ]
31
+
32
+ =end
33
+
34
+ class AutoAwayBot < Nadoka::NDK_Bot
35
+ def bot_initialize
36
+ @threshold = @bot_config.fetch(:threshold, 15*60).to_i
37
+ @message = @bot_config.fetch(:message, 'Away')
38
+ @lastseen = Time.now
39
+ @in_away = false
40
+ end
41
+
42
+ def on_client_privmsg client, ch, msg
43
+ if @threshold > 0
44
+ @lastseen = Time.now
45
+ end
46
+ if @in_away
47
+ @manager.send_to_server Nadoka::Cmd.away()
48
+ end
49
+ end
50
+
51
+ def on_timer time
52
+ if @threshold > 0 && Time.now - @lastseen > @threshold && !@in_away
53
+ @manager.send_to_server Nadoka::Cmd.away(@message)
54
+ end
55
+ end
56
+
57
+ def on_rpl_unaway *arg
58
+ @in_away = false
59
+ end
60
+
61
+ def on_rpl_nowaway *arg
62
+ @in_away = true
63
+ end
64
+ end
65
+
66
+
@@ -0,0 +1,227 @@
1
+ # -*-ruby-*-
2
+ #
3
+ # Copyright (c) 2004-2005 SASADA Koichi <ko1 at atdot.net>
4
+ #
5
+ # This program is free software with ABSOLUTELY NO WARRANTY.
6
+ # You can re-distribute and/or modify this program under
7
+ # the same terms of the Ruby's license.
8
+ #
9
+ #
10
+ # This bot is created by
11
+ # akira yamada <akira at arika.org>
12
+ #
13
+ # $Id$
14
+ #
15
+
16
+ =begin
17
+
18
+ == Abstract
19
+
20
+ Auto save configuration
21
+
22
+ == Configuration
23
+
24
+ add these program to nadokarc(or your configuration file)
25
+
26
+ begin
27
+ dump_file = File.join(Log_dir, Setting_name + '-channel_info.dump')
28
+ channel_info = {}
29
+ begin
30
+ File.open(dump_file, 'r') {|i| channel_info = Marshal.load(i)}
31
+ rescue TypeError
32
+ File.open(dump_file, 'r') {|i| channel_info = YAML.load(i.read)}
33
+ end
34
+
35
+ Channel_info = channel_info
36
+ rescue
37
+ Channel_info = {
38
+ }
39
+ end
40
+
41
+ more detail, see [nadoka:162]
42
+
43
+ =end
44
+
45
+
46
+ class AutoDumpBot < Nadoka::NDK_Bot
47
+ def bot_initialize
48
+ @auto_dump = @bot_config.fetch(:auto_dump, true)
49
+ @default_dump_style = @bot_config.fetch(:dump_style, 'yaml')
50
+ @default_timing = @bot_config.fetch(:dump_timing, :startup)
51
+
52
+ @cinfo = {}
53
+ @manager.state.channels.each do |ch|
54
+ @manager.send_to_server Nadoka::Cmd.mode(ch)
55
+ end
56
+ end
57
+
58
+ def canonical_channel_name ch
59
+ @manager.state.canonical_channel_name ch
60
+ end
61
+
62
+ def on_join prefix, ch
63
+ if @manager.state.current_nick == prefix.nick
64
+ dch = canonical_channel_name(ch)
65
+ @cinfo[dch] ||= {}
66
+ @cinfo[dch][:name] = ch
67
+ @cinfo[dch][:mode] ||= []
68
+
69
+ @manager.send_to_server Nadoka::Cmd.mode(ch)
70
+ end
71
+ end
72
+
73
+ def on_part prefix, ch, msg=''
74
+ if @manager.client_count > 0 && @manager.state.current_nick == prefix.nick
75
+ @cinfo.delete(canonical_channel_name(ch))
76
+ end
77
+ end
78
+
79
+ def on_client_logout count, client
80
+ if count == 1 && @auto_dump
81
+ dump_cinfo
82
+ end
83
+ end
84
+
85
+ MODE_WITH_NICK_ARG = 'ov'
86
+ MODE_WITH_ARGS = 'klbeI'
87
+ MODE_WITHOUT_ARGS = 'aimnqpsrt'
88
+
89
+ def on_mode prefix, nick, ch, *args
90
+ dch = canonical_channel_name(ch)
91
+ if @manager.state.current_channels.has_key? dch
92
+ @cinfo[dch] ||= {}
93
+ @cinfo[dch][:name] = ch
94
+ @cinfo[dch][:mode] ||= []
95
+
96
+ while mode = args.shift
97
+ modes = mode.split(//)
98
+ flag = modes.shift
99
+ modes.each{|m|
100
+ if MODE_WITH_NICK_ARG.include? m
101
+ #chg_cinfo dch, flag, m, args.shift
102
+ elsif MODE_WITH_ARGS.include? m
103
+ chg_cinfo dch, flag, m, args.shift
104
+ elsif MODE_WITHOUT_ARGS.include? m
105
+ chg_cinfo dch, flag, m, nil
106
+ end
107
+ }
108
+ end
109
+ end
110
+ end
111
+
112
+ def on_rpl_channelmodeis prefix, nick, ch, *arg
113
+ on_mode(prefix, nick, ch, *arg)
114
+ end
115
+
116
+ def on_nadoka_command client, command, *params
117
+ if command == 'dump'
118
+ dump_cinfo(params.shift)
119
+ raise ::Nadoka::NDK_BotSendCancel
120
+ end
121
+ end
122
+
123
+ def chg_cinfo ch, flag, mode, arg
124
+ @cinfo[ch][:mode] ||= []
125
+ @cinfo[ch][:mode].delete_if do |m|
126
+ m[0, 1] == mode
127
+ end
128
+ if flag == '+'
129
+ if arg
130
+ @cinfo[ch][:mode] << mode + ' ' + arg
131
+ else
132
+ @cinfo[ch][:mode] << mode
133
+ end
134
+ end
135
+ end
136
+
137
+ def dump_cinfo(style = nil)
138
+ style = @default_dump_style unless style
139
+
140
+ channel_info = {}
141
+ @cinfo.keys.each do |ch|
142
+ name = @cinfo[ch][:name]
143
+ if @state.current_channels.include?(ch)
144
+ name = @state.current_channels[ch].name
145
+ end
146
+ channel_info[name] = cinfo = {}
147
+ config = @manager.instance_eval {@config}
148
+
149
+ if config.default_channels.detect {|tch| canonical_channel_name(tch) == ch}
150
+ cinfo[:timing] = :startup
151
+ elsif config.login_channels.detect {|tch| canonical_channel_name(tch) == ch}
152
+ cinfo[:timing] = :login
153
+ else
154
+ cinfo[:timing] = @default_timing
155
+ end
156
+ if @cinfo[ch][:mode].include?('i')
157
+ cinfo[:timing] = :startup
158
+ elsif !cinfo.include?(:timing)
159
+ cinfo[:timing] = :login
160
+ end
161
+
162
+ @cinfo[ch][:mode].each do |m|
163
+ if m[0] == ?k
164
+ cinfo[:key] = m[2 .. -1]
165
+ end
166
+ end
167
+
168
+ m1, m2 = @cinfo[ch][:mode].partition {|m| m.size == 1}
169
+ imode = nil
170
+ unless m1.empty?
171
+ imode ||= '+'
172
+ imode << m1.join('')
173
+ end
174
+ unless m2.empty?
175
+ imode ||= '+'
176
+ imode << m2.join(' +')
177
+ end
178
+ cinfo[:initial_mode] = imode
179
+ end
180
+
181
+ begin
182
+ dump_file = File.join(@config.log_dir,
183
+ @config.setting_name + '-channel_info.dump')
184
+ File.open(dump_file, 'wb') do |f|
185
+ f.chmod(0600)
186
+ dump_channel_info(channel_info, style, f)
187
+ end
188
+ @logger.slog "current channel information was dumped (#{style})"
189
+ rescue Exception => e
190
+ @logger.slog "current channel information could not be dumped"
191
+ @logger.slog e.message
192
+ end
193
+ end
194
+
195
+ def dump_channel_info(channel_info, style, port)
196
+ if style == 'marshal'
197
+ Marshal.dump(channel_info, port)
198
+
199
+ elsif style == 'yaml'
200
+ require 'yaml'
201
+ YAML.dump(channel_info, port)
202
+
203
+ elsif style == 'text'
204
+ port.puts "Channel_info = {"
205
+ channel_info.each do |ch, info|
206
+ port.puts " #{ch.dump} => {"
207
+ info.each do |tag, value|
208
+ if tag.kind_of?(Symbol)
209
+ if value.kind_of?(Symbol)
210
+ port.puts " :#{tag.to_s} => :#{value.to_s},"
211
+ else
212
+ port.puts " :#{tag.to_s} => #{value.to_s.dump},"
213
+ end
214
+ end
215
+ end
216
+ port.puts " },"
217
+ end
218
+ port.puts "}"
219
+
220
+ else
221
+ raise RuntimeError, "unsupported dump style: #{style.dump}"
222
+ end
223
+ end
224
+
225
+ end
226
+
227
+ # vim:filetype=ruby: