diff options
author | Kibum Kim <kb0929.kim@samsung.com> | 2012-01-07 00:46:29 +0900 |
---|---|---|
committer | Kibum Kim <kb0929.kim@samsung.com> | 2012-01-07 00:46:29 +0900 |
commit | 0c44dc6cd8d3ede16172f22fa2b7c6af4459e55d (patch) | |
tree | 327fd58b5a721a2ecf835f2eccffde08cdbc4070 /.pc/tizen.patch/src | |
parent | 9f11ee482a4a28d6e85613ac5c765c588fdf20aa (diff) | |
download | geoclue-0c44dc6cd8d3ede16172f22fa2b7c6af4459e55d.tar.gz geoclue-0c44dc6cd8d3ede16172f22fa2b7c6af4459e55d.tar.bz2 geoclue-0c44dc6cd8d3ede16172f22fa2b7c6af4459e55d.zip |
Git init
Diffstat (limited to '.pc/tizen.patch/src')
-rwxr-xr-x | .pc/tizen.patch/src/Makefile.am | 90 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/client.c | 994 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/connectivity-connman.c | 739 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/connectivity-connman.h | 56 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/connectivity-networkmanager.c | 369 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/connectivity-networkmanager.h | 56 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/connectivity.c | 276 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/connectivity.h | 73 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/geoclue | 3 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/main.c | 231 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/master-provider.c | 1309 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/master.c | 211 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/org.freedesktop.Geoclue.gschema.xml | 15 | ||||
-rwxr-xr-x | .pc/tizen.patch/src/test-connectivity.c | 97 |
14 files changed, 4519 insertions, 0 deletions
diff --git a/.pc/tizen.patch/src/Makefile.am b/.pc/tizen.patch/src/Makefile.am new file mode 100755 index 0000000..ebb5f22 --- /dev/null +++ b/.pc/tizen.patch/src/Makefile.am @@ -0,0 +1,90 @@ +libexec_PROGRAMS = geoclue-master +noinst_LTLIBRARIES = libconnectivity.la +noinst_PROGRAMS = test-connectivity + +AM_CFLAGS = \ + -I$(top_srcdir) \ + -I$(srcdir) \ + -I$(top_builddir) \ + -DGEOCLUE_PROVIDERS_DIR=\""$(datadir)/geoclue-providers"\" \ + $(GEOCLUE_CFLAGS) \ + $(MASTER_CFLAGS) \ + $(CONNECTIVITY_CFLAGS) + +geoclue_master_LDADD = \ + $(top_builddir)/geoclue/libgeoclue.la \ + libconnectivity.la \ + $(GEOCLUE_LIBS) \ + $(MASTER_LIBS) + +NOINST_H_FILES = \ + main.h \ + master.h \ + master-provider.h \ + client.h + +libconnectivity_la_SOURCES = \ + connectivity.h \ + connectivity-networkmanager.h \ + connectivity-conic.h \ + connectivity-connman.h \ + connectivity.c \ + connectivity-networkmanager.c \ + connectivity-conic.c \ + connectivity-connman.c + +libconnectivity_la_LIBADD = $(CONNECTIVITY_LIBS) + +test_connectivity_SOURCES = test-connectivity.c +test_connectivity_LDADD = libconnectivity.la $(GEOCLUE_LIBS) + +geoclue_master_SOURCES = \ + $(NOINST_H_FILES) \ + client.c \ + main.c \ + master.c \ + master-provider.c + +BUILT_SOURCES = \ + gc-iface-master-glue.h \ + gc-iface-master-client-glue.h + +%-glue.h: stamp-%-glue.h + @true +stamp-gc-iface-master-glue.h: ../interfaces/gc-iface-master.xml + $(AM_V_GEN) $(DBUS_BINDING_TOOL) --prefix=gc_iface_master --mode=glib-server $< > xgen-$(@F) \ + && (cmp -s xgen-$(@F) $(@F:stamp-%=%) || cp xgen-$(@F) $(@F:stamp-%=%)) \ + && rm -f xgen-$(@F) \ + && echo timestamp > $(@F) + +stamp-gc-iface-master-client-glue.h: ../interfaces/gc-iface-master-client.xml + $(AM_V_GEN) $(DBUS_BINDING_TOOL) --prefix=gc_iface_master_client --mode=glib-server $< > xgen-$(@F) \ + && (cmp -s xgen-$(@F) $(@F:stamp-%=%) || cp xgen-$(@F) $(@F:stamp-%=%)) \ + && rm -f xgen-$(@F) \ + && echo timestamp > $(@F) + +servicedir = $(DBUS_SERVICES_DIR) +service_in_files = org.freedesktop.Geoclue.Master.service.in +service_DATA = $(service_in_files:.service.in=.service) + +$(service_DATA): $(service_in_files) Makefile + $(AM_V_GEN) sed -e "s|\@libexecdir\@|$(libexecdir)|" $< > $@ + +convertdir = $(datadir)/GConf/gsettings +convert_DATA = geoclue + +gsettings_SCHEMAS = org.freedesktop.Geoclue.gschema.xml +@GSETTINGS_RULES@ + +EXTRA_DIST = \ + $(service_in_files) \ + $(gsettings_SCHEMAS) \ + $(convert_DATA) + +CLEANFILES = \ + $(BUILT_SOURCES) \ + stamp-gc-iface-master-glue.h \ + stamp-gc-iface-master-client-glue.h + +DISTCLEANFILES = \ + $(service_DATA) diff --git a/.pc/tizen.patch/src/client.c b/.pc/tizen.patch/src/client.c new file mode 100755 index 0000000..dbe5361 --- /dev/null +++ b/.pc/tizen.patch/src/client.c @@ -0,0 +1,994 @@ +/* + * Geoclue + * client.c - Geoclue Master Client + * + * Authors: Iain Holmes <iain@openedhand.com> + * Jussi Kukkonen <jku@o-hand.com> + * Copyright 2007-2008 by Garmin Ltd. or its subsidiaries + * 2008 OpenedHand Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** TODO + * + * might want to write a testing-provider with a gui for + * choosing what to emit... + * + **/ + + +#include <config.h> + +#include <geoclue/geoclue-error.h> +#include <geoclue/geoclue-marshal.h> + +#include <geoclue/gc-provider.h> +#include <geoclue/gc-iface-position.h> +#include <geoclue/gc-iface-address.h> + +#include "client.h" + +#define GEOCLUE_POSITION_INTERFACE_NAME "org.freedesktop.Geoclue.Position" +#define GEOCLUE_ADDRESS_INTERFACE_NAME "org.freedesktop.Geoclue.Address" + +enum { + ADDRESS_PROVIDER_CHANGED, + POSITION_PROVIDER_CHANGED, + LAST_SIGNAL +}; +static guint32 signals[LAST_SIGNAL] = {0, }; + + +enum { + POSITION_CHANGED, /* signal id of current provider */ + ADDRESS_CHANGED, /* signal id of current provider */ + LAST_PRIVATE_SIGNAL +}; + +typedef struct _GcMasterClientPrivate { + guint32 signals[LAST_PRIVATE_SIGNAL]; + + GeoclueAccuracyLevel min_accuracy; + int min_time; + gboolean require_updates; + GeoclueResourceFlags allowed_resources; + + gboolean position_started; + GcMasterProvider *position_provider; + GList *position_providers; + gboolean position_provider_choice_in_progress; + time_t last_position_changed; + + gboolean address_started; + GcMasterProvider *address_provider; + GList *address_providers; + gboolean address_provider_choice_in_progress; + time_t last_address_changed; + +} GcMasterClientPrivate; + +#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GC_TYPE_MASTER_CLIENT, GcMasterClientPrivate)) + + + +static gboolean gc_iface_master_client_set_requirements (GcMasterClient *client, + GeoclueAccuracyLevel min_accuracy, + int min_time, + gboolean require_updates, + GeoclueResourceFlags allowed_resources, + GError **error); +static gboolean gc_iface_master_client_position_start (GcMasterClient *client, GError **error); +static gboolean gc_iface_master_client_address_start (GcMasterClient *client, GError **error); +static gboolean gc_iface_master_client_get_address_provider (GcMasterClient *client, + char **name, + char **description, + char **service, + char **path, + GError **error); +static gboolean gc_iface_master_client_get_position_provider (GcMasterClient *client, + char **name, + char **description, + char **service, + char **path, + GError **error); + +static void gc_master_client_geoclue_init (GcIfaceGeoclueClass *iface); +static void gc_master_client_position_init (GcIfacePositionClass *iface); +static void gc_master_client_address_init (GcIfaceAddressClass *iface); + +G_DEFINE_TYPE_WITH_CODE (GcMasterClient, gc_master_client, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE(GC_TYPE_IFACE_GEOCLUE, + gc_master_client_geoclue_init) + G_IMPLEMENT_INTERFACE (GC_TYPE_IFACE_POSITION, + gc_master_client_position_init) + G_IMPLEMENT_INTERFACE (GC_TYPE_IFACE_ADDRESS, + gc_master_client_address_init)) + +#include "gc-iface-master-client-glue.h" + + +static gboolean status_change_requires_provider_change (GList *provider_list, + GcMasterProvider *current_provider, + GcMasterProvider *changed_provider, + GeoclueStatus status); +static void gc_master_client_emit_position_changed (GcMasterClient *client); +static void gc_master_client_emit_address_changed (GcMasterClient *client); +static gboolean gc_master_client_choose_position_provider (GcMasterClient *client, + GList *providers); +static gboolean gc_master_client_choose_address_provider (GcMasterClient *client, + GList *providers); + + +static void +status_changed (GcMasterProvider *provider, + GeoclueStatus status, + GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + g_debug ("client: provider %s status changed: %d", gc_master_provider_get_name (provider), status); + + /* change providers if needed (and if we're not choosing provider already) */ + + if (!priv->position_provider_choice_in_progress && + status_change_requires_provider_change (priv->position_providers, + priv->position_provider, + provider, status) && + gc_master_client_choose_position_provider (client, + priv->position_providers)) { + + /* we have a new position provider, force-emit position_changed */ + gc_master_client_emit_position_changed (client); + } + + if (!priv->address_provider_choice_in_progress && + status_change_requires_provider_change (priv->address_providers, + priv->address_provider, + provider, status) && + gc_master_client_choose_address_provider (client, + priv->address_providers)) { + + /* we have a new address provider, force-emit address_changed */ + gc_master_client_emit_address_changed (client); + } +} + +static void +accuracy_changed (GcMasterProvider *provider, + GcInterfaceFlags interface, + GeoclueAccuracyLevel level, + GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GcInterfaceAccuracy *accuracy_data; + + accuracy_data = g_new0 (GcInterfaceAccuracy, 1); + g_debug ("client: %s accuracy changed (%d)", + gc_master_provider_get_name (provider), level); + + accuracy_data->interface = interface; + accuracy_data->accuracy_level = priv->min_accuracy; + switch (interface) { + case GC_IFACE_POSITION: + priv->position_providers = + g_list_sort_with_data (priv->position_providers, + (GCompareDataFunc)gc_master_provider_compare, + accuracy_data); + if (priv->position_provider_choice_in_progress) { + g_debug (" ...but provider choice in progress"); + } else if (gc_master_client_choose_position_provider (client, + priv->position_providers)) { + gc_master_client_emit_position_changed (client); + } + break; + + case GC_IFACE_ADDRESS: + priv->address_providers = + g_list_sort_with_data (priv->address_providers, + (GCompareDataFunc)gc_master_provider_compare, + accuracy_data); + if (priv->address_provider_choice_in_progress) { + g_debug (" ...but provider choice in progress"); + } else if (gc_master_client_choose_address_provider (client, + priv->address_providers)) { + gc_master_client_emit_address_changed (client); + } + break; + + default: + g_assert_not_reached (); + } + g_free (accuracy_data); +} + +static void +position_changed (GcMasterProvider *provider, + GeocluePositionFields fields, + int timestamp, + double latitude, + double longitude, + double altitude, + GeoclueAccuracy *accuracy, + GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + time_t now; + + now = time (NULL); + if (priv->min_time > (now - priv->last_position_changed)) { + /* NOTE: currently no-one makes sure there is an emit + * after min_time */ + return; + } + priv->last_position_changed = now; + + gc_iface_position_emit_position_changed + (GC_IFACE_POSITION (client), + fields, + timestamp, + latitude, longitude, altitude, + accuracy); +} + +static void +address_changed (GcMasterProvider *provider, + int timestamp, + GHashTable *details, + GeoclueAccuracy *accuracy, + GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + time_t now; + + now = time (NULL); + if (priv->min_time > (now - priv->last_address_changed)) { + /* NOTE: currently no-one makes sure there is an emit + * after min_time */ + return; + } + priv->last_address_changed = now; + + gc_iface_address_emit_address_changed + (GC_IFACE_ADDRESS (client), + timestamp, + details, + accuracy); +} + +/*if changed_provider status changes, do we need to choose a new provider? */ +static gboolean +status_change_requires_provider_change (GList *provider_list, + GcMasterProvider *current_provider, + GcMasterProvider *changed_provider, + GeoclueStatus status) +{ + if (!provider_list) { + return FALSE; + + } else if (current_provider == NULL) { + return (status == GEOCLUE_STATUS_AVAILABLE); + + } else if (current_provider == changed_provider) { + return (status != GEOCLUE_STATUS_AVAILABLE); + + }else if (status != GEOCLUE_STATUS_AVAILABLE) { + return FALSE; + + } + + while (provider_list) { + GcMasterProvider *p = provider_list->data; + if (p == current_provider) { + /* not interested in worse-than-current providers */ + return FALSE; + } + if (p == changed_provider) { + /* changed_provider is better than current */ + return (status == GEOCLUE_STATUS_AVAILABLE); + } + provider_list = provider_list->next; + } + return FALSE; +} + +static void +gc_master_client_connect_common_signals (GcMasterClient *client, GList *providers) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GList *l; + + /* connect to common signals if the provider is not already connected */ + l = providers; + while (l) { + GcMasterProvider *p = l->data; + if (!g_list_find (priv->address_providers, p) && + !g_list_find (priv->position_providers, p)) { + g_debug ("client: connecting to '%s' accuracy-changed and status-changed", gc_master_provider_get_name (p)); + g_signal_connect (G_OBJECT (p), + "status-changed", + G_CALLBACK (status_changed), + client); + g_signal_connect (G_OBJECT (p), + "accuracy-changed", + G_CALLBACK (accuracy_changed), + client); + } + l = l->next; + } +} + +static void +gc_master_client_unsubscribe_providers (GcMasterClient *client, GList *provider_list, GcInterfaceFlags iface) +{ + while (provider_list) { + GcMasterProvider *provider = provider_list->data; + + gc_master_provider_unsubscribe (provider, client, iface); + provider_list = provider_list->next; + } + +} + +/* get_best_provider will return the best provider with status == GEOCLUE_STATUS_AVAILABLE. + * It will also "subscribe" to that provider and all better ones, and unsubscribe from worse.*/ +static GcMasterProvider * +gc_master_client_get_best_provider (GcMasterClient *client, + GList **provider_list, + GcInterfaceFlags iface) +{ + GList *l = *provider_list; + /* TODO: should maybe choose a acquiring provider if better ones are are not available */ + + g_debug ("client: choosing best provider"); + + while (l) { + GcMasterProvider *provider = l->data; + + g_debug (" ...trying provider %s", gc_master_provider_get_name (provider)); + if (gc_master_provider_subscribe (provider, client, iface)) { + /* provider was started, so accuracy may have changed + (which re-sorts provider lists), restart provider selection */ + /* TODO re-think this: restarting provider selection leads to potentially + never-ending looping */ + g_debug (" ...started %s (status %d), re-starting provider selection", + gc_master_provider_get_name (provider), + gc_master_provider_get_status (provider)); + l = *provider_list; + continue; + } + /* provider did not need to be started */ + + /* TODO: currently returning even providers that are worse than priv->min_accuracy, + * if nothing else is available */ + if (gc_master_provider_get_status (provider) == GEOCLUE_STATUS_AVAILABLE) { + /* unsubscribe from all providers worse than this */ + gc_master_client_unsubscribe_providers (client, l->next, iface); + return provider; + } + l = l->next; + } + + /* no provider found */ + gc_master_client_unsubscribe_providers (client, *provider_list, iface); + return NULL; +} + +static void +gc_master_client_emit_position_changed (GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GeocluePositionFields fields; + int timestamp; + double latitude, longitude, altitude; + GeoclueAccuracy *accuracy = NULL; + GError *error = NULL; + + + if (priv->position_provider == NULL) { + accuracy = geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_NONE, 0.0, 0.0); + gc_iface_position_emit_position_changed + (GC_IFACE_POSITION (client), + GEOCLUE_POSITION_FIELDS_NONE, + time (NULL), + 0.0, 0.0, 0.0, + accuracy); + geoclue_accuracy_free (accuracy); + return; + } + + fields = gc_master_provider_get_position + (priv->position_provider, + ×tamp, + &latitude, &longitude, &altitude, + &accuracy, + &error); + if (error) { + /*TODO what now?*/ + g_warning ("client: failed to get position from %s: %s", + gc_master_provider_get_name (priv->position_provider), + error->message); + g_error_free (error); + return; + } + gc_iface_position_emit_position_changed + (GC_IFACE_POSITION (client), + fields, + timestamp, + latitude, longitude, altitude, + accuracy); +} + +static void +gc_master_client_emit_address_changed (GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + int timestamp; + GHashTable *details = NULL; + GeoclueAccuracy *accuracy = NULL; + GError *error = NULL; + + if (priv->address_provider == NULL) { + accuracy = geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_NONE, 0.0, 0.0); + details = g_hash_table_new (g_str_hash, g_str_equal); + gc_iface_address_emit_address_changed + (GC_IFACE_ADDRESS (client), + time (NULL), + details, + accuracy); + g_hash_table_destroy (details); + geoclue_accuracy_free (accuracy); + return; + } + if (!gc_master_provider_get_address + (priv->address_provider, + ×tamp, + &details, + &accuracy, + &error)) { + /*TODO what now?*/ + g_warning ("client: failed to get address from %s: %s", + gc_master_provider_get_name (priv->address_provider), + error->message); + g_error_free (error); + return; + } + gc_iface_address_emit_address_changed + (GC_IFACE_ADDRESS (client), + timestamp, + details, + accuracy); +} + +/* return true if a _new_ provider was chosen */ +static gboolean +gc_master_client_choose_position_provider (GcMasterClient *client, + GList *providers) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GcMasterProvider *new_p; + + /* choose and start provider */ + priv->position_provider_choice_in_progress = TRUE; + new_p = gc_master_client_get_best_provider (client, + &priv->position_providers, + GC_IFACE_POSITION); + priv->position_provider_choice_in_progress = FALSE; + + if (priv->position_provider && new_p == priv->position_provider) { + return FALSE; + } + + if (priv->signals[POSITION_CHANGED] > 0) { + g_signal_handler_disconnect (priv->position_provider, + priv->signals[POSITION_CHANGED]); + priv->signals[POSITION_CHANGED] = 0; + } + + priv->position_provider = new_p; + + if (priv->position_provider == NULL) { + g_debug ("client: position provider changed (to NULL)"); + g_signal_emit (client, signals[POSITION_PROVIDER_CHANGED], 0, + NULL, NULL, NULL, NULL); + return TRUE; + } + + g_debug ("client: position provider changed (to %s)", gc_master_provider_get_name (priv->position_provider)); + g_signal_emit (client, signals[POSITION_PROVIDER_CHANGED], 0, + gc_master_provider_get_name (priv->position_provider), + gc_master_provider_get_description (priv->position_provider), + gc_master_provider_get_service (priv->position_provider), + gc_master_provider_get_path (priv->position_provider)); + priv->signals[POSITION_CHANGED] = + g_signal_connect (G_OBJECT (priv->position_provider), + "position-changed", + G_CALLBACK (position_changed), + client); + return TRUE; +} + +/* return true if a _new_ provider was chosen */ +static gboolean +gc_master_client_choose_address_provider (GcMasterClient *client, + GList *providers) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GcMasterProvider *new_p; + + + /* choose and start provider */ + priv->address_provider_choice_in_progress = TRUE; + new_p = gc_master_client_get_best_provider (client, + &priv->address_providers, + GC_IFACE_ADDRESS); + priv->address_provider_choice_in_progress = FALSE; + + if (priv->address_provider != NULL && new_p == priv->address_provider) { + /* keep using the same provider */ + return FALSE; + } + + if (priv->address_provider && priv->signals[ADDRESS_CHANGED] > 0) { + g_signal_handler_disconnect (priv->address_provider, + priv->signals[ADDRESS_CHANGED]); + priv->signals[ADDRESS_CHANGED] = 0; + } + + priv->address_provider = new_p; + + if (priv->address_provider == NULL) { + g_debug ("client: address provider changed (to NULL)"); + g_signal_emit (client, signals[ADDRESS_PROVIDER_CHANGED], 0, + NULL, NULL, NULL, NULL); + return TRUE; + } + + g_debug ("client: address provider changed (to %s)", gc_master_provider_get_name (priv->address_provider)); + g_signal_emit (client, signals[ADDRESS_PROVIDER_CHANGED], 0, + gc_master_provider_get_name (priv->address_provider), + gc_master_provider_get_description (priv->address_provider), + gc_master_provider_get_service (priv->address_provider), + gc_master_provider_get_path (priv->address_provider)); + priv->signals[ADDRESS_CHANGED] = + g_signal_connect (G_OBJECT (priv->address_provider), + "address-changed", + G_CALLBACK (address_changed), + client); + return TRUE; +} + +static void +gc_master_provider_set_position_providers (GcMasterClient *client, + GList *providers) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GcInterfaceAccuracy *accuracy_data; + + accuracy_data = g_new0(GcInterfaceAccuracy, 1); + accuracy_data->interface = GC_IFACE_POSITION; + accuracy_data->accuracy_level = priv->min_accuracy; + + gc_master_client_connect_common_signals (client, providers); + priv->position_providers = + g_list_sort_with_data (providers, + (GCompareDataFunc)gc_master_provider_compare, + accuracy_data); + + g_free (accuracy_data); +} + +static void +gc_master_provider_set_address_providers (GcMasterClient *client, + GList *providers) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GcInterfaceAccuracy *accuracy_data; + + accuracy_data = g_new0(GcInterfaceAccuracy, 1); + accuracy_data->interface = GC_IFACE_ADDRESS; + accuracy_data->accuracy_level = priv->min_accuracy; + + gc_master_client_connect_common_signals (client, providers); + priv->address_providers = + g_list_sort_with_data (providers, + (GCompareDataFunc)gc_master_provider_compare, + accuracy_data); + + g_free (accuracy_data); +} + +static void +gc_master_client_init_position_providers (GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + GList *providers; + + if (!priv->position_started) { + return; + } + + /* TODO: free priv->position_providers */ + + providers = gc_master_get_providers (GC_IFACE_POSITION, + priv->min_accuracy, + priv->require_updates, + priv->allowed_resources, + NULL); + g_debug ("client: %d position providers matching requirements found, now choosing current provider", + g_list_length (providers)); + + gc_master_provider_set_position_providers (client, providers); + gc_master_client_choose_position_provider (client, priv->position_providers); +} +static void +gc_master_client_init_address_providers (GcMasterClient *client) +{ + GList *providers; + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + if (!priv->address_started) { + return; + } + + /* TODO: free priv->address_providers */ + + providers = gc_master_get_providers (GC_IFACE_ADDRESS, + priv->min_accuracy, + priv->require_updates, + priv->allowed_resources, + NULL); + g_debug ("client: %d address providers matching requirements found, now choosing current provider", + g_list_length (providers)); + + gc_master_provider_set_address_providers (client, providers); + gc_master_client_choose_address_provider (client, priv->address_providers); +} + +static gboolean +gc_iface_master_client_set_requirements (GcMasterClient *client, + GeoclueAccuracyLevel min_accuracy, + int min_time, + gboolean require_updates, + GeoclueResourceFlags allowed_resources, + GError **error) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + priv->min_accuracy = min_accuracy; + priv->min_time = min_time; + priv->require_updates = require_updates; + priv->allowed_resources = allowed_resources; + + gc_master_client_init_position_providers (client); + gc_master_client_init_address_providers (client); + + return TRUE; +} + + +static gboolean +gc_iface_master_client_position_start (GcMasterClient *client, + GError **error) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + if (priv->position_providers) { + if (error) { + *error = g_error_new (GEOCLUE_ERROR, + GEOCLUE_ERROR_FAILED, + "Position interface already started"); + } + return FALSE; + } + + priv->position_started = TRUE; + + gc_master_client_init_position_providers (client); + + return TRUE; +} + +static gboolean +gc_iface_master_client_address_start (GcMasterClient *client, + GError **error) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + if (priv->address_providers) { + if (error) { + *error = g_error_new (GEOCLUE_ERROR, + GEOCLUE_ERROR_FAILED, + "Address interface already started"); + } + return FALSE; + } + + priv->address_started = TRUE; + gc_master_client_init_address_providers (client); + return TRUE; +} + +static void +get_master_provider_details (GcMasterProvider *provider, + char **name, + char **description, + char **service, + char **path) +{ + if (name) { + if (!provider) { + *name = NULL; + } else { + *name = g_strdup (gc_master_provider_get_name (provider)); + } + } + if (description) { + if (!provider) { + *description = NULL; + } else { + *description = g_strdup (gc_master_provider_get_description (provider)); + } + } + if (service) { + if (!provider) { + *service = NULL; + } else { + *service = g_strdup (gc_master_provider_get_service (provider)); + } + } + if (path) { + if (!provider) { + *path = NULL; + } else { + *path = g_strdup (gc_master_provider_get_path (provider)); + } + } +} + + +static gboolean +gc_iface_master_client_get_address_provider (GcMasterClient *client, + char **name, + char **description, + char **service, + char **path, + GError **error) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + get_master_provider_details (priv->address_provider, + name, description, service, path); + return TRUE; +} + +static gboolean +gc_iface_master_client_get_position_provider (GcMasterClient *client, + char **name, + char **description, + char **service, + char **path, + GError **error) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + get_master_provider_details (priv->position_provider, + name, description, service, path); + return TRUE; +} + +static void +finalize (GObject *object) +{ + GcMasterClient *client = GC_MASTER_CLIENT (object); + GcMasterClientPrivate *priv = GET_PRIVATE (object); + + /* do not free contents of the lists, Master takes care of them */ + if (priv->position_providers) { + gc_master_client_unsubscribe_providers (client, priv->position_providers, GC_IFACE_ALL); + g_list_free (priv->position_providers); + priv->position_providers = NULL; + } + if (priv->address_providers) { + gc_master_client_unsubscribe_providers (client, priv->address_providers, GC_IFACE_ALL); + g_list_free (priv->address_providers); + priv->address_providers = NULL; + } + + ((GObjectClass *) gc_master_client_parent_class)->finalize (object); +} + +static void +gc_master_client_class_init (GcMasterClientClass *klass) +{ + GObjectClass *o_class = (GObjectClass *) klass; + + o_class->finalize = finalize; + + g_type_class_add_private (klass, sizeof (GcMasterClientPrivate)); + + signals[ADDRESS_PROVIDER_CHANGED] = + g_signal_new ("address-provider-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, + geoclue_marshal_VOID__STRING_STRING_STRING_STRING, + G_TYPE_NONE, 4, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + signals[POSITION_PROVIDER_CHANGED] = + g_signal_new ("position-provider-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, 0, + NULL, NULL, + geoclue_marshal_VOID__STRING_STRING_STRING_STRING, + G_TYPE_NONE, 4, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + dbus_g_object_type_install_info (gc_master_client_get_type (), + &dbus_glib_gc_iface_master_client_object_info); + + +} + +static void +gc_master_client_init (GcMasterClient *client) +{ + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + priv->position_provider_choice_in_progress = FALSE; + priv->address_provider_choice_in_progress = FALSE; + + priv->position_started = FALSE; + priv->position_provider = NULL; + priv->position_providers = NULL; + + priv->address_started = FALSE; + priv->address_provider = NULL; + priv->address_providers = NULL; +} + +static gboolean +get_position (GcIfacePosition *iface, + GeocluePositionFields *fields, + int *timestamp, + double *latitude, + double *longitude, + double *altitude, + GeoclueAccuracy **accuracy, + GError **error) +{ + GcMasterClient *client = GC_MASTER_CLIENT (iface); + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + if (priv->position_provider == NULL) { + if (error) { + *error = g_error_new (GEOCLUE_ERROR, + GEOCLUE_ERROR_NOT_AVAILABLE, + "Geoclue master client has no usable Position providers"); + } + return FALSE; + } + + *fields = gc_master_provider_get_position + (priv->position_provider, + timestamp, + latitude, longitude, altitude, + accuracy, + error); + return (!*error); +} + +static gboolean +get_address (GcIfaceAddress *iface, + int *timestamp, + GHashTable **address, + GeoclueAccuracy **accuracy, + GError **error) +{ + GcMasterClient *client = GC_MASTER_CLIENT (iface); + GcMasterClientPrivate *priv = GET_PRIVATE (client); + + if (priv->address_provider == NULL) { + if (error) { + *error = g_error_new (GEOCLUE_ERROR, + GEOCLUE_ERROR_NOT_AVAILABLE, + "Geoclue master client has no usable Address providers"); + } + return FALSE; + } + + return gc_master_provider_get_address + (priv->address_provider, + timestamp, + address, + accuracy, + error); +} + +static gboolean +get_status (GcIfaceGeoclue *geoclue, + GeoclueStatus *status, + GError **error) +{ + /* not really meaningful */ + *status = GEOCLUE_STATUS_AVAILABLE; + return TRUE; +} + +static gboolean +set_options (GcIfaceGeoclue *geoclue, + GHashTable *options, + GError **error) +{ + /* not meaningful, options come from master */ + + /* It is not an error to not have a SetOptions implementation */ + return TRUE; +} + +static gboolean +get_provider_info (GcIfaceGeoclue *geoclue, + gchar **name, + gchar **description, + GError **error) +{ + if (name) { + *name = g_strdup ("Geoclue Master"); + } + if (description) { + *description = g_strdup ("Meta-provider that internally uses what ever provider is the best "); + } + return TRUE; +} + +static void +add_reference (GcIfaceGeoclue *geoclue, + DBusGMethodInvocation *context) +{ + /* TODO implement if needed */ + dbus_g_method_return (context); +} + +static void +remove_reference (GcIfaceGeoclue *geoclue, + DBusGMethodInvocation *context) +{ + /* TODO implement if needed */ + dbus_g_method_return (context); +} + +static void +gc_master_client_geoclue_init (GcIfaceGeoclueClass *iface) +{ + iface->get_provider_info = get_provider_info; + iface->get_status = get_status; + iface->set_options = set_options; + iface->add_reference = add_reference; + iface->remove_reference = remove_reference; +} + +static void +gc_master_client_position_init (GcIfacePositionClass *iface) +{ + iface->get_position = get_position; +} + +static void +gc_master_client_address_init (GcIfaceAddressClass *iface) +{ + iface->get_address = get_address; +} diff --git a/.pc/tizen.patch/src/connectivity-connman.c b/.pc/tizen.patch/src/connectivity-connman.c new file mode 100755 index 0000000..42ccce0 --- /dev/null +++ b/.pc/tizen.patch/src/connectivity-connman.c @@ -0,0 +1,739 @@ +/* + * Geoclue + * connectivity-connman.c + * + * Author: Javier Fernandez <jfernandez@igalia.com> + * Copyright (C) 2010 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#include <config.h> + +#ifdef HAVE_CONNMAN + +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-lowlevel.h> +#include "connectivity-connman.h" + +#define CONNMAN_SERVICE "org.moblin.connman" +#define CONNMAN_MANAGER_PATH "/" +#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" +#define CONNMAN_TECHNOLOGY_INTERFACE CONNMAN_SERVICE ".Technology" +#define CONNMAN_DEVICE_INTERFACE CONNMAN_SERVICE ".Device" +#define CONNMAN_NETWORK_INTERFACE CONNMAN_SERVICE ".Network" +#define CONNMAN_SERVICE_INTERFACE CONNMAN_SERVICE ".Service" + +typedef void (*ConnmanFunc) (GeoclueConnman *self, + const gchar *path, + gpointer out); + +static void geoclue_connman_connectivity_init (GeoclueConnectivityInterface *iface); + +static int _strength_to_dbm (int strength); +static char *_get_mac_for_gateway (const char *gateway); +static char *_mac_strup (char *mac); +static gchar *_get_gateway (GeoclueConnman *self, const gchar *service); +static void _get_best_ap (GeoclueConnman *self, const gchar *network); +static void _get_aps_info (GeoclueConnman *self, const gchar *network, GHashTable **out); +static const GPtrArray *_get_technologies (GeoclueConnman *self, GHashTable **props); +static const GPtrArray *_get_services (GeoclueConnman *self, GHashTable **props); +static const GPtrArray *_get_devices (GeoclueConnman *self, GHashTable **props, const gchar *technology); +static const GPtrArray *_get_networks (GeoclueConnman *self, GHashTable **props, const gchar *device, const gchar *type_filter); +static void _explore_available_aps (GeoclueConnman *self, ConnmanFunc func, gpointer out); + + +G_DEFINE_TYPE_WITH_CODE (GeoclueConnman, geoclue_connman, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GEOCLUE_TYPE_CONNECTIVITY, + geoclue_connman_connectivity_init)) + + +/* GeoclueConnectivity iface methods */ +static int +_get_status (GeoclueConnectivity *iface) +{ + GeoclueConnman *connman = GEOCLUE_CONNMAN (iface); + + return connman->status; +} + +static char * +_get_ap_mac (GeoclueConnectivity *iface) +{ + GeoclueConnman *connman = GEOCLUE_CONNMAN (iface); + + return g_strdup (connman->cache_ap_mac); +} + +static GHashTable * +_get_aps (GeoclueConnectivity *iface) +{ + GeoclueConnman *self = GEOCLUE_CONNMAN (iface); + GHashTable *ht = NULL; + + /* Explore the active networks to collect the APs. */ + _explore_available_aps (self, (ConnmanFunc) _get_aps_info, &ht); + + return ht; +} + +static char * +_get_router_mac (GeoclueConnectivity *iface) +{ + GeoclueConnman *self = GEOCLUE_CONNMAN (iface); + GHashTable *props = NULL; + const GPtrArray *servs = NULL; + const gchar *serv = NULL; + gchar *gateway = NULL; + char *mac = NULL; + guint i; + + /* Get available services and iterate over them */ + /* to get the MAC of the connected router. */ + servs = _get_services (self, &props); + if (servs != NULL) { + for (i = 0; gateway == NULL && servs->len; i++) { + serv = g_ptr_array_index (servs, i); + gateway = _get_gateway (self, serv); + } + } + + /* Check the result. */ + if (gateway != NULL) { + mac = _get_mac_for_gateway (gateway); + g_free (gateway); + } + + /* Free */ + g_hash_table_destroy (props); + + return mac; +} + +/* internal private GObject methods */ +static void +dispose (GObject *object) +{ + GeoclueConnman *self = GEOCLUE_CONNMAN (object); + + g_object_unref (self->client); + self->client = NULL; + + dbus_g_connection_unref (self->conn); + self->conn = NULL; + + g_free (self->cache_ap_mac); + self->cache_ap_mac = NULL; + + ((GObjectClass *) geoclue_connman_parent_class)->dispose (object); +} + +static void +geoclue_connman_class_init (GeoclueConnmanClass *klass) +{ + GObjectClass *o_class = (GObjectClass *) klass; + + o_class->dispose = dispose; +} + +static int +_strength_to_dbm (int strength) +{ + /* Hackish linear strength to dBm conversion. + * 0% is -90 dBm + * 100% is -20 dBm */ + return (strength * 0.7) - 90; +} + +static char * +_get_mac_for_gateway (const char *gateway) +{ + char *cmd, *out, *mac, **split; + + cmd = g_strdup_printf ("ip neigh show %s", gateway); + + if (g_spawn_command_line_sync (cmd, &out, NULL, NULL, NULL) == FALSE) { + g_free (out); + g_free (cmd); + return NULL; + } + g_free (cmd); + + /* 192.168.1.1 dev eth0 lladdr 00:00:00:00:00:00 STALE */ + split = g_strsplit (out, " ", -1); + g_free (out); + + if (split == NULL) + return NULL; + if (g_strv_length (split) != 6) { + g_strfreev (split); + return NULL; + } + mac = g_strdup (split[4]); + g_strfreev (split); + + return _mac_strup (mac); +} + +static char * +_mac_strup (char *mac) +{ + guint i; + + g_assert (mac != NULL); + + for (i = 0; mac[i] != '\0' ; i++) { + if (g_ascii_isalpha (mac[i])) + mac[i] = g_ascii_toupper (mac[i]); + } + return mac; +} + +static GeoclueNetworkStatus +connmanstatus_to_geocluenetworkstatus (const gchar *status) +{ + if (g_strcmp0 (status, "online")) { + return GEOCLUE_CONNECTIVITY_OFFLINE; + } else { + return GEOCLUE_CONNECTIVITY_ONLINE; + } +} + +static gchar * +_get_gateway (GeoclueConnman *self, + const gchar *service) +{ + DBusGProxy *proxy = NULL; + GHashTable *props = NULL; + gchar *gateway = NULL; + const GHashTable *ht = NULL; + const GValue *value = NULL; + const gchar *msg = NULL; + GError *error = NULL; + + /* Create proxy. */ + proxy = dbus_g_proxy_new_for_name (self->conn, + CONNMAN_SERVICE, + service, + CONNMAN_SERVICE_INTERFACE); + if (proxy == NULL) { + g_warning ("%s was unable to create connection to Service iface.", + G_OBJECT_TYPE_NAME (self)); + return NULL; + } + + /* Get Service properties to get the gateway address. */ + if (dbus_g_proxy_call (proxy, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + &props, + G_TYPE_INVALID)) { + + /* Get the mac of the connected router. */ + value = g_hash_table_lookup (props, "IPv4"); + if (value != NULL) { + ht = g_value_get_boxed (value); + value = g_hash_table_lookup ((GHashTable *) ht, "Gateway"); + if (value != NULL) { + gateway = g_value_dup_string (value); + } + } + } else { + msg = "Error getting Service properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + /* Free */ + g_hash_table_destroy (props); + g_object_unref (proxy); + + return gateway; +} + +static void +_get_aps_info (GeoclueConnman *self, + const gchar *network, + GHashTable **out) +{ + DBusGProxy *proxy = NULL; + GHashTable *props = NULL; + gchar *ap_mac = NULL; + const gchar *msg = NULL; + GError *error = NULL; + int strength; + + g_assert (out != NULL); + + /* Create proxy. */ + proxy = dbus_g_proxy_new_for_name (self->conn, + CONNMAN_SERVICE, + network, + CONNMAN_NETWORK_INTERFACE); + if (proxy == NULL) { + g_warning ("%s was unable to create connection to Network iface.", + G_OBJECT_TYPE_NAME (self)); + return; + } + + /* Collect available APs into a HasTable. */ + if (dbus_g_proxy_call (proxy, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + &props, + G_TYPE_INVALID)) { + + /* Store the AP information. */ + ap_mac = g_value_dup_string (g_hash_table_lookup (props, "Address")); + strength = g_value_get_uchar (g_hash_table_lookup (props, "Strength")); + if (ap_mac != NULL) { + /* Create storage for the first case. */ + if (*out == NULL) { + *out = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, NULL); + } + g_hash_table_insert (*out, ap_mac, + GINT_TO_POINTER (_strength_to_dbm (strength))); + } + } else { + msg = "Error getting Network properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + /* Free */ + g_hash_table_destroy (props); + g_object_unref (proxy); +} + +static void +_get_best_ap (GeoclueConnman *self, + const gchar *network) +{ + DBusGProxy *proxy = NULL; + GHashTable *props = NULL; + const gchar *msg = NULL; + GError *error = NULL; + int strength; + + /* Create proxy. */ + proxy = dbus_g_proxy_new_for_name (self->conn, + CONNMAN_SERVICE, + network, + CONNMAN_NETWORK_INTERFACE); + + if (proxy == NULL) { + g_warning ("%s was unable to create connection to Network iface.", + G_OBJECT_TYPE_NAME (self)); + return; + } + + /* Evaluate Network properties and update best AP. */ + if (dbus_g_proxy_call (proxy, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + &props, + G_TYPE_INVALID)) { + + strength = g_value_get_uchar (g_hash_table_lookup (props, "Strength")); + if (strength > self->ap_strength) { + g_free (self->cache_ap_mac); + self->cache_ap_mac = g_value_dup_string (g_hash_table_lookup (props, "Address")); + self->ap_strength = strength; + } + } else { + msg = "Error getting Network properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + /* Free */ + g_hash_table_destroy (props); + g_object_unref (proxy); +} + +static const GPtrArray * +_get_networks (GeoclueConnman *self, + GHashTable **props, + const gchar *device, + const gchar *type_filter) +{ + DBusGProxy *proxy = NULL; + const GPtrArray *nets = NULL; + const GValue *value = NULL; + const gchar *type = NULL; + const gchar *msg = NULL; + GError *error = NULL; + + /* Create proxy. */ + proxy = dbus_g_proxy_new_for_name (self->conn, + CONNMAN_SERVICE, + device, + CONNMAN_DEVICE_INTERFACE); + + if (proxy == NULL) { + g_warning ("%s was unable to create connection to Device iface.", + G_OBJECT_TYPE_NAME (self)); + return NULL; + } + + /* Get available Networks for a specific Device. */ + if (dbus_g_proxy_call (proxy, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + props, + G_TYPE_INVALID)) { + + /* Check only specific networks. */ + if (type_filter != NULL) { + type = g_value_get_string (g_hash_table_lookup (*props, "Type")); + if (g_strcmp0 (type, type_filter)) { + goto frees; + } + } + value = g_hash_table_lookup (*props, "Networks"); + nets = g_value_get_boxed (value); + } else { + msg = "Error getting Device properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + /* Free */ + frees: + g_object_unref (proxy); + + return nets; +} + +static const GPtrArray * +_get_devices (GeoclueConnman *self, + GHashTable **props, + const gchar *technology) +{ + DBusGProxy *proxy = NULL; + const GPtrArray *devs = NULL; + const GValue *value = NULL; + const gchar *msg = NULL; + GError *error = NULL; + + /* Create proxy. */ + proxy = dbus_g_proxy_new_for_name (self->conn, + CONNMAN_SERVICE, + technology, + CONNMAN_TECHNOLOGY_INTERFACE); + + if (proxy == NULL) { + g_warning ("%s was unable to create connection to Technology iface.", + G_OBJECT_TYPE_NAME (self)); + return NULL; + } + + /* Get available Devices for a specific Technology. */ + if (dbus_g_proxy_call (proxy, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + props, + G_TYPE_INVALID)) { + + value = g_hash_table_lookup (*props, "Devices"); + devs = g_value_get_boxed (value); + } else { + msg = "Error getting Technologies properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + /* Free */ + g_object_unref (proxy); + + return devs; +} + +static const GPtrArray * +_get_technologies (GeoclueConnman *self, + GHashTable **props) +{ + const GPtrArray *techs = NULL; + const GValue *value = NULL; + const gchar *msg = NULL; + GError *error = NULL; + + /* Get available technologies (Wifi, Eth, ...). */ + if (dbus_g_proxy_call (self->client, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + props, + G_TYPE_INVALID)) { + + value = g_hash_table_lookup (*props, "Technologies"); + techs = g_value_get_boxed (value); + } else { + msg = "Error getting Manager properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + return techs; +} + +static const GPtrArray * +_get_services (GeoclueConnman *self, + GHashTable **props) +{ + const GPtrArray *servs = NULL; + const GValue *value = NULL; + const gchar *msg = NULL; + GError *error = NULL; + + /* Get available services. */ + if (dbus_g_proxy_call (self->client, "GetProperties", + &error, + G_TYPE_INVALID, + dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), + props, + G_TYPE_INVALID)) { + + value = g_hash_table_lookup (*props, "Services"); + servs = g_value_get_boxed (value); + } else { + msg = "Error getting Manager properties: %s"; + if (error != NULL) { + g_warning (msg, error->message); + g_error_free (error); + } else { + g_warning (msg, "Unknown error"); + } + } + + return servs; +} + +static void +_explore_available_aps (GeoclueConnman *self, + ConnmanFunc func, + gpointer out) +{ + GHashTable *mgr_props = NULL; + GHashTable *tech_props = NULL; + GHashTable *dev_props = NULL; + const GPtrArray *techs = NULL; + const GPtrArray *devs = NULL; + const GPtrArray *nets = NULL; + const gchar *tech = NULL; + const gchar *dev = NULL; + const gchar *net = NULL; + guint i, j, k; + + techs = _get_technologies (self, &mgr_props); + if (techs == NULL) { + goto frees; + } + for (i = 0; i < techs->len; i++) { + tech = g_ptr_array_index (techs, i); + devs = _get_devices (self, &tech_props, tech); + if (devs == NULL) { + continue; + } + for (j = 0; j < devs->len; j++) { + dev = g_ptr_array_index (devs, j); + nets = _get_networks (self, &dev_props, dev, "wifi"); + if (nets == NULL) { + continue; + } + for (k = 0; k < nets->len; k++) { + net = g_ptr_array_index (nets, k); + + /* Perform specific actions. */ + func (self, net, out); + } + } + } + + /* Free */ + frees: + if (mgr_props != NULL) { + g_hash_table_destroy (mgr_props); + } + if (tech_props != NULL) { + g_hash_table_destroy (tech_props); + } + if (dev_props != NULL) { + g_hash_table_destroy (dev_props); + } +} + +static void +_cache_ap_mac (GeoclueConnman *self) +{ + /* Cleanup the cache. */ + g_free (self->cache_ap_mac); + self->cache_ap_mac = NULL; + self->ap_strength = 0; + + /* Explore the active networks to get the best AP. */ + _explore_available_aps (self, (ConnmanFunc) _get_best_ap, NULL); +} + + + +static void +_geoclue_connman_state_changed (DBusGProxy *proxy, + const gchar *status, + gpointer userdata) +{ + GeoclueConnman *self = GEOCLUE_CONNMAN (userdata); + GeoclueNetworkStatus gc_status; + + gc_status = connmanstatus_to_geocluenetworkstatus (status); + + if (gc_status != self->status) { + /* Update status. */ + self->status = gc_status; + + /* Update AP cache. */ + _cache_ap_mac (self); + + /* Notification. */ + geoclue_connectivity_emit_status_changed (GEOCLUE_CONNECTIVITY (self), + self->status); + } +} + + +static void +_method_call_notify_cb (DBusGProxy *proxy, + DBusGProxyCall *call, + gpointer user_data) +{ + GeoclueConnman *self = GEOCLUE_CONNMAN (user_data); + const gchar *msg = NULL; + GError *error = NULL; + gchar *state = NULL; + + /* Collect output data. */ + if (dbus_g_proxy_end_call (proxy, + call, + &error, + G_TYPE_STRING, + &state, + G_TYPE_INVALID)) { + + /* Set current status. */ + _geoclue_connman_state_changed (proxy, + (const gchar *) state, + self); + } else { + msg = "%s was unable to get the current network status: %s."; + if (error != NULL) { + g_warning (msg, G_OBJECT_TYPE_NAME (self), + error->message); + g_error_free (error); + } else { + g_warning (msg, G_OBJECT_TYPE_NAME (self), + "Unknown error"); + } + } + + /* Free */ + g_free (state); +} + +static void +geoclue_connman_init (GeoclueConnman *self) +{ + GError *error = NULL; + + /* Get DBus connection to the System bus. */ + self->conn = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (self->conn == NULL) { + g_warning ("%s was unable to create a connection to D-Bus: %s", + G_OBJECT_TYPE_NAME (self), error->message); + g_error_free (error); + return; + } + + /* Create proxy. */ + self->client = dbus_g_proxy_new_for_name (self->conn, + CONNMAN_SERVICE, + CONNMAN_MANAGER_PATH, + CONNMAN_MANAGER_INTERFACE); + + if (self->client == NULL) { + g_warning ("%s was unable to create connection to Connman Manager.", + G_OBJECT_TYPE_NAME (self)); + return; + } + + /* Get current state (async). */ + dbus_g_proxy_begin_call (self->client, "GetState", + _method_call_notify_cb, + self, + NULL, + G_TYPE_INVALID, + G_TYPE_STRING); + + /* Be aware of State changes. */ + dbus_g_proxy_add_signal (self->client, "StateChanged", + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal (self->client, + "StateChanged", + G_CALLBACK (_geoclue_connman_state_changed), + self, + NULL); +} + + +static void +geoclue_connman_connectivity_init (GeoclueConnectivityInterface *iface) +{ + iface->get_status = _get_status; + iface->get_ap_mac = _get_ap_mac; + iface->get_router_mac = _get_router_mac; + iface->get_aps = _get_aps; +} + +#endif /* HAVE_CONNMAN*/ diff --git a/.pc/tizen.patch/src/connectivity-connman.h b/.pc/tizen.patch/src/connectivity-connman.h new file mode 100755 index 0000000..24c5907 --- /dev/null +++ b/.pc/tizen.patch/src/connectivity-connman.h @@ -0,0 +1,56 @@ +/* + * Geoclue + * connectivity-connman.h + * + * Author: Javier Fernandez <jfernandez@igalia.com> + * Copyright (C) 2010 Igalia S.L + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef _CONNECTIVITY_CONNMAN_H +#define _CONNECTIVITY_CONNMAN_H + +#include <glib-object.h> +#include <dbus/dbus-glib.h> +#include "connectivity.h" + +G_BEGIN_DECLS + +#define GEOCLUE_TYPE_CONNMAN (geoclue_connman_get_type ()) +#define GEOCLUE_CONNMAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEOCLUE_TYPE_CONNMAN, GeoclueConnman)) + +typedef struct { + GObject parent; + + /* private */ + GeoclueNetworkStatus status; + DBusGConnection *conn; + DBusGProxy *client; + gchar *cache_ap_mac; + int ap_strength; +} GeoclueConnman; + +typedef struct { + GObjectClass parent_class; +} GeoclueConnmanClass; + +GType geoclue_connman_get_type (void); + +G_END_DECLS + +#endif diff --git a/.pc/tizen.patch/src/connectivity-networkmanager.c b/.pc/tizen.patch/src/connectivity-networkmanager.c new file mode 100755 index 0000000..09630a0 --- /dev/null +++ b/.pc/tizen.patch/src/connectivity-networkmanager.c @@ -0,0 +1,369 @@ +/* + * Geoclue + * geoclue-networkmanager.c + * + * Authors: Jussi Kukkonen <jku@o-hand.com> + * Copyright 2007 by Garmin Ltd. or its subsidiaries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#include <config.h> + +#ifdef HAVE_NETWORK_MANAGER + + +#include <dbus/dbus-glib.h> +#include <string.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <NetworkManager.h> /*for DBus strings */ + +#include <nm-client.h> +#include <nm-device-wifi.h> +#include <nm-setting-ip4-config.h> + +#if !defined(NM_CHECK_VERSION) +#define NM_CHECK_VERSION(x,y,z) 0 +#endif + +#include "connectivity-networkmanager.h" + +static void geoclue_networkmanager_connectivity_init (GeoclueConnectivityInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GeoclueNetworkManager, geoclue_networkmanager, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GEOCLUE_TYPE_CONNECTIVITY, + geoclue_networkmanager_connectivity_init)) + + +/* GeoclueConnectivity iface method */ +static int +get_status (GeoclueConnectivity *iface) +{ + GeoclueNetworkManager *nm = GEOCLUE_NETWORKMANAGER (iface); + + return nm->status; +} + +static char * +get_ap_mac (GeoclueConnectivity *iface) +{ + GeoclueNetworkManager *self = GEOCLUE_NETWORKMANAGER (iface); + + return g_strdup (self->cache_ap_mac); +} + +static int +strength_to_dbm (int strength) +{ + /* Hackish linear strength to dBm conversion. + * 0% is -90 dBm + * 100% is -20 dBm */ + return (strength * 0.7) - 90; +} + +static GHashTable * +get_aps (GeoclueConnectivity *iface) +{ + GeoclueNetworkManager *self = GEOCLUE_NETWORKMANAGER (iface); + const GPtrArray *devices; + GHashTable *ht; + guint i; + + devices = nm_client_get_devices (self->client); + if (devices == NULL) + return NULL; + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, NULL); + + for (i = 0; i < devices->len; i++) { + NMDevice *device = g_ptr_array_index (devices, i); + if (NM_IS_DEVICE_WIFI (device)) { + const GPtrArray *aps; + guint j; + + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); + if (aps == NULL || aps->len == 0) + continue; + for (j = 0; j < aps->len; j++) { + NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, j)); + char *ap_mac; + int strength; + + ap_mac = g_strdup (nm_access_point_get_hw_address (ap)); + strength = nm_access_point_get_strength (ap); + g_hash_table_insert (ht, ap_mac, GINT_TO_POINTER (strength_to_dbm (strength))); + } + } + } + if (g_hash_table_size (ht) == 0) { + g_hash_table_destroy (ht); + return NULL; + } + + return ht; +} + +static char * +mac_strup (char *mac) +{ + guint i; + for (i = 0; mac[i] != '\0' ; i++) { + if (g_ascii_isalpha (mac[i])) + mac[i] = g_ascii_toupper (mac[i]); + } + return mac; +} + +static char * +get_mac_for_gateway (const char *gateway) +{ + char *cmd, *out, *mac, **split; + + cmd = g_strdup_printf ("ip neigh show %s", gateway); + + if (g_spawn_command_line_sync (cmd, &out, NULL, NULL, NULL) == FALSE) { + g_free (out); + g_free (cmd); + return NULL; + } + g_free (cmd); + + /* 192.168.1.1 dev eth0 lladdr 00:00:00:00:00:00 STALE */ + split = g_strsplit (out, " ", -1); + g_free (out); + + if (split == NULL) + return NULL; + if (g_strv_length (split) != 6) { + g_strfreev (split); + return NULL; + } + mac = g_strdup (split[4]); + g_strfreev (split); + + return mac_strup (mac); +} + +static gchar * +ip4_address_as_string (guint32 ip) +{ + struct in_addr tmp_addr; + char buf[INET_ADDRSTRLEN+1]; + + memset (&buf, '\0', sizeof (buf)); + tmp_addr.s_addr = ip; + + if (inet_ntop (AF_INET, &tmp_addr, buf, INET_ADDRSTRLEN)) + return g_strdup (buf); + + return NULL; +} + +static char * +get_router_mac (GeoclueConnectivity *iface) +{ + GeoclueNetworkManager *self = GEOCLUE_NETWORKMANAGER (iface); + const GPtrArray *devices; + char *gateway, *mac; + guint i; + + devices = nm_client_get_devices (self->client); + if (devices == NULL) + return NULL; + + gateway = NULL; + + for (i = 0; i < devices->len; i++) { + NMDevice *device = g_ptr_array_index (devices, i); + NMIP4Config *cfg4; + GSList *iter; + + if (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED) + continue; + + cfg4 = nm_device_get_ip4_config (device); + if (cfg4 == NULL) + continue; + + for (iter = (GSList *) nm_ip4_config_get_addresses (cfg4); iter; iter = g_slist_next (iter)) { + NMIP4Address *addr = (NMIP4Address *) iter->data; + + gateway = ip4_address_as_string (nm_ip4_address_get_gateway (addr)); + if (gateway != NULL) + break; + } + } + if (gateway == NULL) + return NULL; + + mac = get_mac_for_gateway (gateway); + g_free (gateway); + + return mac; +} + +static void +get_best_ap (GeoclueNetworkManager *self, NMDevice *device) +{ + const GPtrArray *aps; + guint i; + + aps = nm_device_wifi_get_access_points (NM_DEVICE_WIFI (device)); + if (aps == NULL || aps->len == 0) + return; + for (i = 0; i < aps->len; i++) { + NMAccessPoint *ap = NM_ACCESS_POINT (g_ptr_array_index (aps, i)); + int strength; + + strength = nm_access_point_get_strength (ap); + if (strength > self->ap_strength) { + g_free (self->cache_ap_mac); + self->cache_ap_mac = g_strdup (nm_access_point_get_hw_address (ap)); + self->ap_strength = strength; + } + } +} + +static void +cache_ap_mac (GeoclueNetworkManager *self) +{ + const GPtrArray *devices; + guint i; + + devices = nm_client_get_devices (self->client); + + g_free (self->cache_ap_mac); + self->cache_ap_mac = NULL; + self->ap_strength = 0; + + for (i = 0; devices != NULL && i < devices->len; i++) { + NMDevice *device = g_ptr_array_index (devices, i); + if (NM_IS_DEVICE_WIFI (device)) { + get_best_ap (self, device); + } + } +} + +static void +dispose (GObject *object) +{ + GeoclueNetworkManager *self = GEOCLUE_NETWORKMANAGER (object); + + g_free (self->cache_ap_mac); + self->cache_ap_mac = NULL; + g_object_unref (self->client); + self->client = NULL; + ((GObjectClass *) geoclue_networkmanager_parent_class)->dispose (object); +} + +static void +geoclue_networkmanager_class_init (GeoclueNetworkManagerClass *klass) +{ + GObjectClass *o_class = (GObjectClass *) klass; + + o_class->dispose = dispose; +} + +static GeoclueNetworkStatus +nmstate_to_geocluenetworkstatus (NMState status) +{ + switch (status) { + case NM_STATE_UNKNOWN: + return GEOCLUE_CONNECTIVITY_UNKNOWN; + case NM_STATE_ASLEEP: + case NM_STATE_DISCONNECTED: +#if NM_CHECK_VERSION(0,8,992) + case NM_STATE_DISCONNECTING: +#endif + return GEOCLUE_CONNECTIVITY_OFFLINE; + case NM_STATE_CONNECTING: + return GEOCLUE_CONNECTIVITY_ACQUIRING; +#if NM_CHECK_VERSION(0,8,992) + case NM_STATE_CONNECTED_LOCAL: + case NM_STATE_CONNECTED_SITE: + case NM_STATE_CONNECTED_GLOBAL: +#else + case NM_STATE_CONNECTED: +#endif + return GEOCLUE_CONNECTIVITY_ONLINE; + default: + g_warning ("Unknown NMStatus: %d", status); + return GEOCLUE_CONNECTIVITY_UNKNOWN; + } +} + +static void +update_status (GeoclueNetworkManager *self, gboolean do_signal) +{ + GeoclueNetworkStatus old_status; + NMState state; + + old_status = self->status; + + if (nm_client_get_manager_running (self->client)) { + state = nm_client_get_state (self->client); + self->status = nmstate_to_geocluenetworkstatus (state); + cache_ap_mac (self); + } else { + self->status = GEOCLUE_CONNECTIVITY_OFFLINE; + } + + if ((self->status != old_status) && do_signal) { + geoclue_connectivity_emit_status_changed (GEOCLUE_CONNECTIVITY (self), + self->status); + } +} + +static void +nm_update_status_cb (GObject *obj, GParamSpec *spec, gpointer userdata) +{ + update_status (GEOCLUE_NETWORKMANAGER (userdata), TRUE); +} + +static void +geoclue_networkmanager_init (GeoclueNetworkManager *self) +{ + self->status = GEOCLUE_CONNECTIVITY_UNKNOWN; + self->client = nm_client_new (); + if (self->client == NULL) { + g_warning ("%s was unable to create a connection to NetworkManager", + G_OBJECT_TYPE_NAME (self)); + return; + } + + g_signal_connect (G_OBJECT (self->client), "notify::running", + G_CALLBACK (nm_update_status_cb), self); + g_signal_connect (G_OBJECT (self->client), "notify::state", + G_CALLBACK (nm_update_status_cb), self); + + /* get initial status */ + update_status (self, FALSE); +} + +static void +geoclue_networkmanager_connectivity_init (GeoclueConnectivityInterface *iface) +{ + iface->get_status = get_status; + iface->get_ap_mac = get_ap_mac; + iface->get_router_mac = get_router_mac; + iface->get_aps = get_aps; +} + +#endif /* HAVE_NETWORK_MANAGER */ diff --git a/.pc/tizen.patch/src/connectivity-networkmanager.h b/.pc/tizen.patch/src/connectivity-networkmanager.h new file mode 100755 index 0000000..d2e5cae --- /dev/null +++ b/.pc/tizen.patch/src/connectivity-networkmanager.h @@ -0,0 +1,56 @@ +/* + * Geoclue + * connectivity-networkmanager.h + * + * Author: Jussi Kukkonen <jku@o-hand.com> + * Copyright 2007 by Garmin Ltd. or its subsidiaries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef _CONNECTIVITY_NETWORKMANAGER_H +#define _CONNECTIVITY_NETWORKMANAGER_H + +#include <glib-object.h> +#include <nm-client.h> +#include "connectivity.h" + + +G_BEGIN_DECLS + +#define GEOCLUE_TYPE_NETWORKMANAGER (geoclue_networkmanager_get_type ()) +#define GEOCLUE_NETWORKMANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEOCLUE_TYPE_NETWORKMANAGER, GeoclueNetworkManager)) + +typedef struct { + GObject parent; + + /* private */ + GeoclueNetworkStatus status; + NMClient *client; + char *cache_ap_mac; + int ap_strength; +} GeoclueNetworkManager; + +typedef struct { + GObjectClass parent_class; +} GeoclueNetworkManagerClass; + +GType geoclue_networkmanager_get_type (void); + +G_END_DECLS + +#endif diff --git a/.pc/tizen.patch/src/connectivity.c b/.pc/tizen.patch/src/connectivity.c new file mode 100755 index 0000000..96d83ab --- /dev/null +++ b/.pc/tizen.patch/src/connectivity.c @@ -0,0 +1,276 @@ +/* + * Geoclue + * geoclue-connectivity.c + * + * Author: Jussi Kukkonen <jku@o-hand.com> + * Copyright 2007 by Garmin Ltd. or its subsidiaries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#include <config.h> + +#include <glib.h> +#include <string.h> +#include <stdio.h> + +#include "connectivity.h" + +#ifdef HAVE_NETWORK_MANAGER +#include "connectivity-networkmanager.h" +#else +#ifdef HAVE_CONIC +#include "connectivity-conic.h" +#else +#ifdef HAVE_CONNMAN +#include "connectivity-connman.h" +#endif +#endif +#endif + +#define DEFAULT_DBM -50 + +enum { + STATUS_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +static void +geoclue_connectivity_base_init (gpointer klass) +{ + static gboolean initialized = FALSE; + + if (initialized) { + return; + } + + initialized = TRUE; + signals[STATUS_CHANGED] = g_signal_new ("status-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GeoclueConnectivityInterface, + status_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); +} + +GType +geoclue_connectivity_get_type (void) +{ + static GType type = 0; + + if (!type) { + const GTypeInfo info = { + sizeof (GeoclueConnectivityInterface), + geoclue_connectivity_base_init, + NULL, + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "GeoclueConnectivity", + &info, 0); + } + + return type; +} + +GeoclueConnectivity * +geoclue_connectivity_new (void) +{ + GeoclueConnectivity *connectivity = NULL; + +#ifdef HAVE_NETWORK_MANAGER + connectivity = GEOCLUE_CONNECTIVITY (g_object_new (GEOCLUE_TYPE_NETWORKMANAGER, NULL)); +#else +#ifdef HAVE_CONIC + connectivity = GEOCLUE_CONNECTIVITY (g_object_new (GEOCLUE_TYPE_CONIC, NULL)); +#else +#ifdef HAVE_CONNMAN + connectivity = GEOCLUE_CONNECTIVITY (g_object_new (GEOCLUE_TYPE_CONNMAN, NULL)); +#endif +#endif +#endif + return connectivity; +} + +GeoclueNetworkStatus +geoclue_connectivity_get_status (GeoclueConnectivity *self) +{ + return GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_status (self); +} + +/* Parse /proc/net/route to get default gateway address and then parse + * /proc/net/arp to find matching mac address. + * + * There are some problems with this. First, it's IPv4 only. + * Second, there must be a way to do this with ioctl, but that seemed really + * complicated... even /usr/sbin/arp parses /proc/net/arp + * + * returns: + * 1 : on success + * 0 : no success, no errors + * <0 : error + */ +static int +get_router_mac_fallback (char **mac) +{ + char *content; + char **lines, **entry; + GError *error = NULL; + char *route_gateway = NULL; + + g_assert (*mac == NULL); + + if (!g_file_get_contents ("/proc/net/route", &content, NULL, &error)) { + g_warning ("Failed to read /proc/net/route: %s", error->message); + g_error_free (error); + return -1; + } + + lines = g_strsplit (content, "\n", 0); + g_free (content); + entry = lines + 1; + + while (*entry && strlen (*entry) > 0) { + char dest[9]; + char gateway[9]; + if (sscanf (*entry, + "%*s %8[0-9A-Fa-f] %8[0-9A-Fa-f] %*s", + dest, gateway) != 2) { + g_warning ("Failed to parse /proc/net/route entry '%s'", *entry); + } else if (strcmp (dest, "00000000") == 0) { + route_gateway = g_strdup (gateway); + break; + } + entry++; + } + g_strfreev (lines); + + if (!route_gateway) { + g_warning ("Failed to find default route in /proc/net/route"); + return -1; + } + + if (!g_file_get_contents ("/proc/net/arp", &content, NULL, &error)) { + g_warning ("Failed to read /proc/net/arp: %s", error->message); + g_error_free (error); + return -1; + } + + lines = g_strsplit (content, "\n", 0); + g_free (content); + entry = lines+1; + while (*entry && strlen (*entry) > 0) { + char hwa[100]; + char *arp_gateway; + int ip[4]; + + if (sscanf(*entry, + "%d.%d.%d.%d 0x%*x 0x%*x %100s %*s %*s\n", + &ip[0], &ip[1], &ip[2], &ip[3], hwa) != 5) { + g_warning ("Failed to parse /proc/net/arp entry '%s'", *entry); + } else { + arp_gateway = g_strdup_printf ("%02X%02X%02X%02X", ip[3], ip[2], ip[1], ip[0]); + if (strcmp (arp_gateway, route_gateway) == 0) { + g_free (arp_gateway); + *mac = g_strdup (hwa); + break; + } + g_free (arp_gateway); + + } + entry++; + } + g_free (route_gateway); + g_strfreev (lines); + + return *mac ? 1 : 0; +} + +static char * +mac_strup (char *mac) +{ + guint i; + for (i = 0; mac[i] != '\0' ; i++) { + if (g_ascii_isalpha (mac[i])) + mac[i] = g_ascii_toupper (mac[i]); + } + return mac; +} + +char * +geoclue_connectivity_get_router_mac (GeoclueConnectivity *self) +{ + if (self == NULL || + GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_router_mac == NULL) { + char *mac = NULL; + guint i; + int ret_val; + + for (i = 0; i < 5; i++) { + ret_val = get_router_mac_fallback (&mac); + if (ret_val < 0) + return NULL; + else if (ret_val == 1) + break; + g_usleep (G_USEC_PER_SEC / 10); + } + return mac_strup (mac); + } + + return GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_router_mac (self); +} + +char * +geoclue_connectivity_get_ap_mac (GeoclueConnectivity *self) +{ + if (self != NULL && + GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_ap_mac != NULL) + return GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_ap_mac (self); + + /* Hack when not using NetworkManager */ + return geoclue_connectivity_get_router_mac (self); +} + +GHashTable * +geoclue_connectivity_get_aps (GeoclueConnectivity *self) +{ + char *ap; + GHashTable *ht; + + if (self != NULL && + GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_aps != NULL) + return GEOCLUE_CONNECTIVITY_GET_INTERFACE (self)->get_aps (self); + + /* Fallback if the backend does not support get_aps */ + ap = geoclue_connectivity_get_ap_mac (self); + if (ap == NULL) + return NULL; + ht = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, NULL); + g_hash_table_insert (ht, ap, GINT_TO_POINTER (DEFAULT_DBM)); + return NULL; +} + +void +geoclue_connectivity_emit_status_changed (GeoclueConnectivity *self, + GeoclueNetworkStatus status) +{ + g_signal_emit (self, signals[STATUS_CHANGED], 0, status); +} diff --git a/.pc/tizen.patch/src/connectivity.h b/.pc/tizen.patch/src/connectivity.h new file mode 100755 index 0000000..76afbd9 --- /dev/null +++ b/.pc/tizen.patch/src/connectivity.h @@ -0,0 +1,73 @@ +/* + * Geoclue + * geoclue-connectivity.h + * + * Author: Jussi Kukkonen <jku@o-hand.com> + * Copyright 2007 by Garmin Ltd. or its subsidiaries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef _GEOCLUE_CONNECTIVITY_H +#define _GEOCLUE_CONNECTIVITY_H + +#include <glib-object.h> +#include <geoclue/geoclue-types.h> + +G_BEGIN_DECLS + + +#define GEOCLUE_TYPE_CONNECTIVITY (geoclue_connectivity_get_type ()) +#define GEOCLUE_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GEOCLUE_TYPE_CONNECTIVITY, GeoclueConnectivity)) +#define GEOCLUE_IS_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEOCLUE_TYPE_CONNECTIVITY)) +#define GEOCLUE_CONNECTIVITY_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GEOCLUE_TYPE_CONNECTIVITY, GeoclueConnectivityInterface)) + +typedef struct _GeoclueConnectivity GeoclueConnectivity; +typedef struct _GeoclueConnectivityInterface GeoclueConnectivityInterface; + +struct _GeoclueConnectivityInterface { + GTypeInterface parent; + + /* signals */ + void (* status_changed) (GeoclueConnectivity *self, + GeoclueNetworkStatus status); + + /* vtable */ + int (*get_status) (GeoclueConnectivity *self); + GHashTable * (*get_aps) (GeoclueConnectivity *self); + char * (*get_ap_mac) (GeoclueConnectivity *self); + char * (*get_router_mac) (GeoclueConnectivity *self); +}; + +GType geoclue_connectivity_get_type (void); + +GeoclueConnectivity *geoclue_connectivity_new (void); + +GeoclueNetworkStatus geoclue_connectivity_get_status (GeoclueConnectivity *self); + +char *geoclue_connectivity_get_ap_mac (GeoclueConnectivity *self); +char *geoclue_connectivity_get_router_mac (GeoclueConnectivity *self); + +GHashTable *geoclue_connectivity_get_aps (GeoclueConnectivity *self); + +void +geoclue_connectivity_emit_status_changed (GeoclueConnectivity *self, + GeoclueNetworkStatus status); + +G_END_DECLS + +#endif diff --git a/.pc/tizen.patch/src/geoclue b/.pc/tizen.patch/src/geoclue new file mode 100755 index 0000000..03bde7f --- /dev/null +++ b/.pc/tizen.patch/src/geoclue @@ -0,0 +1,3 @@ +[org.freedesktop.Geoclue] +gps-baudrate = /apps/geoclue/master/org.freedesktop.Geoclue.GPSBaudRate +gps-device = /apps/geoclue/master/org.freedesktop.Geoclue.GPSDevice diff --git a/.pc/tizen.patch/src/main.c b/.pc/tizen.patch/src/main.c new file mode 100755 index 0000000..22668e6 --- /dev/null +++ b/.pc/tizen.patch/src/main.c @@ -0,0 +1,231 @@ +/* + * Geoclue + * main.c - Master process + * + * Author: Iain Holmes <iain@openedhand.com> + * Copyright 2007 by Garmin Ltd. or its subsidiaries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <gio/gio.h> + +#include <dbus/dbus-protocol.h> +#include <dbus/dbus-glib.h> +#include <dbus/dbus-glib-bindings.h> + +#include "master.h" + +static GMainLoop *mainloop; +static GHashTable *options; +static GSettings *settings; +static GcMaster *master; + + +#define GEOCLUE_SCHEMA_NAME "org.freedesktop.Geoclue" +#define GEOCLUE_MASTER_NAME "org.freedesktop.Geoclue.Master" + +static GValue * +gvariant_value_to_value (GVariant *value) +{ + GValue *gvalue; + const GVariantType *type; + + g_return_val_if_fail (value != NULL, NULL); + type = g_variant_get_type (value); + + if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_STRING)) { + const char *str; + + gvalue = g_new0 (GValue, 1); + str = g_variant_get_string (value, NULL); + + /* Don't add empty strings in the hashtable */ + if (str != NULL && str[0] == '\0') + str = NULL; + + g_value_init (gvalue, G_TYPE_STRING); + g_value_set_string (gvalue, str); + } else if (g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_UINT32)) { + int i; + + gvalue = g_new0 (GValue, 1); + i = g_variant_get_uint32 (value); + g_value_init (gvalue, G_TYPE_INT); + g_value_set_int (gvalue, i); + } else { + gvalue = NULL; + g_warning ("Value is of unknown type"); + } + + return gvalue; +} + +static void +debug_print_key (gboolean init, + const char *key, + GValue *gvalue) +{ + const char *message; + char *string; + + if (init) + message = "GSettings key '%s' initialised to '%s'"; + else + message = "GSettings key '%s' changed to '%s'"; + + if (G_VALUE_TYPE (gvalue) == G_TYPE_STRING) { + string = g_value_dup_string (gvalue); + } else if (G_VALUE_TYPE (gvalue) == G_TYPE_INT) { + string = g_strdup_printf ("%d", g_value_get_int (gvalue)); + } else { + return; + } + + g_message (message, key, string); + g_free (string); +} + +static void +gsettings_key_changed (GSettings *settings, + char *key, + gpointer user_data) +{ + GVariant *v; + GValue *gvalue; + + v = g_settings_get_value (settings, key); + gvalue = gvariant_value_to_value (v); + if (gvalue == NULL) { + g_variant_unref (v); + return; + } + + debug_print_key (FALSE, key, gvalue); + + g_hash_table_insert (options, g_strdup (key), gvalue); + + g_signal_emit_by_name (G_OBJECT (master), "options-changed", options); +} + +static void +free_gvalue (GValue *value) +{ + if (value == NULL) + return; + g_value_unset (value); + g_free (value); +} + +static GHashTable * +load_options (void) +{ + GHashTable *ht = NULL; + guint i; + const char const * keys[] = { + "gps-baudrate", + "gps-device" + }; + + /* Setup keys monitoring */ + g_signal_connect (G_OBJECT (settings), "changed", + G_CALLBACK (gsettings_key_changed), NULL); + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) free_gvalue); + + g_print ("Master options:\n"); + for (i = 0; i < G_N_ELEMENTS (keys); i++) { + GVariant *v; + GValue *gvalue; + const char *key = keys[i]; + + v = g_settings_get_value (settings, key); + gvalue = gvariant_value_to_value (v); + + if (gvalue == NULL) { + g_variant_unref (v); + continue; + } + + debug_print_key (TRUE, key, gvalue); + + g_hash_table_insert (ht, g_strdup (key), gvalue); + g_variant_unref (v); + } + + return ht; + } + +GHashTable * +geoclue_get_main_options (void) +{ + return options; +} + +int +main (int argc, + char **argv) +{ + DBusGConnection *conn; + DBusGProxy *proxy; + GError *error = NULL; + guint32 request_name_ret; + + g_type_init (); + + mainloop = g_main_loop_new (NULL, FALSE); + + conn = dbus_g_bus_get (GEOCLUE_DBUS_BUS, &error); + if (!conn) { + g_error ("Error getting bus: %s", error->message); + return 1; + } + + proxy = dbus_g_proxy_new_for_name (conn, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + if (!org_freedesktop_DBus_request_name (proxy, GEOCLUE_MASTER_NAME, + 0, &request_name_ret, &error)) { + g_error ("Error registering D-Bus service %s: %s", + GEOCLUE_MASTER_NAME, error->message); + return 1; + } + + /* Just quit if master is already running */ + if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + return 1; + } + + /* Load options */ + settings = g_settings_new (GEOCLUE_SCHEMA_NAME); + options = load_options (); + + master = g_object_new (GC_TYPE_MASTER, NULL); + dbus_g_connection_register_g_object (conn, + "/org/freedesktop/Geoclue/Master", + G_OBJECT (master)); + + g_main_loop_run (mainloop); + return 0; +} diff --git a/.pc/tizen.patch/src/master-provider.c b/.pc/tizen.patch/src/master-provider.c new file mode 100755 index 0000000..e4ea053 --- /dev/null +++ b/.pc/tizen.patch/src/master-provider.c @@ -0,0 +1,1309 @@ +/* + * Geoclue + * master-provider.c - Provider object for master and master client + * + * Author: Jussi Kukkonen <jku@o-hand.com> + * + * Copyright 2007-2008 by Garmin Ltd. or its subsidiaries + * 2008 OpenedHand Ltd + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/** + * Provider object for GcMaster. Takes care of cacheing + * queried data. + * + * Should probably start/stop the actual providers as needed + * in the future + * + * Cache could also be used to save "stale" data for situations when + * current data is not available (MasterClient api would have to + * have a "allowOldData" setting) + * + * TODO: + * figure out what to do if get_* returns GEOCLUE_ERROR_NOT_AVAILABLE. + * Should try again, but when? + * + * implement velocity + * + * implement other (non-updating) ifaces + **/ + +#include <string.h> + +#include "main.h" +#include "master-provider.h" +#include <geoclue/geoclue-position.h> +#include <geoclue/geoclue-address.h> +#include <geoclue/geoclue-marshal.h> + +typedef enum _GeoclueProvideFlags { + GEOCLUE_PROVIDE_NONE = 0, + GEOCLUE_PROVIDE_UPDATES = 1 << 0, /* will send *-changed signals */ + GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION = 1 << 1, /* data can be queried on new connection, and cached until connection ends */ +} GeoclueProvideFlags; + +typedef struct _GcPositionCache { + int timestamp; + GeocluePositionFields fields; + double latitude; + double longitude; + double altitude; + GeoclueAccuracy *accuracy; + GError *error; +} GcPositionCache; + +typedef struct _GcAddressCache { + int timestamp; + GHashTable *details; + GeoclueAccuracy *accuracy; + GError *error; +} GcAddressCache; + +typedef struct _GcMasterProviderPrivate { + char *name; + char *description; + + char *service; + char *path; + GcInterfaceFlags interfaces; + + GList *position_clients; /* list of clients currently using this provider */ + GList *address_clients; + + GeoclueAccuracyLevel expected_accuracy; + + GeoclueResourceFlags required_resources; + GeoclueProvideFlags provides; + + GeoclueStatus master_status; /* net_status and status affect this */ + GeoclueNetworkStatus net_status; + + GeoclueStatus status; /* cached status from actual provider */ + + GeocluePosition *position; + GcPositionCache position_cache; + + GeoclueAddress *address; + GcAddressCache address_cache; + +} GcMasterProviderPrivate; + +enum { + STATUS_CHANGED, + ACCURACY_CHANGED, + POSITION_CHANGED, + ADDRESS_CHANGED, + LAST_SIGNAL +}; +static guint32 signals[LAST_SIGNAL] = {0, }; + +#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GC_TYPE_MASTER_PROVIDER, GcMasterProviderPrivate)) + +G_DEFINE_TYPE (GcMasterProvider, gc_master_provider, G_TYPE_OBJECT) + +static void +copy_error (GError **target, GError *source) +{ + if (*target) { + g_error_free (*target); + *target = NULL; + } + if (source) { + *target = g_error_copy (source); + + /* If the error type is a D-Bus remote exception, + * don't lose the "magic" sauce after the message string. + * See the code in gerror_to_dbus_error_message() in dbus-glib */ + if (source->domain == DBUS_GERROR && + source->code == DBUS_GERROR_REMOTE_EXCEPTION) { + int len; + g_free ((*target)->message); + len = strlen (source->message); + len += strlen (source->message + len + 1); + len += 2; + (*target)->message = g_memdup (source->message, len); + } + } +} + +static GeoclueProvider* +gc_master_provider_get_provider (GcMasterProvider *master_provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (master_provider); + + if (priv->address) { + return GEOCLUE_PROVIDER (priv->address); + } + if (priv->position) { + return GEOCLUE_PROVIDER (priv->position); + } + return NULL; +} + +static gboolean +gc_master_provider_is_running (GcMasterProvider *master_provider) +{ + return (gc_master_provider_get_provider (master_provider) != NULL); +} + +static void +gc_master_provider_handle_new_position_accuracy (GcMasterProvider *provider, + GeoclueAccuracy *accuracy) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + GeoclueAccuracyLevel old_level; + GeoclueAccuracyLevel new_level = GEOCLUE_ACCURACY_LEVEL_NONE; + double new_hor_acc, new_vert_acc; + + geoclue_accuracy_get_details (priv->position_cache.accuracy, + &old_level, NULL, NULL); + if (accuracy) { + geoclue_accuracy_get_details (accuracy, + &new_level, &new_hor_acc, &new_vert_acc); + } + geoclue_accuracy_set_details (priv->position_cache.accuracy, + new_level, new_hor_acc, new_vert_acc); + + if (old_level != new_level) { + g_signal_emit (provider, signals[ACCURACY_CHANGED], 0, + GC_IFACE_POSITION, new_level); + } +} + +static void +gc_master_provider_handle_new_address_accuracy (GcMasterProvider *provider, + GeoclueAccuracy *accuracy) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + GeoclueAccuracyLevel old_level; + GeoclueAccuracyLevel new_level = GEOCLUE_ACCURACY_LEVEL_NONE; + double new_hor_acc, new_vert_acc; + + geoclue_accuracy_get_details (priv->address_cache.accuracy, + &old_level, NULL, NULL); + if (accuracy) { + geoclue_accuracy_get_details (accuracy, + &new_level, &new_hor_acc, &new_vert_acc); + } + geoclue_accuracy_set_details (priv->address_cache.accuracy, + new_level, new_hor_acc, new_vert_acc); + + if (old_level != new_level) { + g_signal_emit (provider, signals[ACCURACY_CHANGED], 0, + GC_IFACE_ADDRESS, new_level); + } +} + +static void +gc_master_provider_set_position (GcMasterProvider *provider, + GeocluePositionFields fields, + int timestamp, + double latitude, + double longitude, + double altitude, + GeoclueAccuracy *accuracy, + GError *error) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + priv->position_cache.timestamp = timestamp; + priv->position_cache.fields = fields; + priv->position_cache.latitude = latitude; + priv->position_cache.longitude = longitude; + priv->position_cache.altitude = altitude; + + copy_error (&priv->position_cache.error, error); + + /* emit accuracy-changed if needed, so masterclient can re-choose providers + * before we emit position-changed */ + gc_master_provider_handle_new_position_accuracy (provider, accuracy); + + if (!error) { + g_signal_emit (provider, signals[POSITION_CHANGED], 0, + fields, timestamp, + latitude, longitude, altitude, + priv->position_cache.accuracy); + } +} + +static void +gc_master_provider_set_address (GcMasterProvider *provider, + int timestamp, + GHashTable *details, + GeoclueAccuracy *accuracy, + GError *error) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + priv->address_cache.timestamp = timestamp; + + g_hash_table_destroy (priv->address_cache.details); + if (details) { + priv->address_cache.details = geoclue_address_details_copy (details); + }else { + priv->address_cache.details = geoclue_address_details_new (); + } + copy_error (&priv->address_cache.error, error); + + /* emit accuracy-changed if needed, so masterclient can re-choose providers + * before we emit position-changed */ + gc_master_provider_handle_new_address_accuracy (provider, accuracy); + + if (!error) { + g_signal_emit (provider, signals[ADDRESS_CHANGED], 0, + priv->address_cache.timestamp, + priv->address_cache.details, + priv->address_cache.accuracy); + } +} + + + +static GeoclueResourceFlags +parse_resource_strings (char **flags) +{ + GeoclueResourceFlags resources = GEOCLUE_RESOURCE_NONE; + int i; + + for (i = 0; flags[i]; i++) { + if (strcmp (flags[i], "RequiresNetwork") == 0) { + resources |= GEOCLUE_RESOURCE_NETWORK; + } else if (strcmp (flags[i], "RequiresCell") == 0) { + resources |= GEOCLUE_RESOURCE_CELL; + } else if (strcmp (flags[i], "RequiresGPS") == 0) { + resources |= GEOCLUE_RESOURCE_GPS; + } + } + + return resources; +} + +static GeoclueProvideFlags +parse_provide_strings (char **flags) +{ + GeoclueProvideFlags provides = GEOCLUE_PROVIDE_NONE; + int i; + + for (i = 0; flags[i]; i++) { + if (strcmp (flags[i], "ProvidesUpdates") == 0) { + provides |= GEOCLUE_PROVIDE_UPDATES; + } else if (strcmp (flags[i], "ProvidesCacheableOnConnection") == 0) { + provides |= GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION; + } + } + + return provides; +} + +static GcInterfaceFlags +parse_interface_strings (char **strs) +{ + GcInterfaceFlags ifaces = GC_IFACE_GEOCLUE; + int i; + + for (i = 0; strs[i]; i++) { + if (strcmp (strs[i], GEOCLUE_POSITION_INTERFACE_NAME) == 0) { + ifaces |= GC_IFACE_POSITION; + } else if (strcmp (strs[i], GEOCLUE_ADDRESS_INTERFACE_NAME) == 0) { + ifaces |= GC_IFACE_ADDRESS; + } + } + return ifaces; +} + +static GeoclueAccuracyLevel +parse_accuracy_string (char *str) +{ + GeoclueAccuracyLevel level = GEOCLUE_ACCURACY_LEVEL_NONE; + if (!str || strcmp (str, "None") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_NONE; + } else if (strcmp (str, "Country") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_COUNTRY; + } else if (strcmp (str, "Region") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_REGION; + } else if (strcmp (str, "Locality") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_LOCALITY; + } else if (strcmp (str, "Postalcode") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_POSTALCODE; + } else if (strcmp (str, "Street") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_STREET; + } else if (strcmp (str, "Detailed") == 0) { + level = GEOCLUE_ACCURACY_LEVEL_DETAILED; + } else { + g_warning ("'%s' is not a recognised accuracy level value", str); + } + return level; +} + +static void +gc_master_provider_handle_error (GcMasterProvider *provider, GError *error) +{ + GcMasterProviderPrivate *priv; + + g_assert (error); + + priv = GET_PRIVATE (provider); + g_debug ("%s handling error %d", priv->name, error->code); + + /* web service providers that are unavailable */ + if (priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION && + error->code == GEOCLUE_ERROR_NOT_AVAILABLE) { + priv->master_status = GEOCLUE_STATUS_UNAVAILABLE; + /* TODO set timer to re-check availability */ + } +} + +/* Sets master_status based on provider status and net_status + * Should be called whenever priv->status or priv->net_status change */ +static void +gc_master_provider_handle_status_change (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + GeoclueStatus new_master_status; + + /* calculate new master status */ + if (priv->required_resources & GEOCLUE_RESOURCE_NETWORK || + priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION) { + switch (priv->net_status) { + case GEOCLUE_CONNECTIVITY_UNKNOWN: + /* falling through */ + case GEOCLUE_CONNECTIVITY_OFFLINE: + new_master_status = GEOCLUE_STATUS_UNAVAILABLE; + break; + case GEOCLUE_CONNECTIVITY_ACQUIRING: + if (priv->status == GEOCLUE_STATUS_AVAILABLE){ + new_master_status = GEOCLUE_STATUS_ACQUIRING; + } else { + new_master_status = priv->status; + } + break; + case GEOCLUE_CONNECTIVITY_ONLINE: + new_master_status = priv->status; + break; + default: + g_assert_not_reached (); + } + + } else { + new_master_status = priv->status; + } + + if (new_master_status != priv->master_status) { + priv->master_status = new_master_status; + + g_signal_emit (provider, signals[STATUS_CHANGED], 0, new_master_status); + } +} + + +static void +gc_master_provider_update_cache (GcMasterProvider *master_provider) +{ + GcMasterProviderPrivate *priv; + + priv = GET_PRIVATE (master_provider); + + if ((!(priv->provides & GEOCLUE_PROVIDE_UPDATES)) || + (!gc_master_provider_get_provider (master_provider))) { + /* non-cacheable provider or provider not running */ + return; + } + + g_debug ("%s: Updating cache ", priv->name); + priv->master_status = GEOCLUE_STATUS_ACQUIRING; + g_signal_emit (master_provider, signals[STATUS_CHANGED], 0, priv->master_status); + + if (priv->position) { + int timestamp; + double lat, lon, alt; + GeocluePositionFields fields; + GeoclueAccuracy *accuracy = NULL; + GError *error = NULL; + + fields = geoclue_position_get_position (priv->position, + ×tamp, + &lat, &lon, &alt, + &accuracy, + &error); + if (error){ + g_warning ("Error updating position cache: %s", error->message); + gc_master_provider_handle_error (master_provider, error); + } + gc_master_provider_set_position (master_provider, + fields, timestamp, + lat, lon, alt, + accuracy, error); + } + + if (priv->address) { + int timestamp; + GHashTable *details = NULL; + GeoclueAccuracy *accuracy = NULL; + GError *error = NULL; + + if (!geoclue_address_get_address (priv->address, + ×tamp, + &details, + &accuracy, + &error)) { + g_warning ("Error updating address cache: %s", error->message); + gc_master_provider_handle_error (master_provider, error); + } + gc_master_provider_set_address (master_provider, + timestamp, + details, + accuracy, + error); + } + + gc_master_provider_handle_status_change (master_provider); +} + +/* signal handlers for the actual providers signals */ + +static void +provider_status_changed (GeoclueProvider *provider, + GeoclueStatus status, + GcMasterProvider *master_provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (master_provider); + + priv->status = status; + gc_master_provider_handle_status_change (master_provider); +} + +static void +position_changed (GeocluePosition *position, + GeocluePositionFields fields, + int timestamp, + double latitude, + double longitude, + double altitude, + GeoclueAccuracy *accuracy, + GcMasterProvider *provider) +{ + /* is there a situation when we'd need to check against cache + * if data has really changed? probably not */ + gc_master_provider_set_position (provider, + fields, timestamp, + latitude, longitude, altitude, + accuracy, NULL); +} + +static void +address_changed (GeoclueAddress *address, + int timestamp, + GHashTable *details, + GeoclueAccuracy *accuracy, + GcMasterProvider *provider) +{ + /* is there a situation when we'd need to check against cache + * if data has really changed? probably not */ + gc_master_provider_set_address (provider, + timestamp, + details, + accuracy, + NULL); +} + + +static void +finalize (GObject *object) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (object); + + geoclue_accuracy_free (priv->position_cache.accuracy); + geoclue_accuracy_free (priv->address_cache.accuracy); + if (priv->position_cache.error) { + g_error_free (priv->position_cache.error); + } + if (priv->address_cache.error) { + g_error_free (priv->address_cache.error); + } + + g_free (priv->name); + g_free (priv->description); + g_free (priv->service); + g_free (priv->path); + + g_free (priv->position_clients); + g_free (priv->address_clients); + + G_OBJECT_CLASS (gc_master_provider_parent_class)->finalize (object); +} + +static void +dispose (GObject *object) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (object); + + if (priv->position) { + g_object_unref (priv->position); + priv->position = NULL; + } + + if (priv->address) { + g_object_unref (priv->address); + priv->address = NULL; + } + if (priv->address_cache.details) { + g_hash_table_destroy (priv->address_cache.details); + priv->address_cache.details = NULL; + } + + G_OBJECT_CLASS (gc_master_provider_parent_class)->dispose (object); +} + +static void +gc_master_provider_class_init (GcMasterProviderClass *klass) +{ + GObjectClass *o_class = (GObjectClass *) klass; + + o_class->finalize = finalize; + o_class->dispose = dispose; + + g_type_class_add_private (klass, sizeof (GcMasterProviderPrivate)); + + signals[STATUS_CHANGED] = g_signal_new ("status-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (GcMasterProviderClass, status_changed), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, + G_TYPE_INT); + signals[ACCURACY_CHANGED] = g_signal_new ("accuracy-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (GcMasterProviderClass, accuracy_changed), + NULL, NULL, + geoclue_marshal_VOID__INT_INT, + G_TYPE_NONE, 2, + G_TYPE_INT, G_TYPE_INT); + signals[POSITION_CHANGED] = g_signal_new ("position-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (GcMasterProviderClass, position_changed), + NULL, NULL, + geoclue_marshal_VOID__INT_INT_DOUBLE_DOUBLE_DOUBLE_BOXED, + G_TYPE_NONE, 6, + G_TYPE_INT, G_TYPE_INT, + G_TYPE_DOUBLE, G_TYPE_DOUBLE, G_TYPE_DOUBLE, + G_TYPE_POINTER); + signals[ADDRESS_CHANGED] = g_signal_new ("address-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (GcMasterProviderClass, address_changed), + NULL, NULL, + geoclue_marshal_VOID__INT_BOXED_BOXED, + G_TYPE_NONE, 3, + G_TYPE_INT, + G_TYPE_POINTER, + G_TYPE_POINTER); +} + +static void +gc_master_provider_init (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + priv->position_clients = NULL; + priv->address_clients = NULL; + + priv->master_status = GEOCLUE_STATUS_UNAVAILABLE; + + priv->position = NULL; + priv->position_cache.accuracy = + geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_NONE, 0 ,0); + priv->position_cache.error = NULL; + + priv->address = NULL; + priv->address_cache.accuracy = + geoclue_accuracy_new (GEOCLUE_ACCURACY_LEVEL_NONE, 0 ,0); + priv->address_cache.details = geoclue_address_details_new (); + priv->address_cache.error = NULL; +} + +#if DEBUG_INFO +static void +gc_master_provider_dump_position (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv; + GeocluePositionFields fields; + int time; + double lat, lon, alt; + GError *error = NULL; + + priv = GET_PRIVATE (provider); + + + g_print (" Position Information:\n"); + g_print (" ---------------------\n"); + + fields = gc_master_provider_get_position (provider, + &time, + &lat, &lon, &alt, + NULL, &error); + if (error) { + g_print (" Error: %s", error->message); + g_error_free (error); + return; + } + g_print (" Timestamp: %d\n", time); + g_print (" Latitude: %.2f %s\n", lat, + fields & GEOCLUE_POSITION_FIELDS_LATITUDE ? "" : "(not set)"); + g_print (" Longitude: %.2f %s\n", lon, + fields & GEOCLUE_POSITION_FIELDS_LONGITUDE ? "" : "(not set)"); + g_print (" Altitude: %.2f %s\n", alt, + fields & GEOCLUE_POSITION_FIELDS_ALTITUDE ? "" : "(not set)"); + +} + +static void +dump_address_key_and_value (char *key, char *value, GHashTable *target) +{ + g_print (" %s: %s\n", key, value); +} + +static void +gc_master_provider_dump_address (GcMasterProvider *provider) +{ + int time; + GHashTable *details; + GError *error = NULL; + + g_print (" Address Information:\n"); + g_print (" --------------------\n"); + if (!gc_master_provider_get_address (provider, + &time, + &details, + NULL, &error)) { + g_print (" Error: %s", error->message); + g_error_free (error); + return; + } + g_print (" Timestamp: %d\n", time); + g_hash_table_foreach (details, (GHFunc)dump_address_key_and_value, NULL); + +} + +static void +gc_master_provider_dump_required_resources (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv; + + priv = GET_PRIVATE (provider); + g_print (" Requires\n"); + if (priv->required_resources & GEOCLUE_RESOURCE_GPS) { + g_print (" - GPS\n"); + } + + if (priv->required_resources & GEOCLUE_RESOURCE_NETWORK) { + g_print (" - Network\n"); + } +} + +static void +gc_master_provider_dump_provides (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv; + + priv = GET_PRIVATE (provider); + g_print (" Provides\n"); + if (priv->provides & GEOCLUE_PROVIDE_UPDATES) { + g_print (" - Updates\n"); + } + if (priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION) { + g_print (" - Cacheable on network connection\n"); + } +} + +static void +gc_master_provider_dump_provider_details (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv; + + priv = GET_PRIVATE (provider); + g_print ("\n Name - %s\n", priv->name); + g_print (" Description - %s\n", priv->description); + g_print (" Service - %s\n", priv->service); + g_print (" Path - %s\n", priv->path); + g_print (" Accuracy level - %d\n", priv->expected_accuracy); + g_print (" Provider is currently %srunning, status %d\n", + gc_master_provider_get_provider (master_provider) ? "" : "not ", + priv->master_status); + gc_master_provider_dump_required_resources (provider); + gc_master_provider_dump_provides (provider); + + + if (priv->interfaces & GC_IFACE_POSITION) { + g_print (" Interface - Position\n"); + gc_master_provider_dump_position (provider); + } + if (priv->interfaces & GC_IFACE_ADDRESS) { + g_print (" Interface - Address\n"); + gc_master_provider_dump_address (provider); + } +} +#endif + +static gboolean +gc_master_provider_initialize_geoclue (GcMasterProvider *master_provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (master_provider); + GeoclueProvider *geoclue; + GError *error = NULL; + + geoclue = gc_master_provider_get_provider (master_provider); + + if (!geoclue_provider_set_options (geoclue, + geoclue_get_main_options (), + &error)) { + g_warning ("Error setting provider options: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + /* priv->name has been read from .provider-file earlier... + * could ask the provider anyway, just to be consistent */ + if (!geoclue_provider_get_provider_info (geoclue, NULL, + &priv->description, &error)) { + g_warning ("Error getting provider info: %s\n", error->message); + g_error_free (error); + return FALSE; + } + + g_signal_connect (G_OBJECT (geoclue), "status-changed", + G_CALLBACK (provider_status_changed), master_provider); + + + if (!geoclue_provider_get_status (geoclue, &priv->status, &error)) { + g_warning ("Error getting provider status: %s\n", error->message); + g_error_free (error); + return FALSE; + } + return TRUE; +} + +static gboolean +gc_master_provider_initialize_interfaces (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv; + + priv = GET_PRIVATE (provider); + + if (priv->interfaces <= GC_IFACE_GEOCLUE) { + g_warning ("No interfaces defined for %s", priv->name); + return FALSE; + } + + if (priv->interfaces & GC_IFACE_POSITION) { + g_assert (priv->position == NULL); + + priv->position = geoclue_position_new (priv->service, + priv->path); + g_signal_connect (G_OBJECT (priv->position), "position-changed", + G_CALLBACK (position_changed), provider); + } + if (priv->interfaces & GC_IFACE_ADDRESS) { + g_assert (priv->address == NULL); + + priv->address = geoclue_address_new (priv->service, + priv->path); + g_signal_connect (G_OBJECT (priv->address), "address-changed", + G_CALLBACK (address_changed), provider); + } + + if (!gc_master_provider_initialize_geoclue (provider)) { + return FALSE; + } + + return TRUE; +} + + +static gboolean +gc_master_provider_initialize (GcMasterProvider *provider) +{ + if (!gc_master_provider_initialize_interfaces (provider)) { + return FALSE; + } + + gc_master_provider_update_cache (provider); +#if DEBUG_INFO + gc_master_provider_dump_provider_details (provider); +#endif + return TRUE; +} + +static void +gc_master_provider_deinitialize (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + if (priv->position) { + g_object_unref (priv->position); + priv->position = NULL; + } + if (priv->address) { + g_object_unref (priv->address); + priv->address = NULL; + } + g_debug ("deinited %s", priv->name); +} + +static void +network_status_changed (gpointer *connectivity, + GeoclueNetworkStatus status, + GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv; + + priv = GET_PRIVATE (provider); + + priv->net_status = status; + /* update connection-cacheable providers */ + if (status == GEOCLUE_CONNECTIVITY_ONLINE && + priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION) { + /* intialize to fill cache (this will handle status change) */ + if (gc_master_provider_initialize (provider)) { + gc_master_provider_deinitialize (provider); + } + } else { + gc_master_provider_handle_status_change (provider); + } +} + +/* for updating cache on providers that are not running */ +static gboolean +update_cache_and_deinit (GcMasterProvider *provider) +{ + /* fill cache */ + if (gc_master_provider_initialize (provider)) { + gc_master_provider_deinitialize (provider); + } + return FALSE; +} + + +/* public methods (for GcMaster and GcMasterClient) */ + +/* Loads provider details from 'filename' */ +GcMasterProvider * +gc_master_provider_new (const char *filename, + GeoclueConnectivity *connectivity) +{ + GcMasterProvider *provider; + GcMasterProviderPrivate *priv; + GKeyFile *keyfile; + GError *error = NULL; + gboolean ret; + char *accuracy_str; + char **flags, **interfaces; + + keyfile = g_key_file_new (); + ret = g_key_file_load_from_file (keyfile, filename, + G_KEY_FILE_NONE, &error); + if (ret == FALSE) { + g_warning ("Error loading %s: %s", filename, error->message); + g_error_free (error); + g_key_file_free (keyfile); + return NULL; + } + + provider = g_object_new (GC_TYPE_MASTER_PROVIDER, NULL); + priv = GET_PRIVATE (provider); + + priv->name = g_key_file_get_value (keyfile, "Geoclue Provider", + "Name", NULL); + priv->service = g_key_file_get_value (keyfile, "Geoclue Provider", + "Service", NULL); + priv->path = g_key_file_get_value (keyfile, "Geoclue Provider", + "Path", NULL); + + accuracy_str = g_key_file_get_value (keyfile, "Geoclue Provider", + "Accuracy", NULL); + priv->expected_accuracy = parse_accuracy_string (accuracy_str); + if (accuracy_str){ + g_free (accuracy_str); + } + + /* set cached accuracies to a default value */ + geoclue_accuracy_set_details (priv->position_cache.accuracy, + priv->expected_accuracy, 0.0, 0.0); + geoclue_accuracy_set_details (priv->address_cache.accuracy, + priv->expected_accuracy, 0.0, 0.0); + + + flags = g_key_file_get_string_list (keyfile, "Geoclue Provider", + "Requires", NULL, NULL); + if (flags != NULL) { + priv->required_resources = parse_resource_strings (flags); + g_strfreev (flags); + } else { + priv->required_resources = GEOCLUE_RESOURCE_NONE; + } + + flags = g_key_file_get_string_list (keyfile, "Geoclue Provider", + "Provides", NULL, NULL); + if (flags != NULL) { + priv->provides = parse_provide_strings (flags); + g_strfreev (flags); + } else { + priv->provides = GEOCLUE_PROVIDE_NONE; + } + + if (!connectivity && + (priv->required_resources & GEOCLUE_RESOURCE_NETWORK)) { + priv->provides &= ~GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION; + priv->net_status = GEOCLUE_CONNECTIVITY_ONLINE; + priv->status = GEOCLUE_STATUS_AVAILABLE; + gc_master_provider_handle_status_change (provider); + } + + if (connectivity && + (priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION)) { + + /* we have network status events: mark network provider + * with update flag, set the callback and set use_cache */ + priv->provides |= GEOCLUE_PROVIDE_UPDATES; + + g_signal_connect (connectivity, + "status-changed", + G_CALLBACK (network_status_changed), + provider); + priv->net_status = geoclue_connectivity_get_status (connectivity); + } + + priv->interfaces = GC_IFACE_GEOCLUE; + interfaces = g_key_file_get_string_list (keyfile, + "Geoclue Provider", + "Interfaces", + NULL, NULL); + if (interfaces) { + priv->interfaces = parse_interface_strings (interfaces); + g_strfreev (interfaces); + } + + if (priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION && + priv->net_status == GEOCLUE_CONNECTIVITY_ONLINE) { + /* do this as idle so we can return without waiting for http queries */ + g_idle_add ((GSourceFunc)update_cache_and_deinit, provider); + } + return provider; +} + +/* client calls this when it wants to use the provider. + Returns true if provider was actually started, and + client should assume accuracy has changed. + Returns false if provider was not started (it was either already + running or starting the provider failed). */ +gboolean +gc_master_provider_subscribe (GcMasterProvider *provider, + gpointer client, + GcInterfaceFlags interface) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + gboolean started = FALSE; + + /* decide wether to run initialize or not */ + if (!gc_master_provider_is_running (provider)) { + if (!(priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION)) { + started = gc_master_provider_initialize (provider); + } + } + + /* add subscription */ + if (interface & GC_IFACE_POSITION) { + if (!g_list_find (priv->position_clients, client)) { + priv->position_clients = g_list_prepend (priv->position_clients, client); + } + } + if (interface & GC_IFACE_ADDRESS) { + if (!g_list_find (priv->address_clients, client)) { + priv->address_clients = g_list_prepend (priv->address_clients, client); + } + } + + return started; +} + +/* client calls this when it does not intend to use the provider */ +void +gc_master_provider_unsubscribe (GcMasterProvider *provider, + gpointer client, + GcInterfaceFlags interface) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + if (interface & GC_IFACE_POSITION) { + priv->position_clients = g_list_remove (priv->position_clients, client); + } + if (interface & GC_IFACE_ADDRESS) { + priv->address_clients = g_list_remove (priv->address_clients, client); + } + + if (!priv->position_clients && + !priv->address_clients) { + /* no one is using this provider, shutdown... */ + /* not clearing cached accuracies on purpose */ + g_debug ("%s without clients", priv->name); + + /* gc_master_provider_deinitialize (provider); */ + } +} + + +GeocluePositionFields +gc_master_provider_get_position (GcMasterProvider *provider, + int *timestamp, + double *latitude, + double *longitude, + double *altitude, + GeoclueAccuracy **accuracy, + GError **error) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + g_assert (priv->position || + priv->provides & GEOCLUE_PROVIDE_CACHEABLE_ON_CONNECTION); + + if (priv->provides & GEOCLUE_PROVIDE_UPDATES) { + if (timestamp != NULL) { + *timestamp = priv->position_cache.timestamp; + } + if (latitude != NULL) { + *latitude = priv->position_cache.latitude; + } + if (longitude != NULL) { + *longitude = priv->position_cache.longitude; + } + if (altitude != NULL) { + *altitude = priv->position_cache.altitude; + } + if (accuracy != NULL) { + *accuracy = geoclue_accuracy_copy (priv->position_cache.accuracy); + } + if (error != NULL) { + g_assert (!*error); + copy_error (error, priv->position_cache.error); + } + return priv->position_cache.fields; + } else { + return geoclue_position_get_position (priv->position, + timestamp, + latitude, + longitude, + altitude, + accuracy, + error); + } +} + +gboolean +gc_master_provider_get_address (GcMasterProvider *provider, + int *timestamp, + GHashTable **details, + GeoclueAccuracy **accuracy, + GError **error) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + if (priv->provides & GEOCLUE_PROVIDE_UPDATES) { + + if (timestamp != NULL) { + *timestamp = priv->address_cache.timestamp; + } + if (details != NULL) { + *details = geoclue_address_details_copy (priv->address_cache.details); + } + if (accuracy != NULL) { + *accuracy = geoclue_accuracy_copy (priv->address_cache.accuracy); + } + if (error != NULL) { + g_assert (!*error); + copy_error (error, priv->address_cache.error); + } + return (!priv->address_cache.error); + } else { + g_assert (priv->address); + return geoclue_address_get_address (priv->address, + timestamp, + details, + accuracy, + error); + } +} + +gboolean +gc_master_provider_is_good (GcMasterProvider *provider, + GcInterfaceFlags iface_type, + GeoclueAccuracyLevel min_accuracy, + gboolean need_update, + GeoclueResourceFlags allowed_resources) +{ + GcMasterProviderPrivate *priv; + GcInterfaceFlags supported_ifaces; + GeoclueProvideFlags required_flags = GEOCLUE_PROVIDE_NONE; + + priv = GET_PRIVATE (provider); + + if (need_update) { + required_flags |= GEOCLUE_PROVIDE_UPDATES; + } + + supported_ifaces = priv->interfaces; + + /* provider must provide all that is required and + * cannot require a resource that is not allowed */ + /* TODO: really, we need to change some of those terms... */ + + return (((supported_ifaces & iface_type) == iface_type) && + ((priv->provides & required_flags) == required_flags) && + (priv->expected_accuracy >= min_accuracy) && + ((priv->required_resources & (~allowed_resources)) == 0)); +} + +void +gc_master_provider_update_options (GcMasterProvider *provider) +{ + GeoclueProvider *geoclue; + GError *error = NULL; + + geoclue = gc_master_provider_get_provider (provider); + + if (!geoclue_provider_set_options (geoclue, + geoclue_get_main_options (), + &error)) { + g_warning ("Error setting provider options: %s\n", error->message); + g_error_free (error); + } +} + +GeoclueStatus +gc_master_provider_get_status (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + return priv->master_status; +} + +GeoclueAccuracyLevel +gc_master_provider_get_accuracy (GcMasterProvider *provider, GcInterfaceFlags iface) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + GeoclueAccuracyLevel acc_level; + + switch (iface) { + case GC_IFACE_POSITION: + geoclue_accuracy_get_details (priv->position_cache.accuracy, + &acc_level, NULL, NULL); + break; + case GC_IFACE_ADDRESS: + geoclue_accuracy_get_details (priv->address_cache.accuracy, + &acc_level, NULL, NULL); + break; + default: + g_assert_not_reached (); + } + return acc_level; +} + +/*returns a reference, but is not meant for editing...*/ +char * +gc_master_provider_get_name (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + return priv->name; +} +char * +gc_master_provider_get_description (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + return priv->description; +} +char * +gc_master_provider_get_service (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + return priv->service; +} +char * +gc_master_provider_get_path (GcMasterProvider *provider) +{ + GcMasterProviderPrivate *priv = GET_PRIVATE (provider); + + return priv->path; +} + +/* GCompareDataFunc for sorting providers by accuracy and required resources */ +int +gc_master_provider_compare (GcMasterProvider *a, + GcMasterProvider *b, + GcInterfaceAccuracy *iface_min_accuracy) +{ + int diff; + GeoclueAccuracy *acc_a, *acc_b; + GeoclueAccuracyLevel level_a, level_b, min_level; + + + GcMasterProviderPrivate *priv_a = GET_PRIVATE (a); + GcMasterProviderPrivate *priv_b = GET_PRIVATE (b); + + /* get the current accuracylevels */ + switch (iface_min_accuracy->interface) { + case GC_IFACE_POSITION: + acc_a = priv_a->position_cache.accuracy; + acc_b = priv_b->position_cache.accuracy; + break; + case GC_IFACE_ADDRESS: + acc_a = priv_a->address_cache.accuracy; + acc_b = priv_b->address_cache.accuracy; + break; + default: + g_warning("iface: %d", iface_min_accuracy->interface); + g_assert_not_reached (); + } + + + geoclue_accuracy_get_details (acc_a, &level_a, NULL, NULL); + geoclue_accuracy_get_details (acc_b, &level_b, NULL, NULL); + min_level = iface_min_accuracy->accuracy_level; + + /* sort by resource requirements and accuracy, but only if both + * providers meet the minimum accuracy requirement */ + if ((level_b >= min_level) && + (level_a >= min_level)) { + diff = priv_a->required_resources - priv_b->required_resources; + if (diff != 0 ) { + return diff; + } + return level_b - level_a; + } + + /* one or both do not meet req's, sort by accuracy */ + return level_b - level_a; +} diff --git a/.pc/tizen.patch/src/master.c b/.pc/tizen.patch/src/master.c new file mode 100755 index 0000000..7877e61 --- /dev/null +++ b/.pc/tizen.patch/src/master.c @@ -0,0 +1,211 @@ +/* + * Geoclue + * master.c - Master process + * + * Authors: Iain Holmes <iain@openedhand.com> + * Jussi Kukkonen <jku@o-hand.com> + * Copyright 2007-2008 by Garmin Ltd. or its subsidiaries + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include <config.h> + +#include <string.h> + +#include "main.h" +#include "master.h" +#include "client.h" +#include "master-provider.h" + +#ifdef HAVE_NETWORK_MANAGER +#include "connectivity-networkmanager.h" +#else +#ifdef HAVE_CONIC +#include "connectivity-conic.h" +#else +#ifdef HAVE_CONNMAN +#include "connectivity-connman.h" +#endif +#endif +#endif + +enum { + OPTIONS_CHANGED, + LAST_SIGNAL +}; + +static guint32 signals[LAST_SIGNAL] = {0, }; + +G_DEFINE_TYPE (GcMaster, gc_master, G_TYPE_OBJECT); + +static GList *providers = NULL; + +static gboolean gc_iface_master_create (GcMaster *master, + const char **object_path, + GError **error); + +#include "gc-iface-master-glue.h" + +#define GEOCLUE_MASTER_PATH "/org/freedesktop/Geoclue/Master/client" +static gboolean +gc_iface_master_create (GcMaster *master, + const char **object_path, + GError **error) +{ + static guint32 serial = 0; + GcMasterClient *client; + char *path; + + path = g_strdup_printf ("%s%d", GEOCLUE_MASTER_PATH, serial++); + client = g_object_new (GC_TYPE_MASTER_CLIENT, NULL); + dbus_g_connection_register_g_object (master->connection, path, + G_OBJECT (client)); + + if (object_path) { + *object_path = path; + } + return TRUE; +} + +static void +gc_master_class_init (GcMasterClass *klass) +{ + dbus_g_object_type_install_info (gc_master_get_type (), + &dbus_glib_gc_iface_master_object_info); + + signals[OPTIONS_CHANGED] = g_signal_new ("options-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | + G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (GcMasterClass, options_changed), + NULL, NULL, + g_cclosure_marshal_VOID__BOXED, + G_TYPE_NONE, 1, + G_TYPE_HASH_TABLE); +} + +/* Load the provider details out of a keyfile */ +static void +gc_master_add_new_provider (GcMaster *master, + const char *filename) +{ + GcMasterProvider *provider; + + provider = gc_master_provider_new (filename, + master->connectivity); + + if (!provider) { + g_warning ("Loading from %s failed", filename); + return; + } + + providers = g_list_prepend (providers, provider); +} + +/* Scan a directory for .provider files */ +#define PROVIDER_EXTENSION ".provider" + +static void +gc_master_load_providers (GcMaster *master) +{ + GDir *dir; + GError *error = NULL; + const char *filename; + + dir = g_dir_open (GEOCLUE_PROVIDERS_DIR, 0, &error); + if (dir == NULL) { + g_warning ("Error opening %s: %s\n", GEOCLUE_PROVIDERS_DIR, + error->message); + g_error_free (error); + return; + } + + filename = g_dir_read_name (dir); + if (!filename) { + g_print ("No providers found in %s\n", dir); + } else { + g_print ("Found providers:\n"); + } + while (filename) { + char *fullname, *ext; + + g_print (" %s\n", filename); + ext = strrchr (filename, '.'); + if (ext == NULL || strcmp (ext, PROVIDER_EXTENSION) != 0) { + g_print (" - Ignored\n"); + filename = g_dir_read_name (dir); + continue; + } + + fullname = g_build_filename (GEOCLUE_PROVIDERS_DIR, + filename, NULL); + gc_master_add_new_provider (master, fullname); + g_free (fullname); + + filename = g_dir_read_name (dir); + } + + g_dir_close (dir); +} + +static void +gc_master_init (GcMaster *master) +{ + GError *error = NULL; + + + master->connection = dbus_g_bus_get (GEOCLUE_DBUS_BUS, &error); + if (master->connection == NULL) { + g_warning ("Could not get %s: %s", GEOCLUE_DBUS_BUS, + error->message); + g_error_free (error); + } + + master->connectivity = geoclue_connectivity_new (); + + gc_master_load_providers (master); +} + + +GList * +gc_master_get_providers (GcInterfaceFlags iface_type, + GeoclueAccuracyLevel min_accuracy, + gboolean can_update, + GeoclueResourceFlags allowed, + GError **error) +{ + GList *l, *p = NULL; + + if (providers == NULL) { + return NULL; + } + + for (l = providers; l; l = l->next) { + GcMasterProvider *provider = l->data; + + if (gc_master_provider_is_good (provider, + iface_type, + min_accuracy, + can_update, + allowed)) { + p = g_list_prepend (p, provider); + } + } + + return p; +} diff --git a/.pc/tizen.patch/src/org.freedesktop.Geoclue.gschema.xml b/.pc/tizen.patch/src/org.freedesktop.Geoclue.gschema.xml new file mode 100755 index 0000000..94ff65d --- /dev/null +++ b/.pc/tizen.patch/src/org.freedesktop.Geoclue.gschema.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<schemalist> + <schema path="/apps/geoclue/" id="org.freedesktop.Geoclue"> + <key type="u" name="gps-baudrate"> + <default>0</default> + <summary>The baud rate for the attached GPS device</summary> + <description>The baud rate for the attached GPS device.</description> + </key> + <key type="s" name="gps-device"> + <default>''</default> + <summary>The device node or Bluetooth address for the attached GPS device</summary> + <description>The device node or Bluetooth address for the attached GPS device.</description> + </key> + </schema> +</schemalist> diff --git a/.pc/tizen.patch/src/test-connectivity.c b/.pc/tizen.patch/src/test-connectivity.c new file mode 100755 index 0000000..c8b7cf6 --- /dev/null +++ b/.pc/tizen.patch/src/test-connectivity.c @@ -0,0 +1,97 @@ + +#include <connectivity.h> + +static void +print_ap (gpointer key, + gpointer value, + gpointer data) +{ + g_message ("\t%s : %d dBm", + key, + GPOINTER_TO_INT (value)); +} + +static void +print_aps (GeoclueConnectivity *conn) +{ + GHashTable *ht; + + ht = geoclue_connectivity_get_aps (conn); + if (ht == NULL) { + g_message ("No Access Points available"); + return; + } + g_message ("APs:"); + g_hash_table_foreach (ht, print_ap, NULL); +} + +static void +print_if_avail (GeoclueConnectivity *self, + GeoclueNetworkStatus status) +{ + char *router, *ap; + if (status != GEOCLUE_CONNECTIVITY_ONLINE) + return; + print_aps (self); + ap = geoclue_connectivity_get_ap_mac (self); + g_message ("AP is '%s'", ap ? ap : "Unavailable"); + g_free (ap); + + router = geoclue_connectivity_get_router_mac (self); + g_message ("Router is '%s'", router); + g_free (router); +} + +static void +status_changed_cb (GeoclueConnectivity *self, + GeoclueNetworkStatus status, + gpointer data) +{ + const char *str; + + switch (status) { + case GEOCLUE_CONNECTIVITY_UNKNOWN: + str = "GEOCLUE_CONNECTIVITY_UNKNOWN"; + break; + case GEOCLUE_CONNECTIVITY_OFFLINE: + str = "GEOCLUE_CONNECTIVITY_OFFLINE"; + break; + case GEOCLUE_CONNECTIVITY_ACQUIRING: + str = "GEOCLUE_CONNECTIVITY_ACQUIRING"; + break; + case GEOCLUE_CONNECTIVITY_ONLINE: + str = "GEOCLUE_CONNECTIVITY_ONLINE"; + break; + default: + g_assert_not_reached (); + } + + g_message ("Connectivity status switch to '%s'", str); + + print_if_avail (self, status); +} + +int main (int argc, char **argv) +{ + GMainLoop *mainloop; + GeoclueConnectivity *conn; + char *router; + + g_type_init (); + mainloop = g_main_loop_new (NULL, FALSE); + conn = geoclue_connectivity_new (); + + if (conn == NULL) { + router = geoclue_connectivity_get_router_mac (conn); + g_message ("Router MAC is detected as '%s'", router ? router : "empty"); + + return 1; + } + print_if_avail (conn, geoclue_connectivity_get_status (conn)); + g_signal_connect (conn, "status-changed", + G_CALLBACK (status_changed_cb), NULL); + + g_main_loop_run (mainloop); + + return 0; +} |