ircbot 0.0.2

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.
@@ -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
+