#!/usr/bin/ruby -w

# This is a Pavatar plugin written in ruby by Jeena Paradies
# I hereby place this script into the public domain.
#
# This is version 0.1 and it could include some bugs I haven't found yet.
# Because the program is licensed free of charge, there is no warranty
# for the program, but it works for me, try it if you want.
#
# If you have some questions contact me: pavatar@jeenaparadies.net
#
# To use it add it in the src attribute of you image:
# <img src="http://example.com/cgi-bin/pavatar.rb?url=http://example.org" alt="" />

# include some libraries to handle HTTP requests
require 'cgi'
require 'uri'
require 'net/http'
require 'image_size' # see http://www.rubycgi.org/archive/

class Pavatar
# content types defined by the spec http://pavatar.com/spec#technical-definition
@@content_types = ['image/png', 'image/jpeg', 'image/gif']

# fetch the pavatar url on initialize
def initialize url

@url = url
@purl = URI.parse(@url)

# check for the first real pavatar url and save it into a class variable
if (@pavatar = xHeader).nil? and (@pavatar = link).nil? and (@pavatar = path).nil?
@pavatar = favicon
end
end

# Autodiscovery methods

# get url from header if there is one
def xHeader
begin
res = FetchHelper.head(@url)
res['X-Pavatar'] unless res['X-Pavatar'].nil?
rescue
end
end

# get url from <link> if there is one
def link
begin
res = FetchHelper.get(@url)
pavatar = /<link rel="pavatar" href="([^"]+)" ?\/?>/.match(res.body)
pavatar[1] unless pavatar.nil?
rescue
end
end

# look in users path if there is a pavatar
def path
begin
# to discover the given directory is a little bit tricky in ruby
path = @purl.path.to_s
unless path[-1..-1] == '/'
path = File.dirname(path)
unless path == '.' or path == '/'
path << '/'
end
end

if path == '.'
path = '/'
end

url = 'http://' + @purl.host.to_s + path + 'pavatar.png'

# if would be ok to look on the header here but Apache has a problem with
# head requests so we use a get request to workaround it
res = FetchHelper.get(url)

# some people redirect to a 404 page and send status 200 so we need to check the content type
url unless res['content-type'].nil? or not @@content_types.include?(res['content-type'])
rescue
end
end

# look in users home directory if there is a pavatar
def favicon
begin
url = 'http://' + @purl.host.to_s + '/pavatar.png'

# same problem with apache here
res = FetchHelper.get(url)
url unless res['content-type'].nil? or not @@content_types.include?(res['content-type'])
rescue
end
end

# url getter
def get_url
@pavatar
end

# get a whole html string to show a pavatar
def get_html (attr = '')
attr = ' ' + attr unless attr.length > 0
'<img src="' + get_url + '"' + attr + ' />'
end

end


# helps us handle redirections
module FetchHelper

def FetchHelper.head(url_str, limit = 10)

# stop if there is a loop
raise ArgumentError, 'HTTP redirect too deep' if limit == 0

url = URI.parse(url_str)
path = File.dirname(url.path.to_s)

response = nil

Net::HTTP.start(url.host, url.port) { |http|
response = http.head( path == '.' ? '/' : url.path.to_s )
}

case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then FetchHelper.head(response['location'], limit - 1)
else
response.error!
end
end

def FetchHelper.get(url_str, limit = 10)
raise ArgumentError, 'HTTP redirect too deep.' if limit == 0

response = Net::HTTP.get_response(URI.parse(url_str))
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then FetchHelper.get(response['location'], limit - 1)
else
response.error!
end
end

def FetchHelper.validate(url, what)
begin
uri = URI.parse(url)
if uri.class != URI::HTTP
raise ArgumentError, "Only HTTP protocol addresses can be used in the #{what} URL."
end
rescue URI::InvalidURIError
raise ArgumentError, "The format of the #{what} URL is not valid."
end
end

end

if __FILE__ == $0
# cach the GET variable
cgi = CGI.new

types = {
'PNG' => 'image/png',
'GIF' => 'image/gif',
'JPEG' => 'image/jpeg'
}

begin
FetchHelper.validate(cgi['url'], 'homepage')
pavatar_url = Pavatar.new(cgi['url'])
raise ArgumentError, "No pavatar here." if pavatar_url.get_url.nil? or pavatar_url.get_url == "none"
FetchHelper.validate(pavatar_url.get_url, 'Pavatar')
pavatar = FetchHelper.get(pavatar_url.get_url)
raise ArgumentError, "File size too big (#{(pavatar.body.to_s.size * 8)}) max: 409600." if (pavatar.body.to_s.size * 8) > 409600
img = ImageSize.new(pavatar.body)
raise ArgumentError, "Width is not 80px but #{img.get_width}px." unless img.get_width == 80
raise ArgumentError, "Height is not 80px but #{img.get_height}px." unless img.get_height == 80
raise ArgumentError, "False image type: #{img.get_type} #{pavatar_url.get_url}." unless types.has_key? img.get_type
rescue Exception => e
pavatar = FetchHelper.get("http://example/img/default-pavatar.png")
print "X-Pavatar-Error: #{e}\r\n"
print "Content-type: #{pavatar['content-type']}\r\n\r\n"
print pavatar.body
exit
end

# print our HTML header
print "Content-type: #{types[img.get_type]}\r\n\r\n"
print pavatar.body

end
# end of file