[geocode-glib] ip-server: Add support for Wi-Fi based search
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geocode-glib] ip-server: Add support for Wi-Fi based search
- Date: Mon, 15 Apr 2013 13:15:34 +0000 (UTC)
commit 8a3fb3e6ebcf9818b1ac1af3b3856702d11975c3
Author: Satabdi Das <satabdidas gmail com>
Date: Fri Apr 5 22:17:57 2013 +0530
ip-server: Add support for Wi-Fi based search
Add geolocalisation using the client's Wi-Fi APs.
If the strength and names of Wi-Fi APs are passed through the
query string, we'll make a request to Google's web service.
Should the request fail, we will fall back to using the IP
address to locate the user.
https://bugzilla.gnome.org/show_bug.cgi?id=696543
geocode-glib/geocode-ip-server/geoip-lookup.c | 215 ++++++++++++++++++++------
1 file changed, 171 insertions(+), 44 deletions(-)
---
diff --git a/geocode-glib/geocode-ip-server/geoip-lookup.c b/geocode-glib/geocode-ip-server/geoip-lookup.c
index 5a6dfee..1cc1dbf 100644
--- a/geocode-glib/geocode-ip-server/geoip-lookup.c
+++ b/geocode-glib/geocode-ip-server/geoip-lookup.c
@@ -5,9 +5,12 @@
#include <glib.h>
#include <json-glib/json-glib.h>
#include <libsoup/soup.h>
+#include <string.h>
#include "geoip-server.h"
+#define WIFI_LOOKUP_BASE_URI
"https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true"
+
static const char *attribution_text = "This product includes GeoLite data created by MaxMind, available from
http://www.maxmind.com\n";
static char *error_message_array [] = {
@@ -229,29 +232,6 @@ validate_ip_address (const char *ipaddress)
}
static char *
-get_ipaddress_from_query (void)
-{
- GHashTable *table;
- const char *data;
- char *value;
-
- data = g_getenv ("QUERY_STRING");
- if (data == NULL)
- return NULL;
-
- table = soup_form_decode (data);
- value = g_strdup (g_hash_table_lookup (table, "ip"));
- g_hash_table_destroy (table);
-
- if (validate_ip_address (value))
- return value;
-
- g_free (value);
-
- return NULL;
-}
-
-static char *
get_client_ipaddress (void)
{
const char *data;
@@ -289,48 +269,195 @@ get_client_ipaddress (void)
return g_strdup (data);
}
}
+ print_error_in_json (INVALID_IP_ADDRESS_ERR, NULL);
return NULL;
}
-static char *
-get_ipaddress (void)
+/* parse_json_for_wifi function parses the JSON output from
+ * google web service and converts it into the JSON format
+ * used by geocode-glib library. On failure, it returns FALSE.
+ * It doesn't print any error message since the IP based search
+ * is performed if Wi-Fi based search fails.
+ */
+static gboolean
+parse_json_for_wifi (const char *data)
{
- char *value;
+ JsonParser *parser;
+ JsonNode *root;
+ JsonObject *root_object;
+ JsonObject *loc_obj;
+ JsonBuilder *builder;
+ GError *error;
- value = get_ipaddress_from_query ();
- if (value) {
- if (validate_ip_address (value) == FALSE) {
- print_error_in_json (INVALID_IP_ADDRESS_ERR, NULL);
- g_free (value);
- return NULL;
- }
+ parser = json_parser_new ();
+ if (json_parser_load_from_data (parser, data, -1, &error) == FALSE) {
+ g_object_unref (parser);
+ return FALSE;
}
- else {
- value = get_client_ipaddress ();
- if (!value) {
- print_error_in_json (INVALID_IP_ADDRESS_ERR, NULL);
- g_free (value);
- return NULL;
+
+ root = json_parser_get_root (parser);
+ root_object = json_node_get_object (root);
+
+ loc_obj = json_object_get_object_member (root_object, "location");
+
+ if (loc_obj == NULL) {
+ return FALSE;
+ }
+ builder = json_builder_new ();
+ json_builder_begin_object (builder);
+ json_builder_set_member_name (builder, "latitude");
+ json_builder_add_double_value (builder,
+ json_object_get_double_member (loc_obj, "lat"));
+ json_builder_set_member_name (builder, "longitude");
+ json_builder_add_double_value (builder,
+ json_object_get_double_member (loc_obj, "lng"));
+
+
+ json_builder_set_member_name (builder, "accuracy");
+ json_builder_add_double_value (builder,
+ json_object_get_double_member (root_object, "accuracy"));
+
+ /* TODO: What should the text of the attribution text be? */
+ json_builder_end_object (builder);
+ print_json_data (builder);
+ g_object_unref (parser);
+ g_object_unref (builder);
+ return TRUE;
+}
+
+static gboolean
+wifi_ap_lookup (const char *data)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ char *final_uri;
+
+ session = soup_session_sync_new ();
+ final_uri = g_strconcat (WIFI_LOOKUP_BASE_URI, "&", data, NULL);
+ msg = soup_message_new ("GET", final_uri);
+ g_free (final_uri);
+
+ soup_session_send_message (session, msg);
+ if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
+ return parse_json_for_wifi (msg->response_body->data);
+ }
+
+ return FALSE;
+}
+
+/* Taken from libsoup/soup-form.c */
+#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
+#define HEXCHAR(s) ((XDIGIT (s[1]) << 4) + XDIGIT (s[2]))
+
+static gboolean
+form_decode (char *part)
+{
+ unsigned char *s, *d;
+
+ s = d = (unsigned char *)part;
+ do {
+ if (*s == '%') {
+ if (!g_ascii_isxdigit (s[1]) ||
+ !g_ascii_isxdigit (s[2]))
+ return FALSE;
+ *d++ = HEXCHAR (s);
+ s += 2;
+ } else if (*s == '+')
+ *d++ = ' ';
+ else
+ *d++ = *s;
+ } while (*s++);
+
+ return TRUE;
+}
+
+/**
+ * decode_query_string () returns a hashtable of Wi-Fi AP
+ * details and fills the ipaddress variable if there's any
+ * ip address in the query string.
+ **/
+static GHashTable *
+decode_query_string (const char *encoded_form,
+ char **ipaddress)
+{
+ GHashTable *form_data_set;
+ char **pairs, *eq, *name, *value;
+ int i;
+
+ form_data_set = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+ g_free, NULL);
+ pairs = g_strsplit (encoded_form, "&", -1);
+ for (i = 0; pairs[i]; i++) {
+ name = pairs[i];
+
+ eq = strchr (name, '=');
+ if (!eq)
+ goto end;
+ *eq = '\0';
+ value = eq + 1;
+
+ if (!form_decode (name) || !form_decode (value))
+ goto end;
+ if (strcmp (name, "wifi") == 0) {
+ g_hash_table_insert (form_data_set, name, value);
+ continue;
+ } else if (strcmp (name, "ip") == 0) {
+ *ipaddress = g_strdup (value);
}
+end:
+ g_free (name);
}
- return value;
+ g_free (pairs);
+
+ return form_data_set;
}
int
main (void)
{
- char *ipaddress;
+ GHashTable *ht;
+ char *ipaddress = NULL;
+ const char *data;
g_type_init ();
g_print ("Content-type: text/plain;charset=us-ascii\n\n");
- ipaddress = get_ipaddress ();
+ /* If the query string contains a Wi-Fi field, request
+ * the information from the Google web service. otherwise
+ * use MaxMind's database for an IP-based search.
+ * IP-based search is also used as a fallback option
+ * when the Wi-Fi based lookup returns an error. */
+ data = g_getenv ("QUERY_STRING");
+ if (data != NULL) {
+ ht = decode_query_string (data, &ipaddress);
+ if (g_hash_table_size (ht) > 0) {
+ char *wifi_ap = soup_form_encode_hash (ht);
+ if (wifi_ap_lookup (wifi_ap) != FALSE) {
+ g_hash_table_destroy (ht);
+ g_free (wifi_ap);
+ return 0;
+ }
+ g_free (wifi_ap);
+ }
+ g_hash_table_destroy (ht);
+ }
+
+ if (ipaddress) {
+ if (validate_ip_address (ipaddress) == FALSE) {
+ print_error_in_json (INVALID_IP_ADDRESS_ERR, NULL);
+ g_free (ipaddress);
+ return 1;
+ }
+ } else {
+ ipaddress = get_client_ipaddress ();
+ }
+
if (!ipaddress)
- return 0;
+ return 1;
ip_addr_lookup (ipaddress);
-
g_free (ipaddress);
+
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]