]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - data/rbot/plugins/url.rb
quiz: stop quizzes and timers on cleanup
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / url.rb
index 7a752ec6c19b6e2ede3f55a29457d2089d0b975a..8327dd945d169c0d1c3282e547fef01d08f1c32e 100644 (file)
@@ -15,6 +15,12 @@ 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.)")
@@ -28,7 +34,12 @@ class UrlPlugin < Plugin
     :default => ['localhost', '^192\.168\.', '^10\.', '^127\.', '^172\.(1[6-9]|2\d|31)\.'],
     :on_change => Proc.new { |bot, v| bot.plugins['url'].reset_no_info_hosts },
     :desc => "A list of regular expressions matching hosts for which no info should be provided")
-
+  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
@@ -37,6 +48,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
@@ -57,8 +70,19 @@ class UrlPlugin < Plugin
     url = uri_str.kind_of?(URI) ? uri_str : URI.parse(uri_str)
     return if url.scheme !~ /https?/
 
-    if url.host =~ @no_info_hosts
-      return "Sorry, info retrieval for #{url.host} is disabled"
+    # also check the ip, the canonical name and the aliases
+    begin
+      checks = TCPSocket.gethostbyname(url.host)
+      checks.delete_at(-2)
+    rescue => e
+      return "Unable to retrieve info for #{url.host}: #{e.message}"
+    end
+
+    checks << url.host
+    checks.flatten!
+
+    unless checks.grep(@no_info_hosts).empty?
+      return ( opts[:always_reply] ? "Sorry, info retrieval for #{url.host} (#{checks.first}) is disabled" : false )
     end
 
     logopts = opts.dup
@@ -68,8 +92,9 @@ class UrlPlugin < Plugin
 
     begin
       debug "+ getting info for #{url.request_uri}"
-      info = Utils.get_html_info(url)
+      info = @bot.filter(:htmlinfo, url)
       debug info
+      logopts[:htmlinfo] = info
       resp = info[:headers]
 
       logopts[:title] = title = info[:title]
@@ -83,13 +108,13 @@ class UrlPlugin < Plugin
         extra << "#{Bold}type#{Bold}: #{resp['content-type']}" unless title
         if enc = resp['content-encoding']
           logopts[:extra] << ", encoding: #{enc}"
-          extra << "#{Bold}encoding#{Bold}: #{enc}"
+          extra << "#{Bold}encoding#{Bold}: #{enc}" if @bot.config['url.first_par'] or not title
         end
 
         size = resp['content-length'].first.gsub(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2') rescue nil
         if size
           logopts[:extra] << ", size: #{size} bytes"
-          extra << "#{Bold}size#{Bold}: #{size} bytes"
+          extra << "#{Bold}size#{Bold}: #{size} bytes" if @bot.config['url.first_par'] or not title
         end
       end
     rescue Exception => e
@@ -109,7 +134,23 @@ class UrlPlugin < Plugin
     return extra.join(", ") if title or not @bot.config['url.titles_only']
   end
 
-  def handle_urls(m, urls, display_info=@bot.config['url.display_link_info'])
+  def handle_urls(m, params={})
+    opts = {
+      :display_info => @bot.config['url.display_link_info'],
+      :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
@@ -117,22 +158,48 @@ class UrlPlugin < Plugin
     urls_displayed = 0
     urls.each do |urlstr|
       debug "working on #{urlstr}"
-      next unless urlstr =~ /^https?:/
+      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)
         debug "Title #{title ? '' : 'not '} found"
+        reply = "#{LINK_INFO} #{title}" if title
       rescue => e
-        m.reply "Error #{e.message}"
+        debug e
+        # we might get a 404 because of trailing punctuation, so we try again
+        # 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 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
 
       if display_info > urls_displayed
-        if title
-          m.reply("#{LINK_INFO} #{title}", :overlong => :truncate)
+        if reply
+          m.reply reply, :overlong => :truncate, :to => :public,
+            :nick => (m.address? ? :auto : false)
           urls_displayed += 1
         end
       end
@@ -155,16 +222,21 @@ class UrlPlugin < Plugin
   def info(m, params)
     escaped = URI.escape(params[:urls].to_s, OUR_UNSAFE)
     urls = URI.extract(escaped)
-    Thread.new { handle_urls(m, urls, params[:urls].length) }
+    Thread.new do
+      handle_urls(m,
+                  :urls => urls,
+                  :display_info => params[:urls].length,
+                  :channels => [])
+    end
   end
 
-  def listen(m)
-    return unless m.kind_of?(PrivMessage)
+  def message(m)
     return if m.address?
 
     escaped = URI.escape(m.message, OUR_UNSAFE)
-    urls = URI.extract(escaped)
-    Thread.new { handle_urls(m, urls) }
+    urls = URI.extract(escaped, ['http', 'https'])
+    return if urls.empty?
+    Thread.new { handle_urls(m, :urls => urls) }
   end
 
   def reply_urls(opts={})