rbot 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/AUTHORS +16 -0
  2. data/COPYING +21 -0
  3. data/ChangeLog +418 -0
  4. data/INSTALL +8 -0
  5. data/README +44 -0
  6. data/REQUIREMENTS +34 -0
  7. data/TODO +5 -0
  8. data/Usage_en.txt +129 -0
  9. data/bin/rbot +81 -0
  10. data/data/rbot/contrib/plugins/figlet.rb +20 -0
  11. data/data/rbot/contrib/plugins/ri.rb +83 -0
  12. data/data/rbot/contrib/plugins/stats.rb +232 -0
  13. data/data/rbot/contrib/plugins/vandale.rb +49 -0
  14. data/data/rbot/languages/dutch.lang +73 -0
  15. data/data/rbot/languages/english.lang +75 -0
  16. data/data/rbot/languages/french.lang +39 -0
  17. data/data/rbot/languages/german.lang +67 -0
  18. data/data/rbot/plugins/autoop.rb +68 -0
  19. data/data/rbot/plugins/autorejoin.rb +16 -0
  20. data/data/rbot/plugins/cal.rb +15 -0
  21. data/data/rbot/plugins/dice.rb +81 -0
  22. data/data/rbot/plugins/eightball.rb +19 -0
  23. data/data/rbot/plugins/excuse.rb +470 -0
  24. data/data/rbot/plugins/fish.rb +61 -0
  25. data/data/rbot/plugins/fortune.rb +22 -0
  26. data/data/rbot/plugins/freshmeat.rb +98 -0
  27. data/data/rbot/plugins/google.rb +51 -0
  28. data/data/rbot/plugins/host.rb +14 -0
  29. data/data/rbot/plugins/httpd.rb.disabled +35 -0
  30. data/data/rbot/plugins/insult.rb +258 -0
  31. data/data/rbot/plugins/karma.rb +85 -0
  32. data/data/rbot/plugins/lart.rb +181 -0
  33. data/data/rbot/plugins/math.rb +122 -0
  34. data/data/rbot/plugins/nickserv.rb +89 -0
  35. data/data/rbot/plugins/nslookup.rb +43 -0
  36. data/data/rbot/plugins/opme.rb +19 -0
  37. data/data/rbot/plugins/quakeauth.rb +51 -0
  38. data/data/rbot/plugins/quotes.rb +321 -0
  39. data/data/rbot/plugins/remind.rb +228 -0
  40. data/data/rbot/plugins/roshambo.rb +54 -0
  41. data/data/rbot/plugins/rot13.rb +10 -0
  42. data/data/rbot/plugins/roulette.rb +147 -0
  43. data/data/rbot/plugins/rss.rb.disabled +414 -0
  44. data/data/rbot/plugins/seen.rb +89 -0
  45. data/data/rbot/plugins/slashdot.rb +94 -0
  46. data/data/rbot/plugins/spell.rb +36 -0
  47. data/data/rbot/plugins/tube.rb +71 -0
  48. data/data/rbot/plugins/url.rb +88 -0
  49. data/data/rbot/plugins/weather.rb +649 -0
  50. data/data/rbot/plugins/wserver.rb +71 -0
  51. data/data/rbot/plugins/xmlrpc.rb.disabled +52 -0
  52. data/data/rbot/templates/keywords.rbot +4 -0
  53. data/data/rbot/templates/lart/larts +98 -0
  54. data/data/rbot/templates/lart/praises +5 -0
  55. data/data/rbot/templates/levels.rbot +30 -0
  56. data/data/rbot/templates/users.rbot +1 -0
  57. data/lib/rbot/auth.rb +203 -0
  58. data/lib/rbot/channel.rb +54 -0
  59. data/lib/rbot/config.rb +363 -0
  60. data/lib/rbot/dbhash.rb +112 -0
  61. data/lib/rbot/httputil.rb +141 -0
  62. data/lib/rbot/ircbot.rb +808 -0
  63. data/lib/rbot/ircsocket.rb +185 -0
  64. data/lib/rbot/keywords.rb +433 -0
  65. data/lib/rbot/language.rb +69 -0
  66. data/lib/rbot/message.rb +256 -0
  67. data/lib/rbot/messagemapper.rb +262 -0
  68. data/lib/rbot/plugins.rb +291 -0
  69. data/lib/rbot/post-install.rb +8 -0
  70. data/lib/rbot/rbotconfig.rb +36 -0
  71. data/lib/rbot/registry.rb +271 -0
  72. data/lib/rbot/rfc2812.rb +1104 -0
  73. data/lib/rbot/timer.rb +201 -0
  74. data/lib/rbot/utils.rb +83 -0
  75. data/setup.rb +1360 -0
  76. metadata +129 -0
@@ -0,0 +1,54 @@
1
+ # Play the game of roshambo (rock-paper-scissors)
2
+ # Copyright (C) 2004 Hans Fugal
3
+ # Distributed under the same license as rbot itself
4
+ require 'time'
5
+ class RoshamboPlugin < Plugin
6
+ def initialize
7
+ super
8
+ @scoreboard = {}
9
+ end
10
+ def help(plugin, topic="")
11
+ "roshambo <rock|paper|scissors> => play roshambo"
12
+ end
13
+ def privmsg(m)
14
+ # simultaneity
15
+ choice = choose
16
+
17
+ # init scoreboard
18
+ if (not @scoreboard.has_key?(m.sourcenick) or (Time.now - @scoreboard[m.sourcenick]['timestamp']) > 3600)
19
+ @scoreboard[m.sourcenick] = {'me'=>0,'you'=>0,'timestamp'=>Time.now}
20
+ end
21
+ case m.params
22
+ when 'rock','paper','scissors'
23
+ s = score(choice,m.params)
24
+ @scoreboard[m.sourcenick]['timestamp'] = Time.now
25
+ myscore=@scoreboard[m.sourcenick]['me']
26
+ yourscore=@scoreboard[m.sourcenick]['you']
27
+ case s
28
+ when 1
29
+ yourscore=@scoreboard[m.sourcenick]['you'] += 1
30
+ m.reply "#{choice}. You win. Score: me #{myscore} you #{yourscore}"
31
+ when 0
32
+ m.reply "#{choice}. We tie. Score: me #{myscore} you #{yourscore}"
33
+ when -1
34
+ myscore=@scoreboard[m.sourcenick]['me'] += 1
35
+ m.reply "#{choice}! I win! Score: me #{myscore} you #{yourscore}"
36
+ end
37
+ else
38
+ m.reply "incorrect usage: " + help(m.plugin)
39
+ end
40
+ end
41
+
42
+ def choose
43
+ ['rock','paper','scissors'][rand(3)]
44
+ end
45
+ def score(a,b)
46
+ beats = {'rock'=>'scissors', 'paper'=>'rock', 'scissors'=>'paper'}
47
+ return -1 if beats[a] == b
48
+ return 1 if beats[b] == a
49
+ return 0
50
+ end
51
+ end
52
+ plugin = RoshamboPlugin.new
53
+ plugin.register("roshambo")
54
+ plugin.register("rps")
@@ -0,0 +1,10 @@
1
+ class RotPlugin < Plugin
2
+ def help(plugin, topic="")
3
+ "rot13 <string> => encode <string> to rot13 or back"
4
+ end
5
+ def rot13(m, params)
6
+ m.reply params[:string].tr("A-Za-z", "N-ZA-Mn-za-m");
7
+ end
8
+ end
9
+ plugin = RotPlugin.new
10
+ plugin.map 'rot13 :string'
@@ -0,0 +1,147 @@
1
+ RouletteHistory = Struct.new("RouletteHistory", :games, :shots, :deaths, :misses, :wins)
2
+
3
+ class RoulettePlugin < Plugin
4
+ def initialize
5
+ super
6
+ reset_chambers
7
+ @players = Array.new
8
+ end
9
+ def help(plugin, topic="")
10
+ "roulette => play russian roulette - starts a new game if one isn't already running. One round in a six chambered gun. Take turns to say roulette to the bot, until somebody dies. roulette reload => force the gun to reload, roulette stats => show stats from all games, roulette stats <player> => show stats for <player>, roulette clearstats => clear stats (config level auth required)"
11
+ end
12
+ def clearstats(m, params)
13
+ @registry.clear
14
+ m.okay
15
+ end
16
+
17
+ def roulette(m, params)
18
+ if m.private?
19
+ m.reply "you gotta play roulette in channel dude"
20
+ return
21
+ end
22
+
23
+ playerdata = nil
24
+ if @registry.has_key?(m.sourcenick)
25
+ playerdata = @registry[m.sourcenick]
26
+ else
27
+ playerdata = RouletteHistory.new(0,0,0,0,0)
28
+ end
29
+
30
+ unless @players.include?(m.sourcenick)
31
+ @players << m.sourcenick
32
+ playerdata.games += 1
33
+ end
34
+ playerdata.shots += 1
35
+
36
+ shot = @chambers.pop
37
+ if shot
38
+ m.reply "#{m.sourcenick}: chamber #{6 - @chambers.length} of 6 => *BANG*"
39
+ playerdata.deaths += 1
40
+ @players.each {|plyr|
41
+ next if plyr == m.sourcenick
42
+ pdata = @registry[plyr]
43
+ next if pdata == nil
44
+ pdata.wins += 1
45
+ @registry[plyr] = pdata
46
+ }
47
+ else
48
+ m.reply "#{m.sourcenick}: chamber #{6 - @chambers.length} of 6 => +click+"
49
+ playerdata.misses += 1
50
+ end
51
+
52
+ @registry[m.sourcenick] = playerdata
53
+
54
+ if shot || @chambers.empty?
55
+ reload(m)
56
+ end
57
+ end
58
+ def reload(m, params = {})
59
+ @bot.action m.replyto, "reloads"
60
+ reset_chambers
61
+ # all players win on a reload
62
+ # (allows you to play 3-shot matches etc)
63
+ @players.each {|plyr|
64
+ pdata = @registry[plyr]
65
+ next if pdata == nil
66
+ pdata.wins += 1
67
+ @registry[plyr] = pdata
68
+ }
69
+ @players = Array.new
70
+ end
71
+ def reset_chambers
72
+ @chambers = [false, false, false, false, false, false]
73
+ @chambers[rand(@chambers.length)] = true
74
+ end
75
+ def playerstats(m, params)
76
+ player = params[:player]
77
+ pstats = @registry[player]
78
+ if pstats.nil?
79
+ m.reply "#{player} hasn't played enough games yet"
80
+ else
81
+ m.reply "#{player} has played #{pstats.games} games, won #{pstats.wins} and lost #{pstats.deaths}. #{player} pulled the trigger #{pstats.shots} times and found the chamber empty on #{pstats.misses} occasions."
82
+ end
83
+ end
84
+ def stats(m, params)
85
+ total_players = 0
86
+ total_games = 0
87
+ total_shots = 0
88
+
89
+ died_most = [nil,0]
90
+ won_most = [nil,0]
91
+ h_win_percent = [nil,0]
92
+ l_win_percent = [nil,0]
93
+ h_luck_percent = [nil,0]
94
+ l_luck_percent = [nil,0]
95
+ @registry.each {|k,v|
96
+ total_players += 1
97
+ total_games += v.deaths
98
+ total_shots += v.shots
99
+
100
+ win_rate = v.wins.to_f / v.games * 100
101
+ if h_win_percent[0].nil? || win_rate > h_win_percent[1] && v.games > 2
102
+ h_win_percent = [[k], win_rate]
103
+ elsif win_rate == h_win_percent[1] && v.games > 2
104
+ h_win_percent[0] << k
105
+ end
106
+ if l_win_percent[0].nil? || win_rate < l_win_percent[1] && v.games > 2
107
+ l_win_percent = [[k], win_rate]
108
+ elsif win_rate == l_win_percent[1] && v.games > 2
109
+ l_win_percent[0] << k
110
+ end
111
+
112
+ luck = v.misses.to_f / v.shots * 100
113
+ if h_luck_percent[0].nil? || luck > h_luck_percent[1] && v.games > 2
114
+ h_luck_percent = [[k], luck]
115
+ elsif luck == h_luck_percent[1] && v.games > 2
116
+ h_luck_percent[0] << k
117
+ end
118
+ if l_luck_percent[0].nil? || luck < l_luck_percent[1] && v.games > 2
119
+ l_luck_percent = [[k], luck]
120
+ elsif luck == l_luck_percent[1] && v.games > 2
121
+ l_luck_percent[0] << k
122
+ end
123
+
124
+ if died_most[0].nil? || v.deaths > died_most[1]
125
+ died_most = [[k], v.deaths]
126
+ elsif v.deaths == died_most[1]
127
+ died_most[0] << k
128
+ end
129
+ if won_most[0].nil? || v.wins > won_most[1]
130
+ won_most = [[k], v.wins]
131
+ elsif v.wins == won_most[1]
132
+ won_most[0] << k
133
+ end
134
+ }
135
+ if total_games < 1
136
+ m.reply "roulette stats: no games played yet"
137
+ else
138
+ m.reply "roulette stats: #{total_games} games completed, #{total_shots} shots fired at #{total_players} players. Luckiest: #{h_luck_percent[0].join(',')} (#{sprintf '%.1f', h_luck_percent[1]}% clicks). Unluckiest: #{l_luck_percent[0].join(',')} (#{sprintf '%.1f', l_luck_percent[1]}% clicks). Highest survival rate: #{h_win_percent[0].join(',')} (#{sprintf '%.1f', h_win_percent[1]}%). Lowest survival rate: #{l_win_percent[0].join(',')} (#{sprintf '%.1f', l_win_percent[1]}%). Most wins: #{won_most[0].join(',')} (#{won_most[1]}). Most deaths: #{died_most[0].join(',')} (#{died_most[1]})."
139
+ end
140
+ end
141
+ end
142
+ plugin = RoulettePlugin.new
143
+ plugin.map 'roulette reload', :action => 'reload'
144
+ plugin.map 'roulette stats :player', :action => 'playerstats'
145
+ plugin.map 'roulette stats', :action => 'stats'
146
+ plugin.map 'roulette clearstats', :action => 'clearstats', :auth => 'config'
147
+ plugin.map 'roulette'
@@ -0,0 +1,414 @@
1
+ # RSS feed plugin for RubyBot
2
+ # (c) 2004 Stanislav Karchebny <berkus@madfire.net>
3
+ # (c) 2005 Ian Monroe <ian@monroe.nu>
4
+ # (c) 2005 Mark Kretschmann <markey@web.de>
5
+ # Licensed under MIT License.
6
+
7
+ # TODO
8
+ # checks feeds very often - does it use HEAD to check it needs to d/l?
9
+ # some usage issues
10
+ # why can't I do this here? :
11
+ # Class String
12
+ # def foo
13
+ # foo
14
+ # end
15
+ # end
16
+
17
+ require 'rss/parser'
18
+ require 'rss/1.0'
19
+ require 'rss/2.0'
20
+ require 'rss/dublincore'
21
+ begin
22
+ require 'rss/dublincore/2.0'
23
+ rescue LoadError => e
24
+ puts "rss plugin: no dublincore 2.0 found, should be okay tho"
25
+ end
26
+
27
+
28
+ class RSSFeedsPlugin < Plugin
29
+ @@watchThreads = Hash.new
30
+
31
+ # Keep a 1:1 relation between commands and handlers
32
+ @@handlers = {
33
+ "rss" => "handle_rss",
34
+ "addrss" => "handle_addrss",
35
+ "rmrss" => "handle_rmrss",
36
+ "listrss" => "handle_listrss",
37
+ "listwatches" => "handle_listrsswatch",
38
+ "rewatch" => "handle_rewatch",
39
+ "watchrss" => "handle_watchrss",
40
+ "rmwatch" => "handle_rmwatch"
41
+ }
42
+
43
+ def name
44
+ 'rss'
45
+ end
46
+
47
+ def initialize
48
+ super
49
+ @feeds = Hash.new
50
+ @watchList = Hash.new
51
+
52
+ if FileTest.exists?("#{@bot.botclass}/rss/feeds")
53
+ IO.foreach("#{@bot.botclass}/rss/feeds") { |line|
54
+ s = line.chomp.split("|", 2)
55
+ @feeds[s[0]] = s[1]
56
+ }
57
+ end
58
+
59
+ if FileTest.exists?("#{@bot.botclass}/rss/watchlist")
60
+ IO.foreach("#{@bot.botclass}/rss/watchlist") { |line|
61
+ s = line.chomp.split("|", 3)
62
+ @watchList[s[0]] = [s[1], s[2]]
63
+ watchRss( s[2], s[0], s[1] )
64
+ }
65
+ end
66
+ end
67
+
68
+ def cleanup
69
+ kill_threads
70
+ end
71
+
72
+ def save
73
+ Dir.mkdir("#{@bot.botclass}/rss") if not FileTest.directory?("#{@bot.botclass}/rss")
74
+ File.open("#{@bot.botclass}/rss/feeds", "w") { |file|
75
+ @feeds.each { |k,v|
76
+ file.puts(k + "|" + v)
77
+ }
78
+ }
79
+ File.open("#{@bot.botclass}/rss/watchlist", "w") { |file|
80
+ @watchList.each { |url, d|
81
+ feedFormat = d[0] || ''
82
+ whichChan = d[1] || 'markey'
83
+ file.puts(url + '|' + feedFormat + '|' + whichChan)
84
+ }
85
+ }
86
+ end
87
+
88
+ def kill_threads
89
+ Thread.critical=true
90
+ # Abort all running threads.
91
+ @@watchThreads.each { |url, thread|
92
+ puts "Killing thread for #{url}"
93
+ thread.kill
94
+ }
95
+ # @@watchThreads.each { |url, thread|
96
+ # puts "Joining on killed thread for #{url}"
97
+ # thread.join
98
+ # }
99
+ @@watchThreads = Hash.new
100
+ Thread.critical=false
101
+ end
102
+
103
+ def help(plugin,topic="")
104
+ "RSS Reader: rss name [limit] => read a named feed [limit maximum posts, default 5], addrss [force] name url => add a feed, listrss => list all available feeds, rmrss name => remove the named feed, watchrss url [type] => watch a rss feed for changes (type may be 'amarokblog', 'amarokforum', 'mediawiki', 'gmame' or empty - it defines special formatting of feed items), rewatch => restart all rss watches, rmwatch url => stop watching for changes in url"
105
+ end
106
+
107
+ def privmsg(m)
108
+ meth = self.method(@@handlers[m.plugin])
109
+ meth.call(m)
110
+ end
111
+
112
+ def handle_rss(m)
113
+ unless m.params
114
+ m.reply("incorrect usage: " + help(m.plugin))
115
+ return
116
+ end
117
+ limit = 5
118
+ if m.params =~ /\s+(\d+)$/
119
+ limit = $1.to_i
120
+ if limit < 1 || limit > 15
121
+ m.reply("weird, limit not in [1..15], reverting to default")
122
+ limit = 5
123
+ end
124
+ m.params.gsub!(/\s+\d+$/, '')
125
+ end
126
+ unless @feeds.has_key?(m.params)
127
+ m.reply(m.params + "? what is that feed about?")
128
+ return
129
+ end
130
+
131
+ m.reply("Please wait, querying...")
132
+ title = ''
133
+ items = fetchRSS(m.replyto, @feeds[m.params], title)
134
+ if(items == nil)
135
+ return
136
+ end
137
+ m.reply("Channel : #{title}")
138
+ # FIXME: optional by-date sorting if dates present
139
+ items[0...limit].each do |item|
140
+ printRSSItem(m.replyto,item)
141
+ end
142
+ end
143
+
144
+ def handle_addrss(m)
145
+ unless m.params
146
+ m.reply "incorrect usage: " + help(m.plugin)
147
+ return
148
+ end
149
+ if m.params =~ /^force /
150
+ forced = true
151
+ m.params.gsub!(/^force /, '')
152
+ end
153
+ feed = m.params.scan(/^(\S+)\s+(\S+)$/)
154
+ unless feed.length == 1 && feed[0].length == 2
155
+ m.reply("incorrect usage: " + help(m.plugin))
156
+ return
157
+ end
158
+ if @feeds.has_key?(feed[0][0]) && !forced
159
+ m.reply("But there is already a feed named #{feed[0][0]} with url #{@feeds[feed[0][0]]}")
160
+ return
161
+ end
162
+ feed[0][0].gsub!("|", '_')
163
+ @feeds[feed[0][0]] = feed[0][1]
164
+ m.reply("RSS: Added #{feed[0][1]} with name #{feed[0][0]}")
165
+ end
166
+
167
+ def handle_rmrss(m)
168
+ unless m.params
169
+ m.reply "incorrect usage: " + help(m.plugin)
170
+ return
171
+ end
172
+ unless @feeds.has_key?(m.params)
173
+ m.reply("dunno that feed")
174
+ return
175
+ end
176
+ @feeds.delete(m.params)
177
+ m.okay
178
+ end
179
+
180
+ def handle_rmwatch(m)
181
+ unless m.params
182
+ m.reply "incorrect usage: " + help(m.plugin)
183
+ return
184
+ end
185
+ unless @watchList.has_key?(m.params)
186
+ m.reply("no such watch")
187
+ return
188
+ end
189
+ unless @watchList[m.params][1] == m.replyto
190
+ m.reply("no such watch for this channel/nick")
191
+ return
192
+ end
193
+ @watchList.delete(m.params)
194
+ Thread.critical=true
195
+ if @@watchThreads[m.params].kind_of? Thread
196
+ @@watchThreads[m.params].kill
197
+ puts "rmwatch: Killed thread for #{m.params}"
198
+ # @@watchThreads[m.params].join
199
+ # puts "rmwatch: Joined killed thread for #{m.params}"
200
+ @@watchThreads.delete(m.params)
201
+ end
202
+ Thread.critical=false
203
+ m.okay
204
+ end
205
+
206
+ def handle_listrss(m)
207
+ reply = ''
208
+ if @feeds.length == 0
209
+ reply = "No feeds yet."
210
+ else
211
+ @feeds.each { |k,v|
212
+ reply << k + ": " + v + "\n"
213
+ }
214
+ end
215
+ m.reply(reply)
216
+ end
217
+
218
+ def handle_listrsswatch(m)
219
+ reply = ''
220
+ if @watchList.length == 0
221
+ reply = "No watched feeds yet."
222
+ else
223
+ @watchList.each { |url,v|
224
+ reply << url + " for " + v[1] + " (in format: " + (v[0]?v[0]:"default") + ")\n"
225
+ }
226
+ end
227
+ m.reply(reply)
228
+ end
229
+
230
+ def handle_rewatch(m)
231
+ kill_threads
232
+
233
+ # Read watches from list.
234
+ @watchList.each{ |url, d|
235
+ feedFormat = d[0]
236
+ whichChan = d[1]
237
+ watchRss(whichChan, url,feedFormat)
238
+ }
239
+ m.okay
240
+ end
241
+
242
+ def handle_watchrss(m)
243
+ unless m.params
244
+ m.reply "incorrect usage: " + help(m.plugin)
245
+ return
246
+ end
247
+ feed = m.params.scan(/^(\S+)\s+(\S+)$/)
248
+ url = feed[0][0]
249
+ feedFormat = feed[0][1]
250
+ if @watchList.has_key?(url)
251
+ m.reply("But there is already a watch for feed #{url} on chan #{@watchList[url][1]}")
252
+ return
253
+ end
254
+ @watchList[url] = [feedFormat, m.replyto]
255
+ watchRss(m.replyto, url,feedFormat)
256
+ m.okay
257
+ end
258
+
259
+ private
260
+ def watchRss(whichChan, url, feedFormat)
261
+ if @@watchThreads.has_key?(url)
262
+ @bot.say whichChan, "ERROR: watcher thread for #{url} is already running! #{@@watchThreads[url]}"
263
+ return
264
+ end
265
+ @@watchThreads[url] = Thread.new do
266
+ puts 'watchRss thread started.'
267
+ oldItems = []
268
+ firstRun = true
269
+ loop do
270
+ begin # exception
271
+ title = ''
272
+ puts 'Fetching rss feed..'
273
+ newItems = fetchRSS(whichChan, url, title)
274
+ if( newItems.empty? )
275
+ @bot.say whichChan, "Oops - Item is empty"
276
+ break
277
+ end
278
+ puts "Checking if new items are available"
279
+ if (firstRun)
280
+ firstRun = false
281
+ else
282
+ newItems.each do |nItem|
283
+ showItem = true;
284
+ oldItems.each do |oItem|
285
+ if (nItem.to_s == oItem.to_s)
286
+ showItem = false
287
+ end
288
+ end
289
+ if showItem
290
+ puts "showing #{nItem.title}"
291
+ printFormatedRSS(whichChan, nItem,feedFormat)
292
+ else
293
+ puts "not showing #{nItem.title}"
294
+ break
295
+ end
296
+ end
297
+ end
298
+ oldItems = newItems
299
+ rescue Exception
300
+ $stderr.print "IO failed: " + $! + "\n"
301
+ end
302
+
303
+ seconds = 150 + rand(100)
304
+ puts "Thread going to sleep #{seconds} seconds.."
305
+ sleep seconds
306
+ end
307
+ end
308
+ end
309
+
310
+ def printRSSItem(whichChan,item)
311
+ if item.kind_of?(RSS::RDF::Item)
312
+ @bot.say whichChan, shorten(riphtml(item.title.chomp), 20) + " @ " + item.link
313
+ else
314
+ @bot.say whichChan, "#{item.pubDate.to_s.chomp+": " if item.pubDate}#{shorten(riphtml(item.title.chomp), 20)+" :: " if item.title}#{" @ "+item.link.chomp if item.link}"
315
+ end
316
+ end
317
+
318
+ def printFormatedRSS(whichChan,item, type)
319
+ case type
320
+ when 'amarokblog'
321
+ @bot.say whichChan, "::#{item.category.content} just blogged at #{item.link}::"
322
+ @bot.say whichChan, "::#{shorten(riphtml(item.title.chomp), 20)} - #{shorten(riphtml(item.description.chomp),60)}::"
323
+ when 'amarokforum'
324
+ @bot.say whichChan, "::Forum:: #{item.pubDate.to_s.chomp+": " if item.pubDate}#{shorten(riphtml(item.title.chomp), 20)+" :: " if item.title}#{" @ "+item.link.chomp if item.link}"
325
+ when 'mediawiki'
326
+ @bot.say whichChan, "::Wiki:: #{item.title} has been edited by #{item.dc_creator}. #{shorten(riphtml(item.description.split("\n")[0].chomp),60)} #{item.link} ::"
327
+ puts "mediawiki #{item.title}"
328
+ when "gmame"
329
+ @bot.say whichChan, "::amarok-devel:: Message #{item.title} sent by #{item.dc_creator}. #{shorten(riphtml(item.description.split("\n")[0].chomp),60)}::"
330
+ else
331
+ printRSSItem(whichChan,item)
332
+ end
333
+ end
334
+
335
+ def fetchRSS(whichChan, url, title)
336
+ begin
337
+ # Use 60 sec timeout, cause the default is too low
338
+ xml = Utils.http_get(url,60,60)
339
+ rescue URI::InvalidURIError, URI::BadURIError => e
340
+ @bot.say whichChan, "invalid rss feed #{url}"
341
+ return
342
+ end
343
+ puts 'fetched'
344
+ unless xml
345
+ @bot.say whichChan, "reading feed #{url} failed"
346
+ return
347
+ end
348
+
349
+ begin
350
+ ## do validate parse
351
+ rss = RSS::Parser.parse(xml)
352
+ puts 'parsed'
353
+ rescue RSS::InvalidRSSError
354
+ ## do non validate parse for invalid RSS 1.0
355
+ begin
356
+ rss = RSS::Parser.parse(xml, false)
357
+ rescue RSS::Error
358
+ @bot.say whichChan, "parsing rss stream failed, whoops =("
359
+ return
360
+ end
361
+ rescue RSS::Error
362
+ @bot.say whichChan, "parsing rss stream failed, oioi"
363
+ return
364
+ rescue
365
+ @bot.say whichChan, "processing error occured, sorry =("
366
+ return
367
+ end
368
+ items = []
369
+ if rss.nil?
370
+ @bot.say whichChan, "#{m.params} does not include RSS 1.0 or 0.9x/2.0"
371
+ else
372
+ begin
373
+ rss.output_encoding = "euc-jp"
374
+ rescue RSS::UnknownConvertMethod
375
+ @bot.say whichChan, "bah! something went wrong =("
376
+ return
377
+ end
378
+ rss.channel.title ||= "Unknown"
379
+ title.replace(rss.channel.title)
380
+ rss.items.each do |item|
381
+ item.title ||= "Unknown"
382
+ items << item
383
+ end
384
+ end
385
+
386
+ if items.empty?
387
+ @bot.say whichChan, "no items found in the feed, maybe try weed?"
388
+ return
389
+ end
390
+ return items
391
+ end
392
+
393
+ def riphtml(str)
394
+ str.gsub(/<[^>]+>/, '').gsub(/&amp;/,'&').gsub(/&quot;/,'"').gsub(/&lt;/,'<').gsub(/&gt;/,'>').gsub(/&ellip;/,'...').gsub(/&apos;/, "'").gsub("\n",'')
395
+ end
396
+
397
+ def shorten(str, limit)
398
+ if str.length > limit
399
+ str+". " =~ /^(.{#{limit}}[^.!;?]*[.!;?])/mi
400
+ return $1
401
+ end
402
+ str
403
+ end
404
+ end
405
+
406
+ plugin = RSSFeedsPlugin.new
407
+ plugin.register("rss")
408
+ plugin.register("addrss")
409
+ plugin.register("rmrss")
410
+ plugin.register("listrss")
411
+ plugin.register("rewatch")
412
+ plugin.register("watchrss")
413
+ plugin.register("listwatches")
414
+ plugin.register("rmwatch")