nadoka 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/ChangeLog.old +1553 -0
- data/Gemfile +4 -0
- data/README.org +31 -0
- data/Rakefile +1 -0
- data/bin/nadoka +13 -0
- data/lib/rss_check.rb +206 -0
- data/lib/tagparts.rb +206 -0
- data/nadoka.gemspec +29 -0
- data/nadoka.rb +123 -0
- data/nadokarc +267 -0
- data/ndk/bot.rb +241 -0
- data/ndk/client.rb +288 -0
- data/ndk/config.rb +571 -0
- data/ndk/error.rb +61 -0
- data/ndk/logger.rb +311 -0
- data/ndk/server.rb +784 -0
- data/ndk/server_state.rb +324 -0
- data/ndk/version.rb +44 -0
- data/plugins/autoawaybot.nb +66 -0
- data/plugins/autodumpbot.nb +227 -0
- data/plugins/autoop.nb +56 -0
- data/plugins/backlogbot.nb +88 -0
- data/plugins/checkbot.nb +64 -0
- data/plugins/cronbot.nb +20 -0
- data/plugins/dictbot.nb +53 -0
- data/plugins/drbcl.rb +39 -0
- data/plugins/drbot.nb +93 -0
- data/plugins/evalbot.nb +49 -0
- data/plugins/gonzuibot.nb +41 -0
- data/plugins/googlebot.nb +345 -0
- data/plugins/identifynickserv.nb +43 -0
- data/plugins/mailcheckbot.nb +0 -0
- data/plugins/marldiabot.nb +99 -0
- data/plugins/messagebot.nb +96 -0
- data/plugins/modemanager.nb +150 -0
- data/plugins/opensearchbot.nb +156 -0
- data/plugins/opshop.nb +23 -0
- data/plugins/pastebot.nb +46 -0
- data/plugins/roulettebot.nb +33 -0
- data/plugins/rss_checkbot.nb +121 -0
- data/plugins/samplebot.nb +24 -0
- data/plugins/sendpingbot.nb +17 -0
- data/plugins/shellbot.nb +59 -0
- data/plugins/sixamobot.nb +77 -0
- data/plugins/tenkibot.nb +111 -0
- data/plugins/timestampbot.nb +62 -0
- data/plugins/titlebot.nb +226 -0
- data/plugins/translatebot.nb +301 -0
- data/plugins/twitterbot.nb +138 -0
- data/plugins/weba.nb +209 -0
- data/plugins/xibot.nb +113 -0
- data/rice/irc.rb +780 -0
- metadata +102 -0
data/Gemfile
ADDED
data/README.org
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#######################################################
|
2
|
+
# Nadoka: IRC Client server program.
|
3
|
+
#
|
4
|
+
# Written by SASADA Koichi <ko1 at atdot.net>
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# $Id$
|
8
|
+
#
|
9
|
+
|
10
|
+
* What's this?
|
11
|
+
|
12
|
+
Nadoka is IRC Client Server program.
|
13
|
+
It's same concept as [[http://www.madoka.org/][madoka]].
|
14
|
+
|
15
|
+
You can do with this software:
|
16
|
+
|
17
|
+
- connect to IRC usually
|
18
|
+
- easy to make a bot with ruby
|
19
|
+
|
20
|
+
|
21
|
+
* more about
|
22
|
+
|
23
|
+
See Web pages:
|
24
|
+
- https://github.com/nadoka/nadoka
|
25
|
+
- http://rubyforge.org/projects/nadoka/
|
26
|
+
- http://www.atdot.net/nadoka/
|
27
|
+
|
28
|
+
|
29
|
+
: Thank you,
|
30
|
+
: --
|
31
|
+
: SASADA Koichi at atdot dot net
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/nadoka
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'rbconfig'
|
3
|
+
ruby = nil
|
4
|
+
begin
|
5
|
+
ruby = RbConfig.ruby
|
6
|
+
rescue
|
7
|
+
ruby = File.join(
|
8
|
+
Config::CONFIG["bindir"],
|
9
|
+
Config::CONFIG["ruby_install_name"] + Config::CONFIG["EXEEXT"]
|
10
|
+
)
|
11
|
+
end
|
12
|
+
top_dir = File.expand_path('../..', __FILE__)
|
13
|
+
exec(ruby, "-I#{top_dir}", File.join(top_dir, 'nadoka.rb'), *ARGV)
|
data/lib/rss_check.rb
ADDED
@@ -0,0 +1,206 @@
|
|
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. Sat, 24 Apr 2004 12:10:31 +0900
|
11
|
+
#
|
12
|
+
|
13
|
+
require "rss/parser"
|
14
|
+
require "rss/1.0"
|
15
|
+
require "rss/2.0"
|
16
|
+
require "rss/syndication"
|
17
|
+
require "rss/dublincore"
|
18
|
+
require "open-uri"
|
19
|
+
require 'uri'
|
20
|
+
require 'yaml/store'
|
21
|
+
require 'csv'
|
22
|
+
require 'stringio'
|
23
|
+
require 'zlib'
|
24
|
+
|
25
|
+
|
26
|
+
class RSS_Check
|
27
|
+
class RSS_File
|
28
|
+
def initialize path, init_now
|
29
|
+
@uri = URI.parse(path)
|
30
|
+
@entry_time = @file_time = (init_now ? Time.now : Time.at(0))
|
31
|
+
end
|
32
|
+
|
33
|
+
def check
|
34
|
+
begin
|
35
|
+
if (mt=mtime) > @file_time
|
36
|
+
@file_time = mt
|
37
|
+
check_entries
|
38
|
+
else
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
rescue => e
|
42
|
+
[{
|
43
|
+
:about => e.message,
|
44
|
+
:title => "RSS Check Error (#{@uri})",
|
45
|
+
:ccode => 'UTF-8'
|
46
|
+
}]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def date_of e
|
51
|
+
if e.respond_to? :dc_date
|
52
|
+
e.dc_date || Time.at(0)
|
53
|
+
else
|
54
|
+
e.pubDate || Time.at(0)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_entries
|
59
|
+
rss = RSS::Parser.parse(read_content, false)
|
60
|
+
et = @entry_time
|
61
|
+
items = rss.items.sort_by{|e|
|
62
|
+
date_of(e)
|
63
|
+
}.map{|e|
|
64
|
+
e_date = date_of(e)
|
65
|
+
if e_date > @entry_time
|
66
|
+
if e_date > et
|
67
|
+
et = e_date
|
68
|
+
end
|
69
|
+
{
|
70
|
+
:about => e.about,
|
71
|
+
:title => e.title,
|
72
|
+
:ccode => 'UTF-8'
|
73
|
+
}
|
74
|
+
end
|
75
|
+
}.compact
|
76
|
+
@entry_time = et
|
77
|
+
items
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_content
|
81
|
+
case @uri.scheme
|
82
|
+
when 'http'
|
83
|
+
open(@uri){|f|
|
84
|
+
if f.content_encoding.any?{|e| /gzip/ =~ e}
|
85
|
+
Zlib::GzipReader.new(StringIO.new(f.read)).read || ''
|
86
|
+
else
|
87
|
+
f.read
|
88
|
+
end
|
89
|
+
}
|
90
|
+
else
|
91
|
+
open(@uri.to_s){|f|
|
92
|
+
f.read
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def mtime
|
98
|
+
case @uri.scheme
|
99
|
+
when 'http'
|
100
|
+
open(@uri){|f|
|
101
|
+
f.last_modified || Time.now
|
102
|
+
}
|
103
|
+
else
|
104
|
+
File.mtime(@rss_file)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class LIRS_File < RSS_File
|
110
|
+
def check_entries
|
111
|
+
et = @entry_time
|
112
|
+
res = []
|
113
|
+
CSV::Reader.parse(read_content){|row|
|
114
|
+
last_detected = Time.at(row[2].data.to_i)
|
115
|
+
if last_detected > @entry_time && row[1].data != row[2].data
|
116
|
+
if last_detected > et
|
117
|
+
et = last_detected
|
118
|
+
end
|
119
|
+
res << {
|
120
|
+
:about => row[5].data,
|
121
|
+
:title => row[6].data,
|
122
|
+
:ccode => 'EUC-JP'
|
123
|
+
}
|
124
|
+
end
|
125
|
+
}
|
126
|
+
@entry_time = et
|
127
|
+
res
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def initialize paths, cache_file=nil, init_now=false
|
132
|
+
@paths = paths
|
133
|
+
@db = YAML::Store.new(cache_file) if cache_file
|
134
|
+
@rss_files = paths.map{|uri|
|
135
|
+
load_file(uri) ||
|
136
|
+
if /LIRS:(.+)/ =~ uri
|
137
|
+
LIRS_File.new($1, init_now)
|
138
|
+
else
|
139
|
+
RSS_File.new(uri, init_now)
|
140
|
+
end
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def check
|
145
|
+
@rss_files.map{|rf|
|
146
|
+
rf.check
|
147
|
+
}.flatten
|
148
|
+
end
|
149
|
+
|
150
|
+
def save
|
151
|
+
@db.transaction{
|
152
|
+
@paths.each_with_index{|path, i|
|
153
|
+
@db[path] = @rss_files[i]
|
154
|
+
}
|
155
|
+
} if @db
|
156
|
+
end
|
157
|
+
|
158
|
+
def load_file file
|
159
|
+
@db.transaction{
|
160
|
+
@db[file]
|
161
|
+
} if @db
|
162
|
+
end
|
163
|
+
|
164
|
+
def clear
|
165
|
+
if @db
|
166
|
+
@db.transaction{
|
167
|
+
@db.keys.each{|k|
|
168
|
+
@db.delete k
|
169
|
+
}
|
170
|
+
}
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
if $0 == __FILE__
|
177
|
+
rss_uri = %w(
|
178
|
+
http://www.ruby-lang.org/ja/index.rdf
|
179
|
+
http://slashdot.jp/slashdotjp.rss
|
180
|
+
http://www3.asahi.com/rss/index.rdf
|
181
|
+
http://pcweb.mycom.co.jp/haishin/rss/index.rdf
|
182
|
+
http://japan.cnet.com/rss/index.rdf
|
183
|
+
http://blog.japan.cnet.com/umeda/index.rdf
|
184
|
+
http://jvn.doi.ics.keio.ac.jp/rss/jvnRSS.rdf
|
185
|
+
)
|
186
|
+
lirs_uri = [
|
187
|
+
'LIRS:http://www.rubyist.net/~kazu/samidare/sites.lirs.gz'
|
188
|
+
]
|
189
|
+
|
190
|
+
rssc = RSS_Check.new(
|
191
|
+
rss_uri + lirs_uri,
|
192
|
+
ARGV.shift || './rss_cache',
|
193
|
+
false # false
|
194
|
+
)
|
195
|
+
require 'iconv'
|
196
|
+
require 'kconv'
|
197
|
+
ic = Iconv.open("EUC-JP", "UTF-8")
|
198
|
+
|
199
|
+
rssc.check.each{|e|
|
200
|
+
puts e[:about]
|
201
|
+
title = (e[:ccode] == 'UTF-8') ? ic.iconv(e[:title]) : e[:title]
|
202
|
+
puts title
|
203
|
+
}
|
204
|
+
rssc.dump
|
205
|
+
end
|
206
|
+
|
data/lib/tagparts.rb
ADDED
@@ -0,0 +1,206 @@
|
|
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
|
+
#
|
11
|
+
|
12
|
+
require 'cgi'
|
13
|
+
module TagParts
|
14
|
+
class TagItem
|
15
|
+
include Enumerable
|
16
|
+
def initialize tag, body, ignore_empty = false
|
17
|
+
@tag = tag.to_s
|
18
|
+
@attr = {}
|
19
|
+
@body = []
|
20
|
+
@ignore_empty = ignore_empty
|
21
|
+
body.each{|e|
|
22
|
+
add! e
|
23
|
+
}
|
24
|
+
end
|
25
|
+
attr_reader :body, :tag, :attr
|
26
|
+
|
27
|
+
def make_attr_str
|
28
|
+
@attr.map{|k,v|
|
29
|
+
" #{CGI.escapeHTML(k.to_s)}='#{CGI.escapeHTML(v)}'"
|
30
|
+
}.join
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
if @body.size > 0 || @ignore_empty
|
35
|
+
body = @body.flatten.map{|e|
|
36
|
+
if e.kind_of? String
|
37
|
+
CGI.escapeHTML(e.to_s)
|
38
|
+
else
|
39
|
+
e.to_s
|
40
|
+
end
|
41
|
+
}
|
42
|
+
"<#{@tag}#{make_attr_str}\n>#{body}</#{@tag}>\n"
|
43
|
+
else
|
44
|
+
"<#{@tag}#{make_attr_str} /\n>"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def inspect
|
49
|
+
"<TagItem: <#{@tag}#{make_attr_str}>>"
|
50
|
+
end
|
51
|
+
|
52
|
+
def add!(elem)
|
53
|
+
if elem.kind_of? Hash
|
54
|
+
@attr.update elem
|
55
|
+
else
|
56
|
+
@body << elem
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def [](k)
|
61
|
+
@attr[k]
|
62
|
+
end
|
63
|
+
|
64
|
+
def []=(k, v)
|
65
|
+
@attr[k] = v
|
66
|
+
end
|
67
|
+
|
68
|
+
def each
|
69
|
+
@body.flatten.each{|e|
|
70
|
+
yield e
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
def each_leaf
|
75
|
+
@body.each{|e|
|
76
|
+
if e.kind_of? TagItem
|
77
|
+
e.each_leaf(&Proc.new)
|
78
|
+
else
|
79
|
+
yield e
|
80
|
+
end
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def each_node
|
85
|
+
yield(self)
|
86
|
+
@body.each{|e|
|
87
|
+
if e.kind_of? TagItem
|
88
|
+
e.each_node(&Proc.new)
|
89
|
+
else
|
90
|
+
yield e
|
91
|
+
end
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
alias << add!
|
96
|
+
end
|
97
|
+
|
98
|
+
def ignore_empty_tag?
|
99
|
+
false
|
100
|
+
end
|
101
|
+
|
102
|
+
# do nothing. please override
|
103
|
+
def tag_encoding str
|
104
|
+
str
|
105
|
+
end
|
106
|
+
|
107
|
+
def tree2string tag
|
108
|
+
tag_encoding(tree2string_(tag))
|
109
|
+
end
|
110
|
+
|
111
|
+
def tree2string_ tag
|
112
|
+
bs = tag.map{|body|
|
113
|
+
if body.kind_of? TagItem
|
114
|
+
tree2string_(body)
|
115
|
+
else
|
116
|
+
CGI.escapeHTML(body.to_s)
|
117
|
+
end
|
118
|
+
}
|
119
|
+
tagname = tag.tag
|
120
|
+
attr = tag.make_attr_str
|
121
|
+
if bs.size > 0 || ignore_empty_tag?
|
122
|
+
"<#{tagname}#{attr}\n>#{bs}</#{tagname}>\n"
|
123
|
+
else
|
124
|
+
"<#{tagname}#{attr}\n/>"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
@@method_prefix = '_'
|
129
|
+
|
130
|
+
def self.newtag sym, ignore_empty, klass = TagParts
|
131
|
+
klass.module_eval <<-EOS
|
132
|
+
def #{@@method_prefix}#{sym}(*args)
|
133
|
+
TagItem.new(:#{sym}, args, #{ignore_empty})
|
134
|
+
end
|
135
|
+
EOS
|
136
|
+
end
|
137
|
+
|
138
|
+
TagParts.module_eval <<-EOS
|
139
|
+
def #{@@method_prefix}(tag, *args)
|
140
|
+
TagItem.new(tag, args, false)
|
141
|
+
end
|
142
|
+
EOS
|
143
|
+
|
144
|
+
def method_missing m, *args
|
145
|
+
if make_unknown_tag? && (/^#{@@method_prefix}(.+)/ =~ m.to_s)
|
146
|
+
TagItem.new($1, args)
|
147
|
+
else
|
148
|
+
super
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def make_unknown_tag?
|
153
|
+
true
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
module HTMLParts
|
159
|
+
include TagParts
|
160
|
+
|
161
|
+
def make_unknown_tag?
|
162
|
+
false
|
163
|
+
end
|
164
|
+
|
165
|
+
def ignore_empty_tag?
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
# copy from cgi.rb
|
171
|
+
PARTS_1 = %w{
|
172
|
+
TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD
|
173
|
+
VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
|
174
|
+
H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP
|
175
|
+
FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
|
176
|
+
TEXTAREA FORM A BLOCKQUOTE CAPTION
|
177
|
+
}
|
178
|
+
PARTS_2 = %w{
|
179
|
+
IMG BASE BR AREA LINK PARAM HR INPUT COL META
|
180
|
+
}
|
181
|
+
PARTS_3 = %w{
|
182
|
+
HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY COLGROUP TR TH TD HEAD
|
183
|
+
}
|
184
|
+
(PARTS_1 + PARTS_2 + PARTS_3).each{|e|
|
185
|
+
elem = e.downcase
|
186
|
+
TagParts.newtag elem, true
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
__END__
|
191
|
+
|
192
|
+
include HTMLParts
|
193
|
+
tags = _html(
|
194
|
+
_head(
|
195
|
+
_title('hogehoge')),
|
196
|
+
_body(
|
197
|
+
_br(),
|
198
|
+
_h1('huga-'),
|
199
|
+
_p('hogehoge', _a('hogehoge', 'href' => 'dokka'), 'huga'),
|
200
|
+
_p('hogehoge', 'huga', ['ho-', 'hu'])
|
201
|
+
))
|
202
|
+
|
203
|
+
puts tags.to_s
|
204
|
+
puts tree2string(tags)
|
205
|
+
p( tags.to_s == tree2string(tags) )
|
206
|
+
|