]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - data/rbot/plugins/url.rb
fix: TCPSocked.gethostbyname is deprecated
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / url.rb
index 8d12f303f62cc8c3792fcffcf81879cd972e8544..934144cc6a0aadb5097a01747e9928e2c68da046 100644 (file)
@@ -3,6 +3,8 @@
 #
 # :title: Url plugin
 
+require 'socket'
+
 define_structure :Url, :channel, :nick, :time, :url, :info
 
 class UrlPlugin < Plugin
@@ -15,12 +17,24 @@ class UrlPlugin < Plugin
   Config.register Config::IntegerValue.new('url.display_link_info',
     :default => 0,
     :desc => "Get the title of links pasted to the channel and display it (also tells if the link is broken or the site is down). Do it for at most this many links per line (set to 0 to disable)")
+  Config.register Config::BooleanValue.new('url.auto_shorten',
+    :default => false,
+    :desc => "Automatically spit out shortened URLs when they're seen. Check shortenurls for config options")
+  Config.register Config::IntegerValue.new('url.auto_shorten_min_length',
+    :default => 48,
+    :desc => "Minimum length of URL to auto-shorten.  Only has an effect when url.auto_shorten is true.")
   Config.register Config::BooleanValue.new('url.titles_only',
     :default => false,
     :desc => "Only show info for links that have <title> tags (in other words, don't display info for jpegs, mpegs, etc.)")
   Config.register Config::BooleanValue.new('url.first_par',
     :default => false,
     :desc => "Also try to get the first paragraph of a web page")
+  Config.register Config::IntegerValue.new('url.first_par_length',
+    :default => 150,
+    :desc => "The max length of the first paragraph")
+  Config.register Config::ArrayValue.new('url.first_par_whitelist',
+    :default => ['twitter.com'],
+    :desc => "List of url patterns to show the content for.")
   Config.register Config::BooleanValue.new('url.info_on_list',
     :default => false,
     :desc => "Show link info when listing/searching for urls")
@@ -31,6 +45,9 @@ class UrlPlugin < Plugin
   Config.register Config::ArrayValue.new('url.only_on_channels',
     :desc => "Show link info only on these channels",
     :default => [])
+  Config.register Config::ArrayValue.new('url.ignore',
+    :desc => "Don't show link info for urls from users represented as hostmasks on this list. Useful for ignoring other bots, for example.",
+    :default => [])
 
   def initialize
     super
@@ -39,6 +56,8 @@ class UrlPlugin < Plugin
       @bot.config.items[:'url.display_link_info'].set_string(@bot.config['url.display_link_info'].to_s)
     end
     reset_no_info_hosts
+    self.filter_group = :htmlinfo
+    load_filters
   end
 
   def reset_no_info_hosts
@@ -61,8 +80,7 @@ class UrlPlugin < Plugin
 
     # also check the ip, the canonical name and the aliases
     begin
-      checks = TCPSocket.gethostbyname(url.host)
-      checks.delete_at(-2)
+      checks = Addrinfo.getaddrinfo(url.host, nil).map { |addr| addr.ip_address }
     rescue => e
       return "Unable to retrieve info for #{url.host}: #{e.message}"
     end
@@ -71,7 +89,7 @@ class UrlPlugin < Plugin
     checks.flatten!
 
     unless checks.grep(@no_info_hosts).empty?
-      return "Sorry, info retrieval for #{url.host} (#{checks.first}) is disabled"
+      return ( opts[:always_reply] ? "Sorry, info retrieval for #{url.host} (#{checks.first}) is disabled" : false )
     end
 
     logopts = opts.dup
@@ -82,14 +100,30 @@ class UrlPlugin < Plugin
     begin
       debug "+ getting info for #{url.request_uri}"
       info = @bot.filter(:htmlinfo, url)
-      debug info
+      logopts[:htmlinfo] = info
       resp = info[:headers]
 
       logopts[:title] = title = info[:title]
 
       if info[:content]
         logopts[:extra] = info[:content]
-        extra << "#{Bold}text#{Bold}: #{info[:content]}" if @bot.config['url.first_par']
+
+        max_length = @bot.config['url.first_par_length']
+
+        whitelist = @bot.config['url.first_par_whitelist']
+        content = nil
+        if whitelist.length > 0
+          whitelist.each do |pattern|
+            if Regexp.new(pattern, Regexp::IGNORECASE).match(url.to_s)
+              content = info[:content][0...max_length]
+              break
+            end
+          end
+        else
+          content = info[:content][0...max_length]
+        end
+
+        extra << "#{Bold}text#{Bold}: #{content}" if @bot.config['url.first_par'] and content
       else
         logopts[:extra] = String.new
         logopts[:extra] << "Content Type: #{resp['content-type']}"
@@ -125,15 +159,20 @@ class UrlPlugin < Plugin
   def handle_urls(m, params={})
     opts = {
       :display_info => @bot.config['url.display_link_info'],
-      :channels => @bot.config['url.only_on_channels']
+      :channels => @bot.config['url.only_on_channels'],
+      :ignore => @bot.config['url.ignore']
     }.merge params
     urls = opts[:urls]
     display_info= opts[:display_info]
     channels = opts[:channels]
+    ignore = opts[:ignore]
+
     unless channels.empty?
       return unless channels.map { |c| c.downcase }.include?(m.channel.downcase)
     end
 
+    ignore.each { |u| return if m.source.matches?(u) }
+
     return if urls.empty?
     debug "found urls #{urls.inspect}"
     list = m.public? ? @registry[m.target] : nil
@@ -142,11 +181,17 @@ class UrlPlugin < Plugin
     urls.each do |urlstr|
       debug "working on #{urlstr}"
       next unless urlstr =~ /^https?:\/\/./
+      if @bot.config['url.auto_shorten'] == true and
+         urlstr.length >= @bot.config['url.auto_shorten_min_length']
+        m.reply(bot.plugins['shortenurls'].shorten(nil, {:url=>urlstr, :called=>true}))
+        next
+      end
       title = nil
       debug "Getting title for #{urlstr}..."
       reply = nil
       begin
         title = get_title_for_url(urlstr,
+                                  :always_reply => m.address?,
                                   :nick => m.source.nick,
                                   :channel => m.channel,
                                   :ircline => m.message)
@@ -158,9 +203,17 @@ class UrlPlugin < Plugin
         # with the last character stripped. this might generate invalid URIs
         # (e.g. because "some.url" gets chopped to some.url%2, so catch that too
         if e.message =~ /\(404 - Not Found\)/i or e.kind_of?(URI::InvalidURIError)
-          # chop off last character, and retry if we still have enough string to
-          # look like a minimal URL
-          retry if urlstr.chop! and urlstr =~ /^https?:\/\/./
+          # chop off last non-word character from the unescaped version of
+          # the URL, and retry if we still have enough string to look like a
+          # minimal URL
+          unescaped = URI.unescape(urlstr)
+          debug "Unescaped: #{unescaped}"
+          if unescaped.sub!(/\W$/,'') and unescaped =~ /^https?:\/\/./
+            urlstr.replace URI.escape(unescaped, OUR_UNSAFE)
+            retry
+          else
+            debug "Not retrying #{unescaped}"
+          end
         end
         reply = "Error #{e.message}"
       end
@@ -202,8 +255,7 @@ class UrlPlugin < Plugin
   def message(m)
     return if m.address?
 
-    escaped = URI.escape(m.message, OUR_UNSAFE)
-    urls = URI.extract(escaped, ['http', 'https'])
+    urls = URI.extract(m.message, ['http', 'https'])
     return if urls.empty?
     Thread.new { handle_urls(m, :urls => urls) }
   end