}
}
-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> 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 ("<div id=\"flashMessage\" class=\"message\">Die eingegebenen Zugangsdaten konnten nicht gefunden werden. Bitte versuchen Sie es erneut.</div>")) {
+ 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)
}
public async unowned List<City>? 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;
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
);
}
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) {
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;
+ }
+ }
+ }
+
+/*
+ <tr class="head top">
+ <td width="150" class="label">Anrede</td>
+ <td width="400">Herr</td>
+ </tr>
+ <tr class="head">
+ <td class="label">Titel</td>
+
+ <td>--</td>
+ </tr>
+ ...
+*/
+ 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)