diff --git a/.gitignore b/.gitignore index 75d9612..6d33611 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.rvmrc .DS_Store pkg/* test/accounts.yml diff --git a/lib/contacts.rb b/lib/contacts.rb index 974b4ff..f43bcfc 100644 --- a/lib/contacts.rb +++ b/lib/contacts.rb @@ -10,3 +10,5 @@ require 'plaxo' require 'aol' require 'mailru' +require 'gmx' +require 'webde' diff --git a/lib/contacts/gmx.rb b/lib/contacts/gmx.rb new file mode 100644 index 0000000..684daa9 --- /dev/null +++ b/lib/contacts/gmx.rb @@ -0,0 +1,65 @@ +class Contacts + class Gmx < Base + LOGIN_URL = 'https://service.gmx.net/de/cgi/login' + JUMP_URL = 'https://uas2.uilogin.de/intern/jump' #used for unified address service auth + MAIL_FOLDER_URL = 'http://service.gmx.net/de/cgi/g.fcgi/mail/index' + MAIL_FOLDER_PARAMS = "folder=%s&allfolders=false&first=%s&CUSTOMERNO=%s&t=%s" + + def real_connect + postdata = "AREA=1&id=%s&p=%s" % [ + CGI.escape(login), + CGI.escape(password) + ] + + data, resp, @cookies, forward = post(LOGIN_URL, postdata) + + if data.include?("/lose/password") || data.include?("login-failed") + raise AuthenticationError, "Username and password do not match" + end + + @customerno = forward.match(/CUSTOMERNO=(\d+)/)[1] + @t = forward.match(/t=([^&]+)/)[1] + end + + def contacts + @contacts = {} + + if connected? + folders.each do |folder| + contacts_for_folder(folder) + end + end + + @contacts.to_a + end + + private + + def scan_contacts(html) + html.scan(/"\"?([\w\.\s-]+)\"?\s<([\w\.-]+@[\w\.-]+\.\w+)(?:>)?"/) do |match| + @contacts[match[0]] = match[1] + end + end + + def contacts_for_folder(folder) + count = 0 + while count < 100 do + data, resp, cookies, forward = get MAIL_FOLDER_URL + "?" + MAIL_FOLDER_PARAMS % [ + folder, + count, + @customerno, + @t + ], @cookies + scan_contacts(data) + count += 10 + end + end + + def folders + %w(inbox sent) + end + + end + + TYPES[:gmx] = Gmx +end \ No newline at end of file diff --git a/lib/contacts/hotmail.rb b/lib/contacts/hotmail.rb index 827c570..853702d 100644 --- a/lib/contacts/hotmail.rb +++ b/lib/contacts/hotmail.rb @@ -89,7 +89,7 @@ def contacts(options = {}) # Grab info case c_info[1] when "e" # Email - build_contacts.last[1] = row.match(/#{email_match_text_beginning}(.*)#{email_match_text_end}/)[1] + build_contacts.last[1] = CGI.unescape(row.match(/#{email_match_text_beginning}([^&]*)#{email_match_text_end}/)[1]) when "dn" # Name build_contacts.last[0] = row.match(/]*>(.+)<\/a>/)[1] end diff --git a/lib/contacts/webde.rb b/lib/contacts/webde.rb new file mode 100644 index 0000000..ebf8a7d --- /dev/null +++ b/lib/contacts/webde.rb @@ -0,0 +1,71 @@ +require "iconv" + +class Contacts + class Webde < Base + LOGIN_URL = "https://login.web.de/intern/login/" + JUMP_URL = "https://uas2.uilogin.de/intern/jump/" + ADDRESSBOOK_URL = "https://adressbuch.web.de/exportcontacts" + + def real_connect + postdata = "service=freemail&server=%s&password=%s&username=%s" % [ + CGI.escape('https://freemail.web.de'), + CGI.escape(password), + CGI.escape(login) + ] + + # send login + data, resp, cookies, forward = post(LOGIN_URL, postdata) + + if forward.include?("logonfailed") + raise AuthenticationError, "Username and password do not match" + end + + # request session from login service + data, resp, cookies, forward = get forward + + # start mail app session + data, resp, cookies, forward = get forward + + @si = forward.match(/si=([^&]+)/)[1] + end + + def connected? + @si && @si.length > 0 + end + + def contacts + connect_to_addressbook + @contacts = [] + if @sessionid + CSV.parse(get_entries_from_addressbook) do |row| + @contacts << [latin1_to_utf8("#{row[2]} #{row[0]}"), latin1_to_utf8(row[9])] unless header_row?(row) + end + end + + @contacts + end + + private + + def latin1_to_utf8(string) + Iconv.conv("utf-8", "ISO-8859-1", string) + end + + def header_row?(row) + row[0] == 'Nachname' + end + + def connect_to_addressbook + data, resp, cookies, forward = get JUMP_URL + "?serviceID=comsaddressbook-live.webde&session=#{@si}&server=https://freemailng2901.web.de&partnerdata=" + @sessionid = forward.match(/session=([^&]+)/)[1] + end + + def get_entries_from_addressbook + postdata = "language=de&raw_format=csv_Outlook2003&session=#{@sessionid}&what=PERSON" + data, resp, cookies, forward = post ADDRESSBOOK_URL, postdata + data + end + end + + TYPES[:webde] = Webde +end \ No newline at end of file diff --git a/test/unit/gmx_contact_importer_test.rb b/test/unit/gmx_contact_importer_test.rb new file mode 100644 index 0000000..4498d57 --- /dev/null +++ b/test/unit/gmx_contact_importer_test.rb @@ -0,0 +1,39 @@ +dir = File.dirname(__FILE__) +require "#{dir}/../test_helper" +require 'contacts' + +class GmxContactImporterTest < ContactImporterTestCase + def setup + super + @account = TestAccounts[:gmx] + end + + def test_successful_login + assert Contacts.new(:gmx, @account.username, @account.password).connected? + end + + def test_importer_fails_with_invalid_password + assert_raise(Contacts::AuthenticationError) do + Contacts.new(:gmx, @account.username, "wrong_password") + end + end + + def test_importer_fails_with_blank_password + assert_raise(Contacts::AuthenticationError) do + Contacts.new(:gmx, @account.username, "") + end + end + + def test_importer_fails_with_blank_username + assert_raise(Contacts::AuthenticationError) do + Contacts.new(:gmx, "", @account.password) + end + end + + def test_fetch_contacts + contacts = Contacts.new(:gmx, @account.username, @account.password).contacts + @account.contacts.each do |contact| + assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}" + end + end +end \ No newline at end of file diff --git a/test/unit/webde_contact_importer_test.rb b/test/unit/webde_contact_importer_test.rb new file mode 100644 index 0000000..9c1eacf --- /dev/null +++ b/test/unit/webde_contact_importer_test.rb @@ -0,0 +1,39 @@ +dir = File.dirname(__FILE__) +require "#{dir}/../test_helper" +require 'contacts' + +class WebdeContactImporterTest < ContactImporterTestCase + def setup + super + @account = TestAccounts[:webde] + end + + def test_successful_login + assert Contacts.new(:webde, @account.username, @account.password).connected? + end + + def test_importer_fails_with_invalid_password + assert_raise(Contacts::AuthenticationError) do + Contacts.new(:webde, @account.username, "wrong_password") + end + end + + def test_importer_fails_with_blank_password + assert_raise(Contacts::AuthenticationError) do + Contacts.new(:webde, @account.username, "") + end + end + + def test_importer_fails_with_blank_username + assert_raise(Contacts::AuthenticationError) do + Contacts.new(:webde, "", @account.password) + end + end + + def test_fetch_contacts + contacts = Contacts.new(:webde, @account.username, @account.password).contacts + @account.contacts.each do |contact| + assert contacts.include?(contact), "Could not find: #{contact.inspect} in #{contacts.inspect}" + end + end +end \ No newline at end of file