class Contacts::Base

Public Class Methods

new(login, password, options={}) click to toggle source
# File lib/contacts/base.rb, line 16
def initialize(login, password, options={})
  @login = login
  @password = password
  @connections = {}
  @options = options
  connect
end

Public Instance Methods

connect() click to toggle source
# File lib/contacts/base.rb, line 24
def connect
  raise AuthenticationError, "Login and password must not be nil, login: #{@login.inspect}, password: #{@password.inspect}" if @login.nil? || @login.empty? || @password.nil? || @password.empty?
  real_connect
end
connected?() click to toggle source
# File lib/contacts/base.rb, line 29
def connected?
  @cookies && !@cookies.empty?
end
contacts(options = {}) click to toggle source
# File lib/contacts/base.rb, line 33
def contacts(options = {})
  return @contacts if @contacts
  if connected?
    url = URI.parse(contact_list_url)
    http = open_http(url)
    resp, data = http.get("#{url.path}?#{url.query}",
      "Cookie" => @cookies
    )

    if resp.code_type != Net::HTTPOK
      raise ConnectionError, self.class.const_get(:PROTOCOL_ERROR)
    end

    parse(data, options)
  end
end
login() click to toggle source
# File lib/contacts/base.rb, line 50
def login
  @attempt ||= 0
  @attempt += 1

  if @attempt == 1
    @login
  else
    if @login.include?("@#{domain}")
      @login.sub("@#{domain}","")
    else
      "#{@login}@#{domain}"
    end
  end
end
password() click to toggle source
# File lib/contacts/base.rb, line 65
def password
  @password
end
skip_gzip?() click to toggle source
# File lib/contacts/base.rb, line 69
def skip_gzip?
  false
end

Private Instance Methods

address_book_url() click to toggle source
# File lib/contacts/base.rb, line 82
def address_book_url
  self.class.const_get(:ADDRESS_BOOK_URL)
end
contact_list_url() click to toggle source
# File lib/contacts/base.rb, line 78
def contact_list_url
  self.class.const_get(:CONTACT_LIST_URL)
end
domain() click to toggle source
# File lib/contacts/base.rb, line 74
def domain
  @d ||= URI.parse(self.class.const_get(:URL)).host.sub(/^www\./,'')
end
get(url, cookies="", referer="") click to toggle source
# File lib/contacts/base.rb, line 156
def get(url, cookies="", referer="")
  url = URI.parse(url)
  http = open_http(url)
  resp, data = http.get("#{url.path}?#{url.query}",
    "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
    "Accept-Encoding" => "gzip",
    "Cookie" => cookies,
    "Referer" => referer
  )
  data = uncompress(resp, data)
  cookies = parse_cookies(resp.response['set-cookie'], cookies)
  forward = resp.response['Location']
if (not forward.nil?) && URI.parse(forward).host.nil?
forward = url.scheme.to_s + "://" + url.host.to_s + forward
end
  return data, resp, cookies, forward
end
open_http(url) click to toggle source
# File lib/contacts/base.rb, line 86
def open_http(url)
  c = @connections[Thread.current.object_id] ||= {}
  http = c["#{url.host}:#{url.port}"]
  unless http
    http = Net::HTTP.new(url.host, url.port)
    if url.port == 443
      http.use_ssl = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
    end
    c["#{url.host}:#{url.port}"] = http
  end
  http.start unless http.started?
  http
end
parse_cookies(data, existing="") click to toggle source
# File lib/contacts/base.rb, line 105
def parse_cookies(data, existing="")
  return existing if data.nil?

  cookies = cookie_hash_from_string(existing)

  data.gsub!(/ ?[\w]+=EXPIRED;/,'')
  data.gsub!(/ ?expires=(.*?, .*?)[;,$]/i, ';')
  data.gsub!(/ ?(domain|path)=[\S]*?[;,$]/i,';')
  data.gsub!(/[,;]?\s*(secure|httponly)/i,'')
  data.gsub!(/(;\s*){2,}/,', ')
  data.gsub!(/(,\s*){2,}/,', ')
  data.sub!(/^,\s*/,'')
  data.sub!(/\s*,$/,'')

  data.split(", ").map{|t|t.to_s.split(";").first}.each do |data|
    k, v = data.split("=", 2).map{|j|j.strip}
    if cookies[k] && v.empty?
      cookies.delete(k)
    elsif v && !v.empty?
      cookies[k] = v
    end
  end

  cookies.map{|k,v| "#{k}=#{v}"}.join("; ")
end
post(url, postdata, cookies="", referer="") click to toggle source
# File lib/contacts/base.rb, line 135
  def post(url, postdata, cookies="", referer="")
    url = URI.parse(url)
    http = open_http(url)
    http_header = { "User-Agent" => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1) Gecko/20061010 Firefox/2.0",
      "Accept-Encoding" => "gzip",
      "Cookie" => cookies,
      "Referer" => referer,
      "Content-Type" => 'application/x-www-form-urlencoded'
    }
    http_header.reject!{|k, v| k == 'Accept-Encoding'} if skip_gzip?
    resp, data = http.post(url.path, postdata, http_header)
    data = uncompress(resp, data)
    cookies = parse_cookies(resp.response['set-cookie'], cookies)
    forward = resp.response['Location']
    forward ||= (data =~ /<meta.*?url='([^']+)'/ ? CGI.unescapeHTML($1) : nil)
if (not forward.nil?) && URI.parse(forward).host.nil?
  forward = url.scheme.to_s + "://" + url.host.to_s + forward
end
    return data, resp, cookies, forward
  end
uncompress(resp, data) click to toggle source
# File lib/contacts/base.rb, line 174
def uncompress(resp, data)
  case resp.response['content-encoding']
  when 'gzip'
    gz = Zlib::GzipReader.new(StringIO.new(data))
    data = gz.read
    gz.close
    resp.response['content-encoding'] = nil
  # FIXME: Not sure what Hotmail was feeding me with their 'deflate',
  #        but the headers definitely were not right
  when 'deflate'
    data = Zlib::Inflate.inflate(data)
    resp.response['content-encoding'] = nil
  end

  data
end