ircbot 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ class String
2
+ def digest (max, tail_adjust = '$')
3
+ euc = NKF::nkf('-e', self)
4
+ if euc .size <= max
5
+ return euc
6
+ end
7
+ euc = euc[0..max-1]
8
+ if euc[max-1] == 164
9
+ euc[max-1] = tail_adjust
10
+ end
11
+ euc
12
+ end
13
+ end
14
+
@@ -0,0 +1,61 @@
1
+ # Extension to ruby-irc-lib
2
+
3
+ module IRC
4
+ class AbnormalTerminated < Exception; end
5
+
6
+ class Connection
7
+ def sendNAMES (channel = nil)
8
+ # p [:sendNAMES, Message(CMD_NAMES, nil, nil, channel)]
9
+ send(Message(CMD_NAMES, nil, nil, channel))
10
+ end
11
+ end
12
+
13
+ class Message
14
+ def create_hash! (client)
15
+ unless @hash
16
+ @hash = {}
17
+ @hash[:client] = client
18
+ @hash[:type] = self.command
19
+ @hash[:prefix] = self.prefix
20
+ @hash[:from] = User::parse(self.prefix).nick
21
+ @hash[:str] = self .trailing
22
+ @hash[:string] = @hash[:str]
23
+ @hash[:to] = to = self .params[0]
24
+ @hash[:timestamp] = Time .now
25
+
26
+ unless to
27
+ case self .command
28
+ when CMD_JOIN, CMD_QUIT
29
+ @hash[:to] = to = @hash[:str]
30
+ end
31
+ end
32
+
33
+ if to != nil and to == client .nick
34
+ @hash[:to] = @hash[:from]
35
+ end
36
+ if client .is_a? Client
37
+ @client = client
38
+ end
39
+ end
40
+ end
41
+
42
+ def [] (key) # key must be a symbol
43
+ @hash[key]
44
+ end
45
+
46
+ def []= (key, val)
47
+ @hash[key] = val
48
+ end
49
+
50
+ def reply (string, to = nil)
51
+ self[:reply] = string
52
+ if @client and string
53
+ @client .speak(self, to)
54
+ end
55
+ end
56
+
57
+ def previous
58
+ @client && @client .previous_message(self)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/local/bin/ruby
2
+ #
3
+ # rand-extension.rb
4
+ # Author:
5
+ # Created: Thu Nov 8 17:26:09 2001
6
+
7
+
8
+ # rand ��¿����
9
+ unless $__RAND_OVERRIDE__
10
+ $__RAND_OVERRIDE__ = true
11
+ alias :__rand__ :rand
12
+ def rand (obj)
13
+ case obj
14
+ when Array
15
+ index = __rand__(obj .size)
16
+ obj[index]
17
+ when Range
18
+ rand(obj .to_a)
19
+ else
20
+ __rand__(obj)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ #!/usr/local/bin/ruby
2
+ #
3
+ # writefile.rb
4
+ # Author: maiha@wota.jp
5
+ # Created: 2002/05/10 14:16:13
6
+ # Changed: 2010/01/02 20:42:25
7
+
8
+ =begin
9
+ == usage
10
+ ensure directories of a path exist before open it.
11
+
12
+ === syntacs
13
+ File::open!(path, ...)
14
+
15
+ == sample
16
+ Dir["/tmp/**/*"] # => []
17
+ File .open!("/tmp/foo/ora", "w+")
18
+ Dir["/tmp/**/*"] # => ["/tmp/foo", "/tmp/foo/ora"]
19
+
20
+ == changes
21
+ * 2002/06/11 19:45:32
22
+ change interface: open(...,'w!') => open!(...)
23
+ =end
24
+
25
+ def File.open! (path, *args, &block)
26
+ dirname = File.dirname(path) + '/'
27
+ unless File.directory?(dirname)
28
+ dirs = []
29
+ dirname.scan(/\//) {dirs << $`}
30
+ dirs.shift
31
+ dirs.each do |dir|
32
+ unless directory?(dir)
33
+ Dir.mkdir(dir)
34
+ end
35
+ end
36
+ end
37
+ open(path, *args, &block)
38
+ end
39
+
40
+ if $0 == __FILE__
41
+ path = "/tmp/a/b/c.txt"
42
+ File.open!(path, "w+") {|f| f.puts "[OK] Wrote to #{path}"}
43
+ puts File.read(path){}
44
+ File.unlink(path)
45
+ end
@@ -0,0 +1,50 @@
1
+ module Ircbot
2
+ mattr_accessor :load_paths
3
+ self.load_paths = {}
4
+
5
+ class InvalidFilename < SecurityError; end
6
+ class FileNotFound < SecurityError; end
7
+
8
+ class Recover < RuntimeError
9
+ attr_reader :wait
10
+
11
+ def initialize(wait = 300)
12
+ @wait = wait
13
+ end
14
+ end
15
+
16
+ class << self
17
+ def root
18
+ @root || File.expand_path(Dir.pwd)
19
+ end
20
+
21
+ def root=(value)
22
+ @root = value
23
+ end
24
+
25
+ def push_path(type, path, file_glob = "**/*.rb")
26
+ load_paths[type] = [Pathname(path), file_glob]
27
+ end
28
+
29
+ def dir_for(type)
30
+ load_paths[type][0] or
31
+ raise RuntimeError, "directory not found: #{type}"
32
+ end
33
+
34
+ def glob_for(type)
35
+ load_paths[type][1]
36
+ end
37
+
38
+ def path_for(type, name)
39
+ name = name.to_s
40
+ raise InvalidFilename, name if name =~ %r{\.\.|~|/}
41
+
42
+ path = dir_for(type) + name
43
+ path.readable_real? or
44
+ raise FileNotFound, name
45
+
46
+ return path
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,91 @@
1
+ ## -*- coding: utf-8 -*-
2
+ # ordered_hash.rb
3
+ # Author:
4
+ # Created: Tue Jul 24 18:52:49 2001
5
+
6
+ class Ircbot::OrderedHash < Hash
7
+ def self.[] (*array)
8
+ size = array .size
9
+ if size % 2 == 0
10
+ hash = self .new
11
+ (size / 2) .times do |index|
12
+ key, value = array[index*2,2]
13
+ hash[key] = value
14
+ end
15
+ hash
16
+ else
17
+ super
18
+ end
19
+ end
20
+
21
+ def initialize(*args)
22
+ super
23
+ @store_order = []
24
+ end
25
+
26
+ def []= (key, value)
27
+ unless self .has_key? key
28
+ @store_order << key
29
+ end
30
+ super
31
+ end
32
+
33
+ def keys
34
+ @store_order
35
+ end
36
+
37
+ def each
38
+ keys .each do |key|
39
+ yield(key, self[key])
40
+ end
41
+ end
42
+ alias :each_pair :each
43
+
44
+ def delete (key)
45
+ @store_order .delete(key)
46
+ super
47
+ end
48
+
49
+ def each_value
50
+ keys .each do |key|
51
+ yield(self[key])
52
+ end
53
+ end
54
+
55
+ def collect
56
+ keys .collect do |key|
57
+ yield(key, self[key])
58
+ end
59
+ end
60
+
61
+ def to_a
62
+ keys .collect do |key|
63
+ [key, self[key]]
64
+ end
65
+ end
66
+
67
+ # $B@hF,$KDI2C$9$k!#(B
68
+ def unshift (key, val)
69
+ self[key] = val
70
+ @store_order .delete key
71
+ @store_order .unshift key
72
+ val
73
+ end
74
+
75
+ # $B;XDj$5$l$?%-!<$r;}$DMWAG$NE:;z$rJV$9!#(B(Array#index $BAjEv$N5!G=(B)
76
+ def index_of_key (value)
77
+ keys .index value
78
+ end
79
+
80
+ def position (value)
81
+ keys .each_with_index do |key, i|
82
+ return i if self[key] == value
83
+ end
84
+ return nil
85
+ end
86
+
87
+ def index_of_value (value)
88
+ position(value)
89
+ end
90
+ end
91
+
@@ -0,0 +1,328 @@
1
+ # -*- coding: euc-jp -*-
2
+
3
+ require 'ircbot/config_client'
4
+
5
+ module Ircbot
6
+ class ReplyClient < ConfigClient
7
+ DIGEST_MAX_SIZE = 400
8
+ REGEXP_REDIRECT = ">|��"
9
+
10
+ def myname_regexp_string
11
+ names = @mynames.join('|')
12
+ "(#{ names })"
13
+ end
14
+
15
+ def speak0 (to, obj, save = nil)
16
+ Thread.critical = true
17
+ message =
18
+ case obj
19
+ when String ; obj
20
+ when Array
21
+ array = obj.collect {|item| item.inspect}.join(', ')
22
+ "(#{obj.size})[#{array}]"
23
+ when Regexp ; "/#{obj.source}/"
24
+ else ; obj.inspect
25
+ end
26
+
27
+ message.split(/\n+/).each do |line|
28
+ buffer = line.digest(DIGEST_MAX_SIZE)
29
+ unless buffer.empty?
30
+ # ����������������
31
+ @message_queue.push([buffer, to])
32
+
33
+ # ��å��������֥������Ȥ�������ơ�@messages �˻Ĥ�
34
+ if save
35
+ # :AnnaChan!~anna@219-106-253-19.cust.bit-drive.ne.jp PRIVMSG #bot :test\r\n"
36
+ str = ":#{@nick}!~bot@localhost PRIVMSG #{@channel} :#{buffer}\r\n"
37
+ msg = Message::parse(str)
38
+ msg.create_hash!(self)
39
+ msg[:id] = add_message(msg)
40
+ end
41
+ end
42
+ end
43
+ Thread.critical = false
44
+ end
45
+
46
+ def speak (msg, to = nil, log = nil)
47
+ speak0(to || msg[:to], msg[:reply], log)
48
+ end
49
+
50
+ def newAgent (name)
51
+ script = Ircbot.path_for(:cpi, "#{name}.cpi").read{}
52
+ eval(script, TOPLEVEL_BINDING)
53
+
54
+ rescue SecurityError => e
55
+ err = "#{e.class}: #{e}"
56
+ syslog(err, :error)
57
+ return err
58
+ end
59
+
60
+ # xxxAgent: Agent �� xxx ����
61
+ # ����: String (Agent �μ��̻�)
62
+ # ����: String (������)
63
+
64
+ # ����������Ȥο�����Ͽ
65
+ def registerAgent (name0)
66
+ # ex) name0="daiben(12345)"
67
+ name, arg = name0.split(/\s|\(/, 2) # ex) name="daiben"
68
+ arg = arg.to_s.delete(")").strip # ex) arg="12345"
69
+
70
+ err = nil
71
+ this = "registerAgent"
72
+ agent = @agents[name]
73
+ @agents_opt[name] = arg
74
+
75
+ # p [:debug, :registerAgent, name0, name, arg]
76
+
77
+ agent = newAgent(name)
78
+ case agent
79
+ when NilClass
80
+ err = "Agent plugin script return nil (will not be registerd)."
81
+ when String
82
+ err = agent
83
+ else
84
+ @agents[name] = AgentManager.new(name, agent, self, arg)
85
+ end
86
+
87
+ status = "#{this}(#{name})... #{err || 'OK.'}"
88
+ syslog(status, err ? :error : :normal)
89
+ return status
90
+ end
91
+
92
+ def startAgent (name0)
93
+ # ex) name0="daiben(12345)"
94
+ name, arg = name0.split(/\s|\(/, 2) # ex) name="daiben"
95
+ arg = arg.to_s.delete(")").strip # ex) arg="12345"
96
+
97
+ err = nil
98
+ this = "startAgent"
99
+ agent = @agents[name]
100
+ arg = @agents_opt[name] if arg.empty?
101
+
102
+ case agent
103
+ when NilClass
104
+ err = "no such agent."
105
+ when AgentManager
106
+ agent.start(arg)
107
+ else
108
+ err = "unknown agent type(#{agent.class})."
109
+ end
110
+
111
+ status = "#{this}(#{name})... #{err || 'OK.'}"
112
+ syslog(status, err ? :error : :normal)
113
+ return status
114
+ end
115
+
116
+ def removeAgent (name)
117
+ err = nil
118
+ this = "removeAgent"
119
+ agent = @agents[name]
120
+
121
+ case agent
122
+ when NilClass
123
+ err = "no such agent."
124
+ when AgentManager
125
+ agent.stop
126
+ @agents.delete(name)
127
+ else
128
+ err = "unknown agent type(#{agent.class})."
129
+ end
130
+
131
+ status = "#{this}(#{name})... #{err || 'OK.'}"
132
+ syslog(status, err ? :error : :normal)
133
+ return status
134
+ end
135
+
136
+ # Agent �κƵ�ư
137
+ def restartAgent (name)
138
+ err = nil
139
+ this = "restartAgent"
140
+ agent = @agents[name]
141
+
142
+ case agent
143
+ when NilClass
144
+ err = "no such agent."
145
+ when AgentManager
146
+ agent.stop
147
+ obj = newAgent(name)
148
+ case obj
149
+ when NilClass
150
+ err = "Agent plugin script return nil (will not be registerd)."
151
+ when String
152
+ err = agent
153
+ else
154
+ arg = @agents_opt[name]
155
+ agent = AgentManager.new(name, obj, self, arg)
156
+ @agents[name] = agent
157
+ agent.start
158
+ end
159
+ else
160
+ err = "unknown agent type(#{agent.class})."
161
+ end
162
+
163
+ status = "#{this}(#{name})... #{err || 'OK.'}"
164
+ syslog(status, err ? :error : :normal)
165
+ return status
166
+ end
167
+
168
+ def stopAgent (name)
169
+ err = nil
170
+ this = "stopAgent"
171
+ agent = @agents[name]
172
+
173
+ case agent
174
+ when NilClass
175
+ err = "no such agent."
176
+ when AgentManager
177
+ agent.stop
178
+ else
179
+ err = "unknown agent type(#{agent.class})."
180
+ end
181
+
182
+ status = "#{this}(#{name})... #{err || 'OK.'}"
183
+ syslog(status, err ? :error : :normal)
184
+ return status
185
+ end
186
+
187
+ def do_help (msg)
188
+ target = msg[:arg].to_s.strip
189
+ if target.empty?
190
+ # �ܥåȤΥإ�ס�cpi�������֤�
191
+ alives = 0
192
+ names = @agents.collect {|name, agent|
193
+ if agent.alive?
194
+ alives += 1
195
+ name = "*#{name}"
196
+ end
197
+ name
198
+ }.join(', ')
199
+ msg[:reply] = "#{@help}\ncpi(#{alives}/#{@agents.size}): #{names}"
200
+ speak(msg)
201
+
202
+ else
203
+ # ���̤� cpi �Υإ�פ��֤���
204
+ target = target.delete('()[] ')
205
+ @agents.each_pair do |name, agent|
206
+ next unless target == name
207
+ next unless (result = agent.apply_methods(msg, :do_help))
208
+ msg[:reply] = result
209
+ speak(msg)
210
+ end
211
+ end
212
+ end
213
+
214
+ def parse_command (msg)
215
+ case msg[:type].to_s
216
+ when CMD_PRIVMSG
217
+ case msg[:str].to_s
218
+ when /^\s*#{myname_regexp_string}\s*(\.\s*[^\s\(]+)/o
219
+ msg[:called] = $1
220
+ msg[:command] = $2
221
+ msg[:arg] = $'.to_s.strip
222
+ msg[:command].gsub!(/^\./, '') if msg[:command]
223
+ when /(#{REGEXP_REDIRECT})\s*#{myname_regexp_string}\s*(\.\s*[^\s\(]+)?\s*$/o
224
+ msg[:arg] = $`.to_s.strip
225
+ msg[:called] = $2
226
+ msg[:command] = $3
227
+ msg[:command].gsub!(/^\./, '') if msg[:command]
228
+ end
229
+ end
230
+ return msg
231
+ end
232
+
233
+ def distributeMessage (msg)
234
+ # prepare accessors for dummy agents
235
+ msg.create_hash!(self)
236
+ msg[:id] = add_message(msg)
237
+ msg = parse_command(msg)
238
+
239
+ # p [msg[:type], msg[:from], msg[:from].to_s.empty?, msg[:str]]
240
+
241
+ # �ȸ������ʥ�å�����(PING��)��̵��
242
+ if msg[:from].to_s.empty?
243
+ return nil
244
+ end
245
+
246
+ begin
247
+ # reserved commands
248
+ name = msg[:arg].to_s.sub(/\A\s*\(?\s*/, '')
249
+ name = name.sub(/\s*\)?\s*\Z/, '') unless name.include?('(')
250
+
251
+ case msg[:command].to_s
252
+ when /^restart$/
253
+ names = name.split(/\s*,?\s+/)
254
+ names = @agents.keys if names.empty?
255
+ names.each do |name|
256
+ msg.reply(restartAgent(name))
257
+ end
258
+ return nil
259
+ when /^register$/ ; msg.reply(registerAgent(name)); return msg.reply(startAgent(name))
260
+ when /^remove$/ ; return msg.reply(removeAgent(name))
261
+ when /^start$/ ; return msg.reply(startAgent(name))
262
+ when /^stop$/ ; return msg.reply(stopAgent(name))
263
+ when /^help$/ ; return do_help(msg)
264
+ end
265
+
266
+ case msg[:type].to_s
267
+ when CMD_JOIN ; each_agent {|agent| agent.apply_methods(msg, :do_join)}
268
+ when CMD_PART ; each_agent {|agent| agent.apply_methods(msg, :do_part)}
269
+ when CMD_PING ; each_agent {|agent| agent.apply_methods(msg, :do_ping)}
270
+ when RPL_NAMREPLY
271
+ # p [:debug, :get_CMD_NAMES]
272
+ each_agent {|agent| agent.apply_methods(msg, :do_names)}
273
+ when CMD_PRIVMSG
274
+
275
+ # �����ν񤭽Ф�
276
+ if @log
277
+ do_log(msg)
278
+ end
279
+
280
+ # do_log �����˸ƤӽФ���(�����������Ѥ�����Τ���)
281
+ message = nil
282
+ catch(:reply) {
283
+ if msg[:called]
284
+ each_agent do |agent|
285
+ next unless (message = agent.apply_methods(msg, :do_command))
286
+ throw :reply
287
+ end
288
+ else
289
+ each_agent do |agent|
290
+ next unless (message = agent.apply_methods(msg, :do_reply))
291
+ throw :reply
292
+ end
293
+ end
294
+ }
295
+
296
+ # Agent#do_log �θƤӽФ�
297
+ each_agent do |agent|
298
+ msg.reply(agent.apply_methods(msg, :do_log))
299
+ end
300
+
301
+ # ��ʬ��ȯ���⵭Ͽ
302
+ if message != nil then
303
+ dummy = {}
304
+ dummy[:str] = message
305
+ dummy[:from] = @nick
306
+ dummy[:to] = @channels
307
+ each_agent { |agent|
308
+ msg.reply(agent.apply_methods(dummy, :do_log))
309
+ }
310
+ end
311
+
312
+ return msg.reply(message)
313
+ end
314
+ rescue Exception
315
+ syslog("distributeMessage: #{$!}(#{$@[0]})", :error)
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+
322
+ if $0 == __FILE__
323
+ config = ARGV.shift or
324
+ raise "Specify your config file\nusage: #{$0} config/xxx.dat"
325
+ irc = IRC::ReplyClient.read_config(config)
326
+ irc.start
327
+ end
328
+