summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPierre GRANDIN <grandinp@altern.org>2016-01-20 10:15:55 -0800
committerPierre GRANDIN <grandinp@altern.org>2016-01-20 10:15:55 -0800
commit0a9e9f8e3080ebaba6368dcf3b831d57dd57785d (patch)
tree775981ea1ea75be01973cfd96345793f615983ef
parent86df00e1313d5b0351452f0e0ee7a7750fd06223 (diff)
downloadnavit-0a9e9f8e3080ebaba6368dcf3b831d57dd57785d.tar.gz
Add:gui_internal:Added Googleplaces search from the internal gui
-rwxr-xr-xCMakeLists.txt10
-rw-r--r--cmake/FindJansson.cmake59
-rw-r--r--config.h.cmake2
-rw-r--r--navit/CMakeLists.txt2
-rw-r--r--navit/gui/internal/CMakeLists.txt11
-rw-r--r--navit/gui/internal/gui_internal_command.c7
-rw-r--r--navit/gui/internal/gui_internal_googlesearch.c298
-rw-r--r--navit/gui/internal/gui_internal_googlesearch.h2
-rw-r--r--navit/network.c148
-rw-r--r--navit/network.h15
-rw-r--r--navit/xpm/googleplaces.svg146
11 files changed, 697 insertions, 3 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a08365d1f..ad5435724 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -148,6 +148,7 @@ find_package(DBusGLib)
find_package(PythonLibs)
find_package(OpenSSL)
find_package(Threads)
+find_package(Jansson)
libfind_pkg_check_modules(FONTCONFIG fontconfig)
#Qt detection
if (NOT DISABLE_QT)
@@ -437,6 +438,15 @@ add_feature(USE_ROUTING "default" TRUE)
add_feature(USE_SVG "default" TRUE)
add_feature(SVG2PNG "default" TRUE)
add_feature(SAMPLE_MAP "default" TRUE)
+add_feature(USE_GOOGLEPLACES "default" FALSE)
+
+if (JANSSON_FOUND)
+ set_with_reason(USE_GOOGLEPLACES "jansson found" FALSE)
+ list(APPEND NAVIT_LIBS "-ljansson -lcurl")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -u fetch_url_to_string ")
+else (JANSSON_FOUND)
+ set_with_reason(USE_GOOGLEPLACES "jansson not found" FALSE)
+endif (JANSSON_FOUND)
IF(NOT svg2png_scaling)
IF(NOT ANDROID)
diff --git a/cmake/FindJansson.cmake b/cmake/FindJansson.cmake
new file mode 100644
index 000000000..32259232f
--- /dev/null
+++ b/cmake/FindJansson.cmake
@@ -0,0 +1,59 @@
+# - Try to find Jansson
+# Once done this will define
+#
+# JANSSON_FOUND - system has Jansson
+# JANSSON_INCLUDE_DIRS - the Jansson include directory
+# JANSSON_LIBRARIES - Link these to use Jansson
+#
+# Copyright (c) 2011 Lee Hambley <lee.hambley@gmail.com>
+#
+# Redistribution and use is allowed according to the terms of the New
+# BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+
+if (JANSSON_LIBRARIES AND JANSSON_INCLUDE_DIRS)
+ # in cache already
+ set(JANSSON_FOUND TRUE)
+else (JANSSON_LIBRARIES AND JANSSON_INCLUDE_DIRS)
+ find_path(JANSSON_INCLUDE_DIR
+ NAMES
+ jansson.h
+ PATHS
+ /usr/include
+ /usr/local/include
+ /opt/local/include
+ /sw/include
+ )
+
+find_library(JANSSON_LIBRARY
+ NAMES
+ jansson
+ PATHS
+ /usr/lib
+ /usr/local/lib
+ /opt/local/lib
+ /sw/lib
+ )
+
+set(JANSSON_INCLUDE_DIRS
+ ${JANSSON_INCLUDE_DIR}
+ )
+
+if (JANSSON_LIBRARY)
+ set(JANSSON_LIBRARIES
+ ${JANSSON_LIBRARIES}
+ ${JANSSON_LIBRARY}
+ )
+endif (JANSSON_LIBRARY)
+
+ include(FindPackageHandleStandardArgs)
+ find_package_handle_standard_args(Jansson DEFAULT_MSG
+ JANSSON_LIBRARIES JANSSON_INCLUDE_DIRS)
+
+ # show the JANSSON_INCLUDE_DIRS and JANSSON_LIBRARIES variables only in the advanced view
+ mark_as_advanced(JANSSON_INCLUDE_DIRS JANSSON_LIBRARIES)
+
+endif (JANSSON_LIBRARIES AND JANSSON_INCLUDE_DIRS)
+
+
diff --git a/config.h.cmake b/config.h.cmake
index abc3d0ebc..e4aeb597a 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -92,3 +92,5 @@
#cmakedefine HAVE_SHMEM 1
#cmakedefine HAVE_IMLIB2 1
+
+#cmakedefine USE_GOOGLEPLACES 1
diff --git a/navit/CMakeLists.txt b/navit/CMakeLists.txt
index 5333c9ff4..db51d5d7a 100644
--- a/navit/CMakeLists.txt
+++ b/navit/CMakeLists.txt
@@ -6,7 +6,7 @@ include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/support")
# navit cre
set(NAVIT_SRC announcement.c atom.c attr.c cache.c callback.c command.c config_.c coord.c country.c data_window.c debug.c
- event.c file.c geom.c graphics.c gui.c item.c layout.c log.c main.c map.c maps.c
+ event.c file.c geom.c graphics.c gui.c item.c layout.c log.c main.c map.c maps.c network.c
linguistics.c mapset.c maptype.c menu.c messages.c bookmarks.c navit.c navit_nls.c navigation.c osd.c param.c phrase.c plugin.c popup.c
profile.c profile_option.c projection.c roadprofile.c route.c script.c search.c speech.c start_real.c sunriset.c transform.c track.c
search_houseno_interpol.c util.c vehicle.c vehicleprofile.c xmlconfig.c )
diff --git a/navit/gui/internal/CMakeLists.txt b/navit/gui/internal/CMakeLists.txt
index 230e315d6..2bc656e23 100644
--- a/navit/gui/internal/CMakeLists.txt
+++ b/navit/gui/internal/CMakeLists.txt
@@ -1 +1,10 @@
-module_add_library(gui_internal gui_internal.c gui_internal_bookmark.c gui_internal_command.c gui_internal_gesture.c gui_internal_html.c gui_internal_menu.c gui_internal_poi.c gui_internal_search.c gui_internal_widget.c gui_internal_keyboard.c)
+if(USE_GOOGLEPLACES)
+ set(api_LIBS "-ljansson -lpthread")
+ set(googleplaces_sources gui_internal_googlesearch.c )
+endif(USE_GOOGLEPLACES)
+set(gui_internal_LIBS ${api_LIBS})
+module_add_library(gui_internal ${googleplaces_sources}
+ gui_internal.c gui_internal_bookmark.c
+ gui_internal_command.c gui_internal_gesture.c gui_internal_html.c
+ gui_internal_menu.c gui_internal_poi.c gui_internal_search.c
+ gui_internal_widget.c gui_internal_keyboard.c)
diff --git a/navit/gui/internal/gui_internal_command.c b/navit/gui/internal/gui_internal_command.c
index 98a736fb8..45461cccf 100644
--- a/navit/gui/internal/gui_internal_command.c
+++ b/navit/gui/internal/gui_internal_command.c
@@ -36,6 +36,9 @@
#include "gui_internal_search.h"
#include "gui_internal_poi.h"
#include "gui_internal_command.h"
+#ifdef USE_GOOGLEPLACES
+#include "gui_internal_googlesearch.h"
+#endif
extern char *version;
@@ -1226,7 +1229,9 @@ static struct command_table commands[] = {
{"waypoints",command_cast(gui_internal_cmd2)},
{"write",command_cast(gui_internal_cmd_write)},
{"about",command_cast(gui_internal_cmd2)},
-
+#ifdef USE_GOOGLEPLACES
+ {"googlesearch_search", command_cast (gui_internal_googlesearch_search)},
+#endif
};
void
diff --git a/navit/gui/internal/gui_internal_googlesearch.c b/navit/gui/internal/gui_internal_googlesearch.c
new file mode 100644
index 000000000..2099a48af
--- /dev/null
+++ b/navit/gui/internal/gui_internal_googlesearch.c
@@ -0,0 +1,298 @@
+/* vim: set tabstop=8 expandtab: */
+#include <glib.h>
+#include <navit/main.h>
+#include <navit/debug.h>
+#include <navit/point.h>
+#include <navit/navit.h>
+#include <navit/callback.h>
+#include <navit/color.h>
+#include <navit/event.h>
+#include <navit/command.h>
+#include <navit/config_.h>
+#include <navit/transform.h>
+
+#include "gui_internal.h"
+#include "coord.h"
+#include "math.h"
+#include "gui_internal_menu.h"
+#include "gui_internal_widget.h"
+#include "gui_internal_priv.h"
+#include "gui_internal_googlesearch.h"
+#include "network.h"
+#include <time.h> // Benchmarking the multithreading code, to be removed
+#include <pthread.h>
+
+#include "jansson.h"
+
+
+/*
+ * Implements searching from Googleplaces.
+ * To use :
+ * - add your own googleplaces API key below
+ * - add something like <img src='googleplaces' onclick='googlesearch_search()'><text>GooglePlaces</text></img> to your navit.xml GUI declaration
+ */
+char *googleplaces_apikey = "";
+
+struct googleplace {
+ char * id;
+ char * name;
+ struct pcoord c;
+ struct coord_geo g;
+ struct gui_priv *gui_priv;
+ struct widget *wm;
+};
+
+/**
+ * @brief Fetches the details about a given place
+ * @param[in] id - the googleplace id
+ *
+ * @return googleplace - an object containing the details about the place
+ *
+ * Fetches the details about a given place
+ *
+ */
+struct googleplace
+fetch_googleplace_details(char * id)
+{
+ char url[256];
+ strcpy (url, g_strdup_printf ("https://maps.googleapis.com/maps/api/place/details/json?key=%s&placeid=%s",googleplaces_apikey,id));
+ dbg(lvl_error,"Url %s\n", url);
+
+ json_t *root;
+ json_error_t error;
+ char * item_js= fetch_url_to_string(url);
+ dbg(lvl_info,"%s\n",item_js);
+ root = json_loads (item_js, 0, &error);
+ free(item_js);
+ if(!root)
+ {
+ dbg(lvl_error,"Invalid json for url %s, giving up for place id %s\n",url,id);
+ json_decref (root);
+ return;
+ }
+
+ struct googleplace gp;
+ json_t *result, *geometry, *location, *name;
+ result = json_object_get (root, "result");
+ geometry = json_object_get (result, "geometry");
+ name = json_object_get (result, "name");
+ location = json_object_get (geometry, "location");
+ gp.g.lat = json_real_value (json_object_get (location, "lat"));
+ gp.g.lng = json_real_value (json_object_get (location, "lng"));
+ gp.c.pro=projection_mg;
+ struct coord c;
+ transform_from_geo (projection_mg, &gp.g, &c);
+ gp.c.x=c.x;
+ gp.c.y=c.y;
+ dbg(lvl_error, "Item %s as at : %4.16f x %4.16f [ %x x %x ]\n", json_string_value(name), gp.g.lat, gp.g.lng, gp.c.x, gp.c.y);
+ gp.name=g_strdup(json_string_value(name));
+ json_decref (root);
+ return gp;
+}
+
+/**
+ * @brief Set the destination to a given place, read from a widget
+ * @param[in] this - the current gui_priv object
+ * wm - the widget containing the place reference
+ * data - container for extra datas. Not used here
+ *
+ * @return nothing
+ *
+ * Set the destination to a given place, read from a widget
+ *
+ */
+static void
+googlesearch_set_destination (struct gui_priv *this, struct widget *wm, void *data)
+{
+ struct googleplace gp=fetch_googleplace_details(wm->name);
+ dbg(lvl_error, "%s c=%d:0x%x,0x%x [ %4.16f x %4.16f }\n", gp.name, gp.c.pro, gp.c.x, gp.c.y, gp.g.lat, gp.g.lng);
+ navit_set_destination (this->nav, &gp.c, gp.name, 1);
+ gui_internal_prune_menu (this, NULL);
+}
+
+/**
+ * @brief Updates the search results list, autocompletion
+ * @param[in] this - the current gui_priv object
+ * wm - the widget containing the text input
+ * data - container for extra datas. Not used here
+ *
+ * @return nothing
+ *
+ * Updates the search results list, refining the search as the user types
+ *
+ */
+static void
+gui_internal_cmd_googlesearch_filter_do(struct gui_priv *this, struct widget *wm, void *data)
+{
+ struct widget *w=data;
+
+ if(!w->text)
+ return;
+
+ char *prefix = 0;
+ char track_icon[64];
+ struct coord_geo g;
+
+ struct transformation *trans;
+ trans = navit_get_trans (this->nav);
+ struct coord c;
+ // We want the search to be relative to where we clicked on the map
+ c.x = this->clickp.x;
+ c.y = this->clickp.y;
+
+ transform_to_geo (transform_get_projection (trans), &c, &g);
+
+ dbg(lvl_info, "googlesearch called for %d x %d, converted to %4.16f x %4.16f\n", wm->c.x, wm->c.y, g.lat, g.lng);
+
+ char *baseurl = "https://maps.googleapis.com/maps/api/place/autocomplete/json?";
+ char url[256];
+ char lat_string[50];
+ snprintf (lat_string, 50, "%f", g.lat);
+ char lng_string[50];
+ snprintf (lng_string, 50, "%f", g.lng);
+ char *radius="20000";
+
+ strcpy (url, g_strdup_printf ("%slocation=%s,%s&key=%s&input=%s&radius=%s", baseurl, lat_string, lng_string, googleplaces_apikey, w->text, radius));
+
+ char * js=fetch_url_to_string(url);
+
+ json_t *root;
+ json_error_t error;
+ root = json_loads (js, 0, &error);
+
+ json_t *response, *venues;
+ response = json_object_get (root, "response");
+ venues = json_object_get (root, "predictions");
+
+ struct timespec now, tmstart;
+ clock_gettime(CLOCK_REALTIME, &tmstart);
+
+ int i = 0;
+
+ // The autocomplete API returns max 5 results
+ pthread_t thread_id[5];
+ // struct googleplace gp[5];
+ for (i = 0; i < json_array_size (venues); i++)
+ {
+ json_t *venue, *description, *id;
+ venue = json_array_get (venues, i);
+ description = json_object_get (venue, "description");
+ id = json_object_get (venue, "place_id");
+
+ dbg(lvl_info, "Found [%i] %s with id %s\n", i, json_string_value (description), json_string_value (id));
+ strcpy (track_icon, "default");
+#if 0
+ /* Threads were not efficient on a mobile connection. They have been deactivated */
+ gp[i].id=g_strdup(json_string_value (id));
+ gp[i].description=g_strdup(json_string_value (description));
+ gp[i].gui_priv=this;
+ gp[i].wm=wm;
+ pthread_create( &thread_id[i], NULL, &fetch_googleplace_details_as_thread, &gp[i] );
+#endif
+
+ struct widget *wtable=gui_internal_menu_data(this)->search_list;
+ struct widget *wc;
+ struct widget *row;
+ gui_internal_widget_append (wtable, row =
+ gui_internal_widget_table_row_new (this,
+ gravity_left | orientation_horizontal | flags_fill));
+ gui_internal_widget_append (row, wc =
+ gui_internal_button_new_with_callback (this,
+ json_string_value(description),
+ image_new_xs (this, "gui_active"),
+ gravity_left_center | orientation_horizontal | flags_fill,
+ googlesearch_set_destination,
+ NULL));
+
+ wc->selection_id = wm->selection_id;
+ wc->name = g_strdup (json_string_value(id));
+ wc->c.pro = projection_mg;
+ wc->prefix = g_strdup (wm->prefix);
+ }
+#if 0
+ int j;
+ for(j=0; j < json_array_size (venues); j++)
+ {
+ dbg(lvl_info,"Checking thread #%i with p:%p\n",j,thread_id[j]);
+ pthread_join( thread_id[j], NULL);
+ }
+#endif
+ clock_gettime(CLOCK_REALTIME, &now);
+
+ double seconds = (double)((now.tv_sec+now.tv_nsec*1e-9) - (double)(tmstart.tv_sec+tmstart.tv_nsec*1e-9));
+ dbg(lvl_error,"wall time %fs\n", seconds);
+ gui_internal_menu_render(this);
+ g_free (prefix);
+ json_decref (root);
+}
+
+/**
+ * @brief Callback called when the user types in the search box
+ * @param[in] this - the current gui_priv object
+ * wm - the parent widget
+ * data - container for extra datas. Not used here
+ *
+ * @return nothing
+ *
+ * This callback is called everytime the user types in the search box
+ *
+ */
+static void
+gui_internal_cmd_google_filter_changed(struct gui_priv *this, struct widget *wm, void *data)
+{
+// if (wm->text && wm->reason==gui_internal_reason_keypress_finish) {
+// gui_internal_cmd_googlesearch_filter_do(this, wm, wm);
+// }
+ if (wm->text) {
+ gui_internal_widget_table_clear(this, gui_internal_menu_data(this)->search_list);
+ gui_internal_cmd_googlesearch_filter_do(this, wm, wm);
+ }
+}
+
+/**
+ * @brief Builds the Googleplaces search menu
+ * @param[in] this - the current gui_priv object
+ * wm - the parent widget
+ * data - container for extra datas. Not used here
+ *
+ * @return nothing
+ *
+ * Builds the Googleplaces search menu
+ *
+ */
+void
+gui_internal_googlesearch_search(struct gui_priv *this, struct widget *wm, void *data)
+{
+ struct widget *wb, *w, *wr, *wk, *we, *wl;
+ int keyboard_mode;
+ keyboard_mode=2+gui_internal_keyboard_init_mode(getenv("LANG"));
+ wb=gui_internal_menu(this,"Search");
+ w=gui_internal_box_new(this, gravity_center|orientation_vertical|flags_expand|flags_fill);
+ gui_internal_widget_append(wb, w);
+ wr=gui_internal_box_new(this, gravity_top_center|orientation_vertical|flags_expand|flags_fill);
+ gui_internal_widget_append(w, wr);
+ we=gui_internal_box_new(this, gravity_left_center|orientation_horizontal|flags_fill);
+ gui_internal_widget_append(wr, we);
+
+ gui_internal_widget_append(we, wk=gui_internal_label_new(this, NULL));
+ wk->state |= STATE_EDIT|STATE_EDITABLE;
+ wk->func=gui_internal_cmd_google_filter_changed;
+ wk->background=this->background;
+ wk->flags |= flags_expand|flags_fill;
+ wk->name=g_strdup("POIsFilter");
+ wk->c=wm->c;
+ dbg(lvl_error, "googlesearch filter called for %d x %d\n", this->clickp.x, this->clickp.y);
+ gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_active")));
+ wb->state |= STATE_SENSITIVE;
+ wb->func = gui_internal_cmd_googlesearch_filter_do;
+ wb->name=g_strdup("NameFilter");
+ wb->c=this->clickp;
+ wb->data=wk;
+ wl=gui_internal_widget_table_new(this,gravity_left_top | flags_fill | flags_expand |orientation_vertical,1);
+ gui_internal_widget_append(wr, wl);
+ gui_internal_menu_data(this)->search_list=wl;
+
+ if (this->keyboard)
+ gui_internal_widget_append(w, gui_internal_keyboard(this,keyboard_mode));
+ gui_internal_menu_render(this);
+}
diff --git a/navit/gui/internal/gui_internal_googlesearch.h b/navit/gui/internal/gui_internal_googlesearch.h
new file mode 100644
index 000000000..88372cbdc
--- /dev/null
+++ b/navit/gui/internal/gui_internal_googlesearch.h
@@ -0,0 +1,2 @@
+void googlesearch_navit_init();
+void gui_internal_googlesearch_search(struct gui_priv *this, struct widget *wm, void *data);
diff --git a/navit/network.c b/navit/network.c
new file mode 100644
index 000000000..3683dd5de
--- /dev/null
+++ b/navit/network.c
@@ -0,0 +1,148 @@
+#include "curl/curl.h"
+#include <navit/debug.h>
+#include "unistd.h"
+#include "stddef.h"
+
+struct string {
+ char *ptr;
+ size_t len;
+};
+
+ /**
+ * @brief Initialize a "string" object
+ *
+ * @param string the struct string pointer
+ * @returns nothing
+ */
+void
+init_string(struct string *s)
+{
+ s->len = 0;
+ s->ptr = malloc(s->len + 1);
+ if (s->ptr == NULL) {
+ dbg(lvl_error, "malloc() failed\n");
+ }
+ s->ptr[0] = '\0';
+}
+
+ /**
+ * @brief store the incoming data into a dynamically
+ * growing allocated buffer. Typical when using libcurl.
+ *
+ * @param ptr pointer to the delivered data
+ * @param size size of the delivered data
+ * @param nmemb number of mem blocks
+ * @param s CURLOPT_WRITEDATA option
+ * @returns the size of the buffer after expansion
+ */
+size_t
+writefunc(void *ptr, size_t size, size_t nmemb, struct string *s)
+{
+ size_t new_len = s->len + size * nmemb;
+ s->ptr = realloc(s->ptr, new_len + 1);
+ if (s->ptr == NULL) {
+ dbg(lvl_error, "realloc() failed\n");
+ }
+ memcpy(s->ptr + s->len, ptr, size * nmemb);
+ s->ptr[new_len] = '\0';
+ s->len = new_len;
+
+ return size * nmemb;
+}
+
+ /**
+ * @brief Replace all occurrences of the search string with the replacement string
+ * From http://creativeandcritical.net/str-replace-c/
+ *
+ * @param str the string to replace in
+ * @param old the content to replace
+ * @param new the new content
+ * @returns the updated string
+ */
+char *
+replace_str(const char *str, const char *old, const char *new)
+{
+ char *ret, *r;
+ const char *p, *q;
+ size_t oldlen = strlen(old);
+ size_t count, retlen, newlen = strlen(new);
+
+ if (oldlen != newlen) {
+ for (count = 0, p = str; (q = strstr(p, old)) != NULL;
+ p = q + oldlen)
+ count++;
+ /* this is undefined if p - str > PTRDIFF_MAX */
+ retlen = p - str + strlen(p) + count * (newlen - oldlen);
+ } else
+ retlen = strlen(str);
+
+ if ((ret = malloc(retlen + 1)) == NULL)
+ return NULL;
+
+ for (r = ret, p = str; (q = strstr(p, old)) != NULL;
+ p = q + oldlen) {
+ /* this is undefined if q - p > PTRDIFF_MAX */
+ ptrdiff_t l = q - p;
+ memcpy(r, p, l);
+ r += l;
+ memcpy(r, new, newlen);
+ r += newlen;
+ }
+ strcpy(r, p);
+
+ return ret;
+}
+
+
+ /**
+ * @brief fetch the content from a url
+ *
+ * @param url the url to fetch content from
+ * @returns the content of the webpage at the given url
+ */
+char *
+fetch_url_to_string(char *url)
+{
+ struct string s;
+ char *sanitized_url = replace_str(url, " ", "%20");
+ init_string(&s);
+ CURL *curl;
+ curl_global_init(CURL_GLOBAL_ALL);
+ curl = curl_easy_init();
+ curl_easy_setopt(curl, CURLOPT_URL, sanitized_url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
+ curl_easy_perform(curl);
+ curl_easy_cleanup(curl);
+ dbg(lvl_info, "url %s gave %s\n", sanitized_url, s.ptr);
+ dbg(lvl_error, "url %s gave js of size %i\n", sanitized_url,
+ strlen(s.ptr));
+ free(sanitized_url);
+ return strdup(s.ptr);
+}
+
+ /**
+ * @brief perform a http/post and returns the result
+ *
+ * @param url the url, including the encoded parameters
+ * @returns the html response
+ */
+char *
+post_to_string(char *url)
+{
+ struct string s;
+ init_string(&s);
+ CURL *curl;
+ curl_global_init(CURL_GLOBAL_ALL);
+ curl = curl_easy_init();
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+ curl_easy_setopt(curl, CURLOPT_URL, url);
+ curl_easy_setopt(curl, CURLOPT_POST, 1);
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, url);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &s);
+ curl_easy_perform(curl);
+ free(s.ptr);
+ curl_easy_cleanup(curl);
+ return g_strdup(s.ptr);
+}
diff --git a/navit/network.h b/navit/network.h
new file mode 100644
index 000000000..147f8f94c
--- /dev/null
+++ b/navit/network.h
@@ -0,0 +1,15 @@
+#ifndef NAVIT_NETWORK_H
+#define NAVIT_NETWORK_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char * fetch_url_to_string(char * url);
+char * post_to_string(char * url);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/navit/xpm/googleplaces.svg b/navit/xpm/googleplaces.svg
new file mode 100644
index 000000000..3b1062065
--- /dev/null
+++ b/navit/xpm/googleplaces.svg
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="256"
+ height="256"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="google.svg"
+ version="1.0"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2555">
+ <stop
+ style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
+ offset="0"
+ id="stop2557" />
+ <stop
+ style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
+ offset="1"
+ id="stop2559" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2555"
+ id="linearGradient2449"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.5914583,0,0,0.5914584,210.0216,142.2324)"
+ x1="-344.15295"
+ y1="274.711"
+ x2="-395.84943"
+ y2="425.39993" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.35"
+ inkscape:cx="351.23943"
+ inkscape:cy="155.4078"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="853"
+ inkscape:window-height="674"
+ inkscape:window-x="1"
+ inkscape:window-y="281"
+ showgrid="false"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>User:ZyMOS</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+ <dc:description />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>Open Icon Library</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-373.642,-318.344)">
+ <rect
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ transform="scale(-1,1)"
+ ry="35.487503"
+ rx="35.487503"
+ y="328.84921"
+ x="-619.14587"
+ height="234.98955"
+ width="235.00784"
+ id="rect1942"
+ style="fill:#194fc8;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.87500000000000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.87500000000000000, 1.75000000000000000;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ sodipodi:nodetypes="ccccsssc"
+ id="path1950"
+ d="M 557.05665,338.89518 L 446.22721,338.89518 C 416.89033,338.89518 393.27256,362.70492 393.27256,392.28025 L 393.27256,500.40761 C 394.22216,523.49366 397.87485,508.89915 404.82758,483.3329 C 412.90814,453.61975 439.22406,427.65003 471.27219,408.1872 C 495.73352,393.33195 523.11328,383.84595 572.95174,382.94353 C 601.21656,382.43177 598.72124,346.26062 557.05665,338.89518 z"
+ style="opacity:1;fill:url(#linearGradient2449);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.87500000000000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.87500000000000000, 1.75000000000000000;stroke-dashoffset:0;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:232.84083557px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.00000024;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Arial;-inkscape-font-specification:Arial"
+ x="441.18173"
+ y="480.17572"
+ id="text4746"
+ sodipodi:linespacing="125%"
+ transform="scale(1.0013237,0.99867803)"><tspan
+ sodipodi:role="line"
+ id="tspan4748"
+ x="441.18173"
+ y="480.17572"
+ style="font-size:232.84083557px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:3.00000024;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Georgia;-inkscape-font-specification:Georgia">g</tspan></text>
+ </g>
+</svg>