nadoka 0.8.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.
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: