mod_spox 0.1.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/CHANGELOG +36 -0
  2. data/INSTALL +2 -2
  3. data/README +0 -1
  4. data/bin/mod_spox +51 -12
  5. data/data/mod_spox/extras/AOLSpeak.rb +5 -18
  6. data/data/mod_spox/extras/AutoKick.rb +44 -23
  7. data/data/mod_spox/extras/AutoMode.rb +2 -5
  8. data/data/mod_spox/extras/AutoRejoin.rb +21 -0
  9. data/data/mod_spox/extras/Bouncer.rb +10 -10
  10. data/data/mod_spox/extras/Bytes.rb +12 -0
  11. data/data/mod_spox/extras/Confess.rb +131 -52
  12. data/data/mod_spox/extras/DCC.rb +189 -0
  13. data/data/mod_spox/extras/DevWatch.rb +32 -33
  14. data/data/mod_spox/extras/FloodKicker.rb +129 -0
  15. data/data/mod_spox/extras/GoogleIt.rb +13 -0
  16. data/data/mod_spox/extras/Headers.rb +31 -4
  17. data/data/mod_spox/extras/Karma.rb +103 -49
  18. data/data/mod_spox/extras/Logger.rb +45 -30
  19. data/data/mod_spox/extras/LolSpeak.rb +1 -1
  20. data/data/mod_spox/extras/NickServ.rb +83 -0
  21. data/data/mod_spox/extras/PhpCli.rb +12 -15
  22. data/data/mod_spox/extras/PhpFuncLookup.rb +57 -25
  23. data/data/mod_spox/extras/Quotes.rb +5 -4
  24. data/data/mod_spox/extras/RegexTracker.rb +160 -0
  25. data/data/mod_spox/extras/Roulette.rb +22 -23
  26. data/data/mod_spox/extras/Search.rb +3 -2
  27. data/data/mod_spox/extras/Slashdot.rb +35 -0
  28. data/data/mod_spox/extras/Topten.rb +5 -5
  29. data/data/mod_spox/extras/TracTicket.rb +68 -0
  30. data/data/mod_spox/extras/Translate.rb +69 -30
  31. data/data/mod_spox/extras/Twitter.rb +372 -0
  32. data/data/mod_spox/extras/UrbanDictionary.rb +21 -12
  33. data/data/mod_spox/extras/Weather.rb +1 -1
  34. data/data/mod_spox/plugins/Authenticator.rb +63 -30
  35. data/data/mod_spox/plugins/Banner.rb +164 -151
  36. data/data/mod_spox/plugins/Helper.rb +18 -7
  37. data/data/mod_spox/plugins/PluginLoader.rb +46 -22
  38. data/data/mod_spox/plugins/PoolConfig.rb +52 -0
  39. data/data/mod_spox/plugins/Quitter.rb +1 -1
  40. data/data/mod_spox/plugins/Status.rb +28 -0
  41. data/lib/mod_spox/Action.rb +20 -3
  42. data/lib/mod_spox/BaseConfig.rb +1 -0
  43. data/lib/mod_spox/Bot.rb +98 -75
  44. data/lib/mod_spox/BotConfig.rb +14 -6
  45. data/lib/mod_spox/ConfigurationWizard.rb +94 -105
  46. data/lib/mod_spox/Database.rb +33 -13
  47. data/lib/mod_spox/Helpers.rb +67 -38
  48. data/lib/mod_spox/Loader.rb +25 -5
  49. data/lib/mod_spox/Logger.rb +20 -62
  50. data/lib/mod_spox/MessageFactory.rb +34 -25
  51. data/lib/mod_spox/Monitors.rb +5 -0
  52. data/lib/mod_spox/Pipeline.rb +40 -51
  53. data/lib/mod_spox/Plugin.rb +40 -9
  54. data/lib/mod_spox/PluginManager.rb +46 -38
  55. data/lib/mod_spox/Pool.rb +129 -143
  56. data/lib/mod_spox/Socket.rb +41 -50
  57. data/lib/mod_spox/Sockets.rb +211 -0
  58. data/lib/mod_spox/Timer.rb +86 -69
  59. data/lib/mod_spox/handlers/BadNick.rb +1 -1
  60. data/lib/mod_spox/handlers/Created.rb +1 -1
  61. data/lib/mod_spox/handlers/Handler.rb +9 -0
  62. data/lib/mod_spox/handlers/Invite.rb +1 -1
  63. data/lib/mod_spox/handlers/Join.rb +2 -2
  64. data/lib/mod_spox/handlers/Kick.rb +1 -1
  65. data/lib/mod_spox/handlers/LuserChannels.rb +1 -1
  66. data/lib/mod_spox/handlers/LuserOp.rb +1 -1
  67. data/lib/mod_spox/handlers/LuserUnknown.rb +1 -1
  68. data/lib/mod_spox/handlers/Mode.rb +2 -2
  69. data/lib/mod_spox/handlers/MyInfo.rb +1 -1
  70. data/lib/mod_spox/handlers/Names.rb +1 -1
  71. data/lib/mod_spox/handlers/Nick.rb +20 -3
  72. data/lib/mod_spox/handlers/NickInUse.rb +3 -3
  73. data/lib/mod_spox/handlers/Notice.rb +5 -15
  74. data/lib/mod_spox/handlers/Part.rb +1 -1
  75. data/lib/mod_spox/handlers/Ping.rb +1 -1
  76. data/lib/mod_spox/handlers/Pong.rb +1 -1
  77. data/lib/mod_spox/handlers/Privmsg.rb +2 -2
  78. data/lib/mod_spox/handlers/Quit.rb +1 -1
  79. data/lib/mod_spox/handlers/Topic.rb +2 -1
  80. data/lib/mod_spox/handlers/Welcome.rb +3 -3
  81. data/lib/mod_spox/handlers/Who.rb +9 -7
  82. data/lib/mod_spox/handlers/Whois.rb +29 -16
  83. data/lib/mod_spox/handlers/YourHost.rb +1 -1
  84. data/lib/mod_spox/messages/incoming/Privmsg.rb +38 -19
  85. data/lib/mod_spox/messages/internal/DCCListener.rb +12 -0
  86. data/lib/mod_spox/messages/internal/DCCRequest.rb +12 -0
  87. data/lib/mod_spox/messages/internal/DCCSocket.rb +19 -0
  88. data/lib/mod_spox/messages/internal/StatusRequest.rb +2 -1
  89. data/lib/mod_spox/messages/outgoing/Privmsg.rb +21 -5
  90. data/lib/mod_spox/migrations/001_initialize_models.rb +115 -0
  91. data/lib/mod_spox/models/Auth.rb +24 -16
  92. data/lib/mod_spox/models/AuthGroup.rb +4 -3
  93. data/lib/mod_spox/models/Channel.rb +20 -12
  94. data/lib/mod_spox/models/ChannelMode.rb +2 -2
  95. data/lib/mod_spox/models/Config.rb +11 -3
  96. data/lib/mod_spox/models/Group.rb +6 -1
  97. data/lib/mod_spox/models/Nick.rb +93 -33
  98. data/lib/mod_spox/models/NickChannel.rb +8 -6
  99. data/lib/mod_spox/models/NickGroup.rb +16 -0
  100. data/lib/mod_spox/models/NickMode.rb +3 -3
  101. data/lib/mod_spox/models/Server.rb +6 -2
  102. data/lib/mod_spox/models/Setting.rb +12 -6
  103. data/lib/mod_spox/models/Signature.rb +7 -13
  104. data/lib/mod_spox/models/Trigger.rb +1 -1
  105. metadata +125 -100
@@ -1,7 +1,7 @@
1
1
  class Roulette < ModSpox::Plugin
2
2
 
3
3
  include Models
4
-
4
+
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
7
  Signature.find_or_create(:signature => 'roulette', :plugin => name, :method => 'roulette', :requirement => 'public')
@@ -15,7 +15,7 @@ class Roulette < ModSpox::Plugin
15
15
  @banner = nil
16
16
  @pipeline.hook(self, :get_banner, :Internal_PluginResponse)
17
17
  end
18
-
18
+
19
19
  # message:: ModSpox::Messages::Incoming::Privmsg
20
20
  # Display chamber statistics
21
21
  def chambers(m, p)
@@ -32,13 +32,13 @@ class Roulette < ModSpox::Plugin
32
32
  reply m.replyto, "\2Error:\2 No games found"
33
33
  end
34
34
  end
35
-
35
+
36
36
  # message:: ModSpox::Messages::Internal::PluginResponse
37
37
  # Get the banner plugin
38
38
  def get_banner(message)
39
39
  @banner = message.plugin if message.found?
40
40
  end
41
-
41
+
42
42
  # message:: ModSpox::Messages::Incoming::Privmsg
43
43
  # params:: empty
44
44
  # Play roulette
@@ -46,7 +46,7 @@ class Roulette < ModSpox::Plugin
46
46
  return unless message.is_public?
47
47
  do_shot(message.source, message.target)
48
48
  end
49
-
49
+
50
50
  # message:: ModSpox::Messages::Incoming::Privmsg
51
51
  # params:: empty
52
52
  # Kill self
@@ -54,7 +54,7 @@ class Roulette < ModSpox::Plugin
54
54
  return unless message.is_public?
55
55
  do_suicide(message.source, message.target)
56
56
  end
57
-
57
+
58
58
  # message:: ModSpox::Messages::Incoming::Privmsg
59
59
  # params:: nick
60
60
  # Shoot other person playing current game
@@ -76,7 +76,6 @@ class Roulette < ModSpox::Plugin
76
76
  return unless message.is_public?
77
77
  ds = Database.db[:infos].left_outer_join(:games, :id => :game_id)
78
78
  ds.select!(:nick_id, :COUNT[:win] => :wins).where!(:channel_id => message.target.pk, :win => true).group!(:nick_id).reverse_order!(:wins).limit!(10)
79
- Logger.log(ds.sql)
80
79
  ids = ds.map(:nick_id)
81
80
  top = []
82
81
  ids.each do |id|
@@ -106,9 +105,9 @@ class Roulette < ModSpox::Plugin
106
105
  end
107
106
  reply(message.replyto, "\2Roulette stats #{nick.nick}:\2 #{win_loss_ratio(nick, message.target)}% survival rate. Has won #{games_won(nick, message.target)} games and lost #{games_lost(nick, message.target)} games, taking a total of #{total_shots(nick, message.target)} shots.")
108
107
  end
109
-
108
+
110
109
  private
111
-
110
+
112
111
  # nick:: ModSpox::Models::Nick
113
112
  # channel:: ModSpox::Models::Channel
114
113
  # Report win/loss ratio for nick
@@ -129,7 +128,7 @@ class Roulette < ModSpox::Plugin
129
128
  def games_won(nick, channel)
130
129
  Info.left_outer_join(:games, :id => :game_id).filter('nick_id = ?', nick.pk).filter('channel_id = ?', channel.pk).filter('win = ?', true).size
131
130
  end
132
-
131
+
133
132
  # nick:: ModSpox::Models::Nick
134
133
  # channel:: ModSpox::Models::Channel
135
134
  # Return number of games nick has lost
@@ -155,7 +154,7 @@ class Roulette < ModSpox::Plugin
155
154
 
156
155
  # nick:: ModSpox::Models::Nick
157
156
  # channel:: ModSpox::Models::Channel
158
- # Fire shot
157
+ # Fire shot
159
158
  def do_shot(nick, channel)
160
159
  begin
161
160
  shot(nick, channel)
@@ -165,7 +164,7 @@ class Roulette < ModSpox::Plugin
165
164
  kill_nick(nick, channel)
166
165
  end
167
166
  end
168
-
167
+
169
168
  # nick:: ModSpox::Models::Nick
170
169
  # channel:: ModSpox::Models::Channel
171
170
  # Commit suicide
@@ -179,7 +178,7 @@ class Roulette < ModSpox::Plugin
179
178
  kill_nick(nick, channel)
180
179
  end
181
180
  end
182
-
181
+
183
182
  def kill_nick(nick, channel)
184
183
  unless(@banner.nil?)
185
184
  begin
@@ -188,7 +187,7 @@ class Roulette < ModSpox::Plugin
188
187
  reply(channel, "#{nick.nick}: *BANG*")
189
188
  rescue Object => boom
190
189
  reply(channel, "#{nick.nick}: *BANG*")
191
- Logger.log("Error: Roulette ban generated an unexpected error: #{boom}")
190
+ Logger.warn("Error: Roulette ban generated an unexpected error: #{boom}")
192
191
  end
193
192
  else
194
193
  reply(channel, "#{nick.nick}: *BANG*")
@@ -207,7 +206,7 @@ class Roulette < ModSpox::Plugin
207
206
  end
208
207
  return game
209
208
  end
210
-
209
+
211
210
  # nick:: ModSpox::Models::Nick
212
211
  # channel:: ModSpox::Models::Channel
213
212
  # Process shot
@@ -218,7 +217,7 @@ class Roulette < ModSpox::Plugin
218
217
  cur_game.update_with_params(:shots => cur_game.shots - 1)
219
218
  raise Bullet.new(cur_game) if cur_game.shots < 1
220
219
  end
221
-
220
+
222
221
  # nick:: ModSpox::Models::Nick
223
222
  # game:: Game
224
223
  # Return number of games nick has won
@@ -227,7 +226,7 @@ class Roulette < ModSpox::Plugin
227
226
  info.update_with_params(:win => true) unless info.nick_id == nick.pk
228
227
  end
229
228
  end
230
-
229
+
231
230
  class Game < Sequel::Model
232
231
  set_schema do
233
232
  primary_key :id
@@ -236,16 +235,16 @@ class Roulette < ModSpox::Plugin
236
235
  integer :chamber, :null => false, :default => 1
237
236
  foreign_key :channel_id, :null => false, :table => :channels
238
237
  end
239
-
238
+
240
239
  before_create do
241
240
  self.stamp = Time.now
242
241
  end
243
-
242
+
244
243
  def channel
245
244
  Models::Channel[channel_id]
246
245
  end
247
246
  end
248
-
247
+
249
248
  class Info < Sequel::Model
250
249
  set_schema do
251
250
  primary_key :id
@@ -254,16 +253,16 @@ class Roulette < ModSpox::Plugin
254
253
  foreign_key :nick_id, :null => false, :table => :nicks
255
254
  foreign_key :game_id, :null => false, :table => :games
256
255
  end
257
-
256
+
258
257
  def nick
259
258
  Models::Nick[nick_id]
260
259
  end
261
-
260
+
262
261
  def game
263
262
  Models::Game[game_id]
264
263
  end
265
264
  end
266
-
265
+
267
266
  class Bullet < Exception
268
267
  attr_reader :game
269
268
  def initialize(game)
@@ -8,12 +8,12 @@ class Search < ModSpox::Plugin
8
8
  super(pipeline)
9
9
  Models::Signature.find_or_create(:signature => 'search (\d+)? ?(.+)', :plugin => name, :method => 'search', :description => 'Search the internet').params = [:number, :terms]
10
10
  end
11
-
11
+
12
12
  def search(message, params)
13
13
  limit = params[:number] ? params[:number].to_i : 1
14
14
  limit = limit > 5 || limit < 1 ? 1 : limit
15
15
  begin
16
- resp = Net::HTTP.new('www.scroogle.org', 80).request_get("/cgi-bin/nbbw.cgi?Gw=#{CGI::escape(params[:terms])}", nil)
16
+ resp = Net::HTTP.new('www.scroogle.org', 80).request_get("/cgi-bin/nbbw.cgi?Gw=#{CGI::escape(params[:terms])}")
17
17
  resp.value
18
18
  page = resp.body
19
19
  results = []
@@ -29,6 +29,7 @@ class Search < ModSpox::Plugin
29
29
  reply message.replyto, output
30
30
  rescue Object => boom
31
31
  @pipeline << Privmsg.new(message.replyto, "Failed to find any results for: #{params[:terms]} Reason: #{boom}")
32
+ Logger.warn("Error: #{boom}\n#{boom.backtrace.join("\n")}")
32
33
  end
33
34
  end
34
35
  end
@@ -0,0 +1,35 @@
1
+ require 'rexml/document'
2
+ require 'open-uri'
3
+
4
+ class Slashdot < ModSpox::Plugin
5
+
6
+ def initialize(pipeline)
7
+ begin
8
+ require 'htmlentities'
9
+ rescue Object => boom
10
+ Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
11
+ raise Exceptions::BotException.new("Missing required HTMLEntities library")
12
+ end
13
+ super
14
+ add_sig(:sig => '(slashdot|\/\.) ?(\d+)?', :method => 'show_slashdot', :desc => 'Slashdot headlines', :params => [:trig, :num])
15
+ @coder = HTMLEntities.new
16
+ end
17
+
18
+ def show_slashdot(message, params)
19
+ src = open('http://rss.slashdot.org/Slashdot/slashdot')
20
+ doc = REXML::Document.new(src.read)
21
+ num = params[:num].nil? || params[:num].to_i < 1 ? 1 : params[:num].to_i
22
+ num = 5 if num > 5
23
+ output = []
24
+ doc.elements.each('rdf:RDF/item') do |item|
25
+ num -= 1
26
+ title = CGI::unescapeHTML(item.elements['title'].text)
27
+ title = title.gsub(/<.+?>/, ' ').gsub(/[\r\n]/, '').gsub(/\s+/, ' ')
28
+ title = @coder.decode(title)
29
+ output << "\2/.\2 #{title.strip} \2->\2 #{Helpers.tinyurl(item.elements['link'].text)}"
30
+ break if num < 1
31
+ end
32
+ reply message.replyto, output
33
+ end
34
+
35
+ end
@@ -11,7 +11,7 @@ class Topten < ModSpox::Plugin
11
11
  :description => 'Show topten from given date', :requirement => 'public').params = [:date]
12
12
  Signature.find_or_create(:signature => 'stats ?(\S+)?', :plugin => name, :method => 'stats', :description => 'Show stats on nick',
13
13
  :requirement => 'public').params = [:nick]
14
- Signature.find_or_create(:signature => 'stats lifetime? (\S+)?', :plugin => name, :method => 'life_stats',
14
+ Signature.find_or_create(:signature => 'stats lifetime (\S+)?', :plugin => name, :method => 'life_stats',
15
15
  :description => 'Show stat totals for given nick', :requirement => 'public').params = [:nick]
16
16
  @pipeline.hook(self, :log_stats, :Incoming_Privmsg)
17
17
  end
@@ -62,9 +62,9 @@ class Topten < ModSpox::Plugin
62
62
  def life_stats(m, p)
63
63
  nick = p[:nick] ? Nick.locate(p[:nick], false) : m.source
64
64
  if(nick)
65
- result = ChatStat.group(:nick_id).select(:SUM[:bytes] => :tbytes, :SUM[:words] => :twords, :SUM[:questions] => :tquestions).filter(:nick_id => nick.pk).first
66
- bytes = (result.tbytes > 1023) ? "#{sprintf('%.2f', (result.tbytes / 1024.0))}kb" : "#{result.tbytes}b"
67
- reply m.replyto, "#{nick.nick} (total): #{bytes} logged, #{result.twords} words spoken and #{result.tquestions} questions asked"
65
+ result = ChatStat.group(:nick_id).select(:SUM[:bytes].as(:tbytes), :SUM[:words].as(:twords), :SUM[:questions].as(:tquestions)).filter(:nick_id => nick.pk).first
66
+ bytes = (result[:tbytes] > 1023) ? "#{sprintf('%.2f', (result[:tbytes] / 1024.0))}kb" : "#{result[:tbytes]}b"
67
+ reply m.replyto, "#{nick.nick} (total): #{bytes} logged, #{result[:twords]} words spoken and #{result[:tquestions]} questions asked"
68
68
  else
69
69
  reply m.replyto, "\2Error:\2 Failed to find #{p[:nick]}"
70
70
  end
@@ -76,7 +76,7 @@ class Topten < ModSpox::Plugin
76
76
  stat = ChatStat.find_or_create(:nick_id => m.source.pk, :channel_id => m.target.pk, :daykey => key)
77
77
  words = m.message.scan(/([^ ]+ |[^ ]$)/).size
78
78
  bytes = m.message.gsub(/[^a-zA-Z0-9`\~\!@#\$%\^&\*\(\)_\+\[\]\}\{;:'"\/\?\.>,<\\|\-=]/, '').length
79
- questions = m.message.scan(/.+?(\? |\?$)/).size
79
+ questions = m.message.scan(/.+?(!?\?!? |!?\?!?$)/).size
80
80
  stat.words += words
81
81
  stat.bytes += bytes
82
82
  stat.questions += questions
@@ -0,0 +1,68 @@
1
+ require 'net/http'
2
+
3
+ class TracTicket < ModSpox::Plugin
4
+
5
+ def initialize(pipeline)
6
+ super
7
+ admin = Group.find_or_create(:name => 'admin')
8
+ add_sig(:sig => 'ticket (defect|enhancement|task) (.+?)( # (.+))?', :method => :add_ticket,
9
+ :desc => 'Add new ticket to trac ticket tracker', :params => [:type, :short, :trash, :long])
10
+ add_sig(:sig => 'ticket trac( (\S+))?', :method => :trac_location, :group => admin,
11
+ :desc => 'Show/set trac site', :params => [:trash, :site])
12
+ add_sig(:sig => 'ticket site', :method => :trac_location, :desc => 'Show trac site')
13
+ @site = Config[:trac]
14
+ end
15
+
16
+ def trac_location(message, params)
17
+ if(params[:site])
18
+ site = Config.find_or_create(:name => 'trac')
19
+ site.value = params[:site]
20
+ site.save
21
+ @site = params[:site]
22
+ reply message.replyto, "\2Trac Update:\2 Location of trac system has been updated: #{params[:site]}"
23
+ else
24
+ output = "\2Error:\2 Trac site has not yet been set"
25
+ unless(@site.nil?)
26
+ output = "\2Trac location:\2 #{@site}"
27
+ end
28
+ reply message.replyto, output
29
+ end
30
+ end
31
+
32
+ def add_ticket(message, params)
33
+ if(@site =~ /(http:\/\/)?([^\/:]+)(:\d+)?(.+)$/)
34
+ addr = $2
35
+ port = $3
36
+ path = $4
37
+ port = port.nil? ? 80 : port.gsub(/:/, '').to_i
38
+ con = Net::HTTP.new(addr, port)
39
+ begin
40
+ cookie, fid = get_form_info(con, path)
41
+ long = params[:long] ? params[:long] : params[:short]
42
+ headers = {
43
+ 'Cookie' => cookie,
44
+ 'Referer' => @site,
45
+ 'Content-Type' => 'application/x-www-form-urlencoded'
46
+ }
47
+ data = "reporter=#{URI.escape(message.source.nick)}&summary=#{URI.escape(params[:short])}&description=#{URI.escape(long)}&type=#{URI.escape(params[:type])}&action=create&status=new&priority=minor&__FORM_TOKEN=#{URI.escape(fid)}"
48
+ resp, data = con.post(path, data, headers)
49
+ reply message.replyto, 'Ticket was successfully added to tracker'
50
+ rescue Object => boom
51
+ reply message.replyto, "\2Error:\2 Encountered unexpected error while submitting ticket: #{boom}"
52
+ end
53
+ else
54
+ reply message.replyto, "\2Error:\2 Trac location has not been set"
55
+ end
56
+ end
57
+
58
+ def get_form_info(con, path)
59
+ res, content = con.get(path, {})
60
+ cookie = res['set-cookie']
61
+ if(content =~ /name="__FORM_TOKEN" value="(.+?)"/i)
62
+ return cookie, $1
63
+ else
64
+ raise 'Failed to locate proper identification'
65
+ end
66
+ end
67
+
68
+ end
@@ -4,37 +4,64 @@ class Translate < ModSpox::Plugin
4
4
 
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
+ begin
8
+ require 'htmlentities'
9
+ rescue Object => boom
10
+ Logger.warn('Error: This plugin requires the HTMLEntities gem. Please install and reload plugin.')
11
+ raise Exceptions::BotException.new("Missing required HTMLEntities library")
12
+ end
7
13
  Signature.find_or_create(:signature => 'translate ([a-z]{2}\|[a-z]{2}) (.+)', :plugin => name, :method => 'translate',
8
14
  :description => 'Translate text').params = [:lang, :text]
9
15
  Signature.find_or_create(:signature => 'autotranslate add ([a-z]{2}) (\S+)', :plugin => name, :method => 'auto_add',
10
16
  :description => 'Add a nick to the autotranslate service').params = [:lang, :nick]
11
17
  Signature.find_or_create(:signature => 'autotranslate remove (\S+)', :plugin => name, :method => 'auto_remove',
12
18
  :description => 'Remove a nick from the autotranslate service').params = [:nick]
19
+ add_sig(:sig => 'translate languages', :method => 'langs', :description => 'Show available languages')
20
+ @pipeline.hook(self, :listener, :Incoming_Privmsg)
13
21
  @watchers = {}
14
22
  @cache = {}
23
+ @coder = HTMLEntities.new
24
+ @allowed = {'zh'=>'Chinese-simplified','zt'=>'Chinese-traditional','en'=>'English','nl'=>'Dutch',
25
+ 'fr'=>'French','de'=>'German','el'=>'Greek','it'=>'Italian','ja'=>'Japanese',
26
+ 'ko'=>'Korean','pt'=>'Portuguese','ru'=>'Russian','es'=>'Spanish'}
27
+ @allowed_trans = ['zh_en','zh_zt', 'zt_en', 'zt_zh', 'en_zh', 'en_zt', 'en_nl', 'en_fr', 'en_de',
28
+ 'en_el', 'en_it', 'en_ja', 'en_ko', 'en_pt', 'en_ru', 'en_es', 'nl_en', 'nl_fr',
29
+ 'fr_nl', 'fr_en', 'fr_de', 'fr_el', 'fr_it', 'fr_pt', 'fr_es', 'de_en', 'de_fr',
30
+ 'el_en', 'el_fr', 'it_en', 'it_fr', 'ja_en', 'ko_en', 'pt_en', 'pt_fr', 'ru_en',
31
+ 'es_en', 'es_fr']
32
+ end
33
+
34
+ def langs(m, params)
35
+ output = ['Available languages for translate:']
36
+ s = []
37
+ @allowed.each_pair{|k,v| s << "#{v} (\2#{k}\2)"}
38
+ output << s.join(', ')
39
+ reply m.replyto, output
15
40
  end
16
41
 
17
42
  def auto_add(message, params)
18
43
  return unless message.is_public?
19
- nick = Helpers.find_model(params[:nick], false)
20
- if(nick && nick.channels.include?(message.target))
21
- @watchers[message.target.pk] = {} unless @watchers.has_key?(message.target.pk)
22
- @watchers[message.target.pk][nick.pk] = params[:lang] unless @watchers[message.target.pk].has_key?(nick.pk)
23
- hook
24
- reply message.replyto, "#{params[:nick]} is now being tracked for auto translation"
44
+ if(@allowed_trans.include?("en_#{params[:lang]}") && @allowed_trans.include?("#{params[:lang]}_en"))
45
+ nick = Helpers.find_model(params[:nick], false)
46
+ if(nick && nick.channels.include?(message.target))
47
+ @watchers[message.target.pk] = {} unless @watchers.has_key?(message.target.pk)
48
+ @watchers[message.target.pk][nick.pk] = params[:lang] unless @watchers[message.target.pk].has_key?(nick.pk)
49
+ reply message.replyto, "#{params[:nick]} is now being tracked for auto translation"
50
+ else
51
+ reply message.replyto, "\2Error:\2 Failed to locate #{params[:nick]}"
52
+ end
25
53
  else
26
- reply message.replyto, "\2Error:\2 Failed to locate #{params[:nick]}"
54
+ reply message.replyt, "\2Error:\2 Unsupported bi-directional translation"
27
55
  end
28
56
  end
29
57
 
30
58
  def auto_remove(message, params)
31
59
  return unless message.is_public?
32
- nick = Helpers.find_model(params[:nick], false)
60
+ nick = Models::Nick.locate(params[:nick], false)
33
61
  if(nick)
34
62
  if(@watchers.has_key?(message.target.pk))
35
63
  @watchers[message.target.pk].delete(nick.pk) if @watchers[message.target.pk].has_key?(nick.pk)
36
64
  @watchers.delete(message.target.pk) if @watchers[message.target.pk].empty?
37
- hook
38
65
  reply message.replyto, "#{params[:nick]} is no longer being tracked for auto translation"
39
66
  else
40
67
  reply message.replyto, "No one is currently being tracked"
@@ -45,15 +72,20 @@ class Translate < ModSpox::Plugin
45
72
  end
46
73
 
47
74
  def translate(message, params)
48
- reply message.replyto, "\2Translation:\2 #{do_translation(params[:lang], params[:text])}"
75
+ begin
76
+ reply message.replyto, "\2Translation:\2 #{do_translation(params[:lang], params[:text])}"
77
+ rescue Object => boom
78
+ reply message.replyto, "\2Error:\2 #{boom}"
79
+ end
49
80
  end
50
81
 
51
82
  def listener(message)
52
83
  if(message.is_public? && @watchers.has_key?(message.target.pk))
53
84
  if(@watchers[message.target.pk].has_key?(message.source.pk))
54
- reply message.replyto, "\2Translation (#{message.source.nick}):\2 #{do_translation("#{@watchers[message.target.pk][message.source.pk]}en", message.message)}"
85
+ trans_message = do_translation("#{@watchers[message.target.pk][message.source.pk]}en", message.message)
86
+ reply message.replyto, "\2Translation (#{message.source.nick}):\2 #{trans_message}" unless trans_message == message.message
55
87
  elsif(message.message =~ /^(\S+)[:,]/)
56
- Logger.log("Matched a nick: #{$1}")
88
+ Logger.info("Translate matched a followed nick: #{$1}")
57
89
  nick = Helpers.find_model($1, false)
58
90
  return unless nick
59
91
  if(@watchers[message.target.pk].has_key?(nick.pk))
@@ -66,29 +98,36 @@ class Translate < ModSpox::Plugin
66
98
  private
67
99
 
68
100
  def do_translation(langs, text)
101
+ raise 'Unsupported language combination for translation' unless @allowed_trans.include?(langs.gsub(/\|/, '_'))
69
102
  if(@cache.has_key?(langs) && @cache[langs].has_key?(text))
70
103
  return @cache[langs][text]
71
104
  end
72
- connection = Net::HTTP.new('babelfish.altavista.com', 80)
73
- response = connection.request_get("/tr?tt=urltext&trtext=#{CGI::escape(text)}&lp=#{langs.gsub(/\|/, '_')}", nil)
74
- response.value()
75
- if response.body.gsub(/[\r\n]/, '') =~ /<div style=padding:10px;>(.+?)<\/div>/
76
- result = $1
77
- if(text.length < 15)
78
- @cache[langs] = {} unless @cache.has_key?(langs)
79
- @cache[langs][text] = result
105
+ content = Net::HTTP.post_form(URI.parse('http://babelfish.yahoo.com/translate_txt'), {
106
+ 'ei' => 'UTF-8',
107
+ 'doit' => 'done',
108
+ 'fr' => 'bf-home',
109
+ 'intl' => '1',
110
+ 'tt' => 'urltext',
111
+ 'trtext' => text,
112
+ 'lp' => langs.gsub(/\|/, '_'),
113
+ 'btnTrTxt' => 'Translate'
114
+ }).body
115
+ if(content)
116
+ if(content =~ /<div id="result">(.+?)<input/im)
117
+ tr = $1
118
+ tr.gsub!(/<.+?>/, '')
119
+ tr.gsub!(/[\r\n]/, ' ')
120
+ tr.gsub!(/\s+/, ' ')
121
+ if(text.length < 15)
122
+ @cache[langs] = {} unless @cache.has_key?(langs)
123
+ @cache[langs][text] = tr
124
+ end
125
+ return @coder.decode(tr).strip
126
+ else
127
+ raise 'Failed to locate translation'
80
128
  end
81
- return result.gsub(/\s+/, ' ')
82
- else
83
- raise "Failed to extract translation"
84
- end
85
- end
86
-
87
- def hook
88
- if(@watchers.size > 0)
89
- @pipeline.hook(self, :listener, :Incoming_Privmsg)
90
129
  else
91
- @pipeline.unhook(self, :listener, :Incoming_Privmsg)
130
+ raise "Failed to receive result from server"
92
131
  end
93
132
  end
94
133