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