X-Git-Url: http://git.maemo.org/git/?p=beifahrer;a=blobdiff_plain;f=src%2Fadac-mitfahrclub.vala;fp=src%2Fadac-mitfahrclub.vala;h=b78fe54c0b041b8e380f5a4212497b506ecd34fa;hp=a9a8aced20afca827282f0d80575ee5ddb21d61c;hb=2f3a03bf739b66c1c7219c264f658777ae17b92d;hpb=d5531e7a10d8058db8850a5ebe6054bfcb0f6df3 diff --git a/src/adac-mitfahrclub.vala b/src/adac-mitfahrclub.vala index a9a8ace..b78fe54 100644 --- a/src/adac-mitfahrclub.vala +++ b/src/adac-mitfahrclub.vala @@ -71,40 +71,201 @@ public class Lift : Object { } } -public class CallbackMessage : Soup.Message { - public SourceFunc callback; - - public CallbackMessage (string url, SourceFunc? _callback) { - method = "GET"; - callback = _callback; - set_uri (new Soup.URI (url)); +public class MyInformation { + public enum Gender { + MALE, + FEMALE } + + public Gender gender; + public string title; + public string first_name; + public string last_name; + public Date birthday; + public Date registered_since; + + // Address + public string street; + public string number; + public string zip_code; + public string city; + public string country; + + // Contact + public string phone1; + public string phone2; + public string phone3; + public string cell; + public string email1; + public string email2; + + public bool smoker; + public bool adac_member; } public class AdacMitfahrclub { - const string BASE_URI = "http://mitfahrclub.adac.de"; + const string HTTP_BASE_URI = "http://mitfahrclub.adac.de"; + const string HTTPS_BASE_URI = "https://mitfahrclub.adac.de"; - Soup.SessionAsync session; + Curl.EasyHandle curl; List city_list = null; public AdacMitfahrclub () { - session = new Soup.SessionAsync (); + curl = new Curl.EasyHandle (); + // FIXME: Fremantle SDK doesn't come with certs + curl.setopt (Curl.Option.SSL_VERIFYPEER, 0); + // curl.setopt (Curl.Option.VERBOSE, 1); } - private void message_finished (Soup.Session session, Soup.Message message) { - Idle.add (((CallbackMessage) message).callback); + private string _url = null; + private SourceFunc callback = null; + void* download_thread () { + curl.setopt (Curl.Option.WRITEFUNCTION, write_callback); + curl.setopt (Curl.Option.WRITEDATA, this); + curl.setopt (Curl.Option.URL, _url); + if (aeolus_cookie != null) + curl.setopt (Curl.Option.COOKIE, "MIKINIMEDIA=%s; Quirinus[adacAeolus]=%s;".printf (mikini_cookie, aeolus_cookie)); + else if (mikini_cookie != null) + curl.setopt (Curl.Option.COOKIE, "MIKINIMEDIA=%s".printf (mikini_cookie)); + var res = curl.perform (); + + if (callback != null) + Idle.add (callback); + callback = null; + + return null; + } + + StringBuilder result; + + [CCode (instance_pos = -1)] + size_t write_callback (void *buffer, size_t size, size_t nmemb) { + // if (cancellable != null && cancellable.is_cancelled ()) + // return 0; + + result.append_len ((string) buffer, (ssize_t) (size * nmemb)); + + return size * nmemb; } private async Html.Doc* get_html_document (string url) { - var message = new CallbackMessage (url, get_html_document.callback); - session.queue_message (message, message_finished); + _url = url; + callback = get_html_document.callback; + result = new StringBuilder (); + try { + Thread.create(download_thread, false); + } catch (ThreadError e) { + critical ("Failed to create download thread\n"); + return null; + } yield; - return Html.Doc.read_memory ((char[]) message.response_body.data, (int) message.response_body.length, + return Html.Doc.read_memory ((char[]) result.str, (int) result.len, url, null, Html.ParserOption.NOERROR | Html.ParserOption.NOWARNING); } + private string username; + private string password; + private string mikini_cookie; + private string aeolus_cookie; + + public void set_cookie (string value) { + aeolus_cookie = value; + } + + public void login (string? _username, string? _password) { + username = _username; + password = _password; + if (logged_in) + return; + if (login_callback != null) + return; + login_thread (); + } + + public bool logged_in = false; + private SourceFunc login_callback = null; + public async bool login_async (string? _username, string? _password) { + username = _username; + password = _password; + if (logged_in) + return true; + if (login_callback != null) + return false; + login_callback = login_async.callback; + result = new StringBuilder (); + try { + Thread.create(login_thread, false); + } catch (ThreadError e) { + critical ("Failed to create login thread\n"); + return false; + } + + yield; + login_callback = null; + + return logged_in; + } + + void *login_thread () { + result = new StringBuilder (); + curl.setopt (Curl.Option.URL, HTTP_BASE_URI); + curl.setopt (Curl.Option.WRITEFUNCTION, write_callback); + curl.setopt (Curl.Option.WRITEDATA, this); + curl.setopt (Curl.Option.COOKIEFILE, ""); + var res = curl.perform (); + + Curl.SList cookies; + curl.getinfo (Curl.Info.COOKIELIST, out cookies); + unowned Curl.SList cookie = cookies; + while (cookie != null) { + if (cookie.data != null) { + var c = cookie.data.split ("\t"); + if (c.length > 5) + print ("%s=%s\n", c[5], c[6]); + if (c[5] == "MIKINIMEDIA") + mikini_cookie = c[6]; + } + cookie = cookie.next; + } + + result = new StringBuilder (); + string postdata = "data[User][continue]=/&data[User][js_allowed]=0&data[User][cookie_allowed]=1&data[User][username]=%s&data[User][password]=%s&data[User][remember_me]=1".printf (username, password); + curl.setopt (Curl.Option.POSTFIELDS, postdata); + curl.setopt (Curl.Option.URL, HTTPS_BASE_URI + "/users/login/"); + curl.setopt (Curl.Option.SSL_VERIFYPEER, 0); + res = curl.perform (); + // print ("%s\n", result.str); + + cookies = null; + curl.getinfo (Curl.Info.COOKIELIST, out cookies); + cookie = cookies; + while (cookie != null) { + if (cookie.data != null) { + var c = cookie.data.split ("\t"); + if (c.length > 5) + print ("%s=%s\n", c[5], c[6]); + // "Quirinus[adacAeolus]" + if (c[5] == "Quirinus[adacAeolus]") { + aeolus_cookie = c[6]; + logged_in = true; + } + } + cookie = cookie.next; + } + + if (result.str.contains ("
Die eingegebenen Zugangsdaten konnten nicht gefunden werden. Bitte versuchen Sie es erneut.
")) { + print ("LOGIN FAILED\n"); + aeolus_cookie = null; + logged_in = false; + } + + if (login_callback != null) + Idle.add (login_callback); + return null; + } + private void save_city_list () { FileStream list_file = FileStream.open ("/home/user/.cache/beifahrer/city_list", "w"); if (list_file == null) @@ -166,7 +327,7 @@ public class AdacMitfahrclub { } public async unowned List? download_city_list () { - var doc = yield get_html_document (BASE_URI); + var doc = yield get_html_document (HTTP_BASE_URI); if (doc == null) { stderr.printf ("Error: parsing failed\n"); return null; @@ -253,7 +414,7 @@ public class AdacMitfahrclub { return null; } - string url = BASE_URI + "/mitfahrclub/%s/%s/b.html".printf ( + string url = HTTP_BASE_URI + "/mitfahrclub/%s/%s/b.html".printf ( city_from, city_to ); @@ -369,7 +530,7 @@ public class AdacMitfahrclub { } public async bool update_lift_details (Lift lift) { - string url = BASE_URI + lift.href; + string url = HTTP_BASE_URI + lift.href; var doc = yield get_html_document (url); if (doc == null) { @@ -512,6 +673,139 @@ public class AdacMitfahrclub { return true; } + public async MyInformation get_my_information () { + string url = HTTPS_BASE_URI + "/users/view"; + + var doc = yield get_html_document (url); + if (doc == null) { + stderr.printf ("Error: parsing failed\n"); + return null; + } + + var table = search_tag_by_class (doc->children, "table", "user"); + if (table == null) { + stderr.printf ("Error: does not contain user table\n"); + return null; + } + + var my_info = new MyInformation (); + + Xml.Node* n; + for (n = table->children; n != null; n = n->next) { + if (n->name == "tr") { + var n2 = n->children; + if (n2 == null || n2->name != "td" || + n2->children == null || n2->children->name != "text") + continue; + + string text = n2->children->content; + + n2 = n2->next; + if (n2 != null && n2->name == "text") + n2 = n2->next; + if (n2 == null || n2->name != "td" || + n2->children == null || n2->children->name != "text") + continue; + + string content = n2->children->content; + + switch (text) { + case "Anrede": + my_info.gender = (content == "Herr") ? MyInformation.Gender.MALE : MyInformation.Gender.FEMALE; + continue; + case "Titel": + my_info.title = content; + continue; + case "Vorname": + my_info.first_name = content; + continue; + case "Name": + my_info.last_name = content; + continue; + case "Geburtsdatum": + // my_info.birthday = ... + continue; + case "registriert seit": + // my_info.registered_since = content; + continue; + // default: + // print ("\t%s=%s\n", text, content); + // break; + } + + text = content; + + n2 = n2->next; + if (n2 != null && n2->name == "text") + n2 = n2->next; + if (n2 == null || n2->name != "td") + continue; + + if (n2->children != null && n2->children->name != "text") + content = n2->children->content; + else + content = ""; + + switch (text) { + case "Straße, Nr.": + my_info.street = content; + my_info.number = ""; + continue; + case "PLZ, Ort": + my_info.zip_code = ""; + my_info.city = content; + continue; + case "Land": + my_info.country = content; + continue; + case "Telefon 1": + my_info.phone1 = content; + continue; + case "Telefon 2": + my_info.phone2 = content; + continue; + case "Telefon 3": + my_info.phone3 = content; + continue; + case "Handy": + my_info.cell = content; + continue; + case "Email 1": + my_info.email1 = content; + continue; + case "Email 2": + my_info.email2 = content; + continue; + case "Raucher": + // FIXME + my_info.smoker = false; + continue; + case "ADAC-Mitglied": + // FIXME + my_info.adac_member = false; + continue; + // default: + // print ("\"%s\"=\"%s\"\n", text, content); + // break; + } + } + } + +/* + + Anrede + Herr + + + Titel + + -- + + ... +*/ + return my_info; + } + Xml.Node* search_tag_by_property (Xml.Node* node, string tag, string prop, string val) requires (node != null) { for (var n = node; n != null; n = n->next) { if (n->name == tag && n->get_prop (prop) == val)