require 'rexml/document' class Ping < ActiveRecord::Base belongs_to :article class Pinger attr_accessor :article attr_accessor :blog def send_pingback_or_trackback begin @response = Net::HTTP.get_response(URI.parse(ping.url)) send_pingback or send_trackback rescue Timeout::Error => err return rescue => err raise err # Ignore end end def pingback_url if @response["X-Pingback"] @response["X-Pingback"] elsif response.body =~ // $1 else nil end end def origin_url @origin_url end def response @response end def ping @ping end def send_xml_rpc(*args) ping.send(:send_xml_rpc, *args) end def trackback_url rdfs = response.body.scan(//m) rdfs.each do |rdf| xml = REXML::Document.new(rdf) xml.elements.each("//rdf:Description") do |desc| if rdfs.size == 1 || desc.attributes["dc:identifier"] == ping.url return desc.attributes["trackback:ping"] end end end # Didn't find a trackback url, so fall back to the url itself. @ping.url end def send_pingback if pingback_url send_xml_rpc(pingback_url, "pingback.ping", origin_url, ping.url) return true else return false end end def send_trackback ping.send_trackback(trackback_url, origin_url) end private def initialize(origin_url, ping) @origin_url = origin_url @ping = ping # Make sure these are fetched now for thread safety purposes. self.article = ping.article self.blog = article.blog end end def send_pingback_or_trackback(origin_url) Pinger.new(origin_url, self).send_pingback_or_trackback end def send_trackback(trackback_url, origin_url) trackback_uri = URI.parse(trackback_url) post = "title=#{CGI.escape(article.title)}" post << "&excerpt=#{CGI.escape(article.html(:body).strip_html[0..254])}" post << "&url=#{origin_url}" post << "&blog_name=#{CGI.escape(article.blog.blog_name)}" Net::HTTP.start(trackback_uri.host, trackback_uri.port) do |http| path = trackback_uri.path path += "?#{trackback_uri.query}" if trackback_uri.query http.post(path, post, 'Content-type' => 'application/x-www-form-urlencoded; charset=utf-8') end end def send_weblogupdatesping(server_url, origin_url) send_xml_rpc(self.url, "weblogUpdates.ping", article.blog.blog_name, server_url, origin_url) end protected def send_xml_rpc(xml_rpc_url, name, *args) begin server = XMLRPC::Client.new2(URI.parse(xml_rpc_url).to_s) begin result = server.call(name, *args) rescue XMLRPC::FaultException => e logger.error(e) end rescue Exception => e logger.error(e) end end end