diff options
author | Zeeshan Ali (Khattak) <zeeshanak@gnome.org> | 2013-09-20 23:07:25 +0300 |
---|---|---|
committer | Zeeshan Ali (Khattak) <zeeshanak@gnome.org> | 2013-09-26 16:48:24 +0300 |
commit | 73b631c67d6689f8cf4b46b49b163cf94bd7ab4f (patch) | |
tree | 5c7825f6274d1ead5efd0d1853b143ac6538c8fb /demo | |
parent | 34fe5033792f866bb1a197d3fece4e50a038d8be (diff) | |
download | geoclue-73b631c67d6689f8cf4b46b49b163cf94bd7ab4f.tar.gz |
Add a demo user-authorization agent
It uses libnotify to ask user to authorize the app for access to geolocation
info.
Diffstat (limited to 'demo')
-rw-r--r-- | demo/Makefile.am | 30 | ||||
-rw-r--r-- | demo/agent.c | 137 | ||||
-rw-r--r-- | demo/gclue-service-agent.c | 374 | ||||
-rw-r--r-- | demo/gclue-service-agent.h | 67 |
4 files changed, 607 insertions, 1 deletions
diff --git a/demo/Makefile.am b/demo/Makefile.am index b3d15fa..4f0ef38 100644 --- a/demo/Makefile.am +++ b/demo/Makefile.am @@ -1,7 +1,35 @@ -noinst_PROGRAMS = where-am-i +noinst_PROGRAMS = where-am-i agent where_am_i_SOURCES = where-am-i.c where_am_i_CFLAGS = $(GEOCLUE_CFLAGS) \ $(WARN_CFLAGS) \ -DLOCALEDIR="\"$(datadir)/locale\"" where_am_i_LDADD = $(GEOCLUE_LIBS) + +if BUILD_DEMO_AGENT + +interface_data = $(top_builddir)/src/agent/geoclue-agent-interface.xml +dbus_built_sources = geoclue-agent-interface.c geoclue-agent-interface.h +geoclue-agent-interface.c: geoclue-agent-interface.h +geoclue-agent-interface.h: Makefile.am $(interface_data) + gdbus-codegen \ + --interface-prefix org.freedesktop.GeoClue2. \ + --c-namespace GClue \ + --generate-c-code geoclue-agent-interface \ + $(interface_data) + +BUILT_SOURCES = $(dbus_built_sources) \ + $(NULL) + +agent_SOURCES = $(BUILT_SOURCES) \ + gclue-service-agent.h \ + gclue-service-agent.c \ + agent.c \ + $(NULL) +agent_CFLAGS = $(DEMO_AGENT_CFLAGS) \ + $(WARN_CFLAGS) \ + -DLOCALEDIR="\"$(datadir)/locale\"" \ + -DABS_SRCDIR=\""$(abs_srcdir)"\" +agent_LDADD = $(DEMO_AGENT_LIBS) + +endif # BUILD_DEMO_AGENT diff --git a/demo/agent.c b/demo/agent.c new file mode 100644 index 0000000..d0d7ee2 --- /dev/null +++ b/demo/agent.c @@ -0,0 +1,137 @@ +/* vim: set et ts=8 sw=8: */ +/* agent.c + * + * Copyright (C) 2013 Red Hat, Inc. + * + * Geoclue is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Geoclue 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with Geoclue; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + */ +#include <config.h> + +#include <gio/gio.h> +#include <locale.h> +#include <glib/gi18n.h> +#include <stdlib.h> +#include <libnotify/notify.h> + +#include "gclue-service-agent.h" + +/* Commandline options */ +static gboolean version; + +static GOptionEntry entries[] = +{ + { "version", + 0, + 0, + G_OPTION_ARG_NONE, + &version, + N_("Display version number"), + NULL }, + { NULL } +}; + +GDBusConnection *connection; +GMainLoop *main_loop; +GClueServiceAgent *agent = NULL; + +static void +on_service_agent_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + + agent = gclue_service_agent_new_finish (res, &error); + if (agent == NULL) { + g_critical ("Failed to launch agent service: %s", error->message); + g_error_free (error); + + exit (-3); + } +} + +static void +on_get_bus_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + + connection = g_bus_get_finish (res, &error); + if (connection == NULL) { + g_critical ("Failed to get connection to system bus: %s", + error->message); + g_error_free (error); + + exit (-2); + } + + gclue_service_agent_new_async (connection, + NULL, + on_service_agent_ready, + NULL); +} + +#define ABS_PATH ABS_SRCDIR "/agent" + +int +main (int argc, char **argv) +{ + GError *error = NULL; + GOptionContext *context; + + setlocale (LC_ALL, ""); + + textdomain (GETTEXT_PACKAGE); + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + g_set_application_name ("GeoClue Agent"); + + notify_init (_("GeoClue")); + + context = g_option_context_new ("- Geoclue Agent service"); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + g_critical ("option parsing failed: %s\n", error->message); + exit (-1); + } + + if (version) { + g_print ("%s\n", PACKAGE_VERSION); + exit (0); + } + + if (g_strcmp0 (ABS_PATH, argv[0]) != 0) { + g_print ("Must be run with absolute path to binary: %s\n", + ABS_PATH); + exit (-4); + } + + g_bus_get (G_BUS_TYPE_SYSTEM, + NULL, + on_get_bus_ready, + NULL); + + main_loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (main_loop); + + if (agent != NULL); + g_object_unref (agent); + g_main_loop_unref (main_loop); + + return 0; +} diff --git a/demo/gclue-service-agent.c b/demo/gclue-service-agent.c new file mode 100644 index 0000000..151032d --- /dev/null +++ b/demo/gclue-service-agent.c @@ -0,0 +1,374 @@ +/* vim: set et ts=8 sw=8: */ +/* gclue-service-agent.c + * + * Copyright (C) 2013 Red Hat, Inc. + * + * Geoclue is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Geoclue 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with Geoclue; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + */ + +#include <glib/gi18n.h> +#include <libnotify/notify.h> + +#include "gclue-service-agent.h" + +static void +gclue_service_agent_agent_iface_init (GClueAgentIface *iface); +static void +gclue_service_agent_async_initable_init (GAsyncInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (GClueServiceAgent, + gclue_service_agent, + GCLUE_TYPE_AGENT_SKELETON, + G_IMPLEMENT_INTERFACE (GCLUE_TYPE_AGENT, + gclue_service_agent_agent_iface_init) + G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, + gclue_service_agent_async_initable_init)) + +struct _GClueServiceAgentPrivate +{ + GDBusConnection *connection; +}; + +enum +{ + PROP_0, + PROP_CONNECTION, + LAST_PROP +}; + +static GParamSpec *gParamSpecs[LAST_PROP]; + +static void +gclue_service_agent_finalize (GObject *object) +{ + GClueServiceAgentPrivate *priv = GCLUE_SERVICE_AGENT (object)->priv; + + g_clear_object (&priv->connection); + + /* Chain up to the parent class */ + G_OBJECT_CLASS (gclue_service_agent_parent_class)->finalize (object); +} + +static void +gclue_service_agent_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GClueServiceAgent *agent = GCLUE_SERVICE_AGENT (object); + + switch (prop_id) { + case PROP_CONNECTION: + g_value_set_object (value, agent->priv->connection); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gclue_service_agent_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GClueServiceAgent *agent = GCLUE_SERVICE_AGENT (object); + + switch (prop_id) { + case PROP_CONNECTION: + agent->priv->connection = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +gclue_service_agent_class_init (GClueServiceAgentClass *klass) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (klass); + object_class->finalize = gclue_service_agent_finalize; + object_class->get_property = gclue_service_agent_get_property; + object_class->set_property = gclue_service_agent_set_property; + + g_type_class_add_private (object_class, sizeof (GClueServiceAgentPrivate)); + + gParamSpecs[PROP_CONNECTION] = g_param_spec_object ("connection", + "Connection", + "DBus Connection", + G_TYPE_DBUS_CONNECTION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property (object_class, + PROP_CONNECTION, + gParamSpecs[PROP_CONNECTION]); +} + +static void +gclue_service_agent_init (GClueServiceAgent *agent) +{ + agent->priv = G_TYPE_INSTANCE_GET_PRIVATE (agent, + GCLUE_TYPE_SERVICE_AGENT, + GClueServiceAgentPrivate); +} + +static void +on_add_agent_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + GVariant *results; + GError *error = NULL; + + results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), + res, + &error); + if (results == NULL) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} + +static void +on_manager_proxy_ready (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GTask *task = G_TASK (user_data); + GDBusProxy *proxy; + GError *error = NULL; + + proxy = g_dbus_proxy_new_for_bus_finish (res, &error); + if (proxy == NULL) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + g_dbus_proxy_call (proxy, + "AddAgent", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + g_task_get_cancellable (task), + on_add_agent_ready, + task); +} + +static void +gclue_service_agent_init_async (GAsyncInitable *initable, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + char *path; + GError *error = NULL; + + task = g_task_new (initable, cancellable, callback, user_data); + + path = g_strdup_printf ("/org/freedesktop/GeoClue2/Agent/%u", getuid ()); + if (!g_dbus_interface_skeleton_export + (G_DBUS_INTERFACE_SKELETON (initable), + GCLUE_SERVICE_AGENT (initable)->priv->connection, + path, + &error)) { + g_task_return_error (task, error); + g_object_unref (task); + g_free (path); + return; + } + g_free (path); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.freedesktop.GeoClue2", + "/org/freedesktop/GeoClue2/Manager", + "org.freedesktop.GeoClue2.Manager", + cancellable, + on_manager_proxy_ready, + task); +} + +static gboolean +gclue_service_agent_init_finish (GAsyncInitable *initable, + GAsyncResult *result, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (result), error); +} + +typedef struct +{ + GClueAgent *agent; + GDBusMethodInvocation *invocation; + NotifyNotification *notification; + char *bus_name; + char *title; + gboolean authorized; +} NotificationData; + +static void +notification_data_free (NotificationData *data) +{ + g_free (data->bus_name); + g_free (data->title); + g_object_unref (data->notification); + g_slice_free (NotificationData, data); +} + +#define ACTION_YES "yes" +#define ACTION_NO "NO" + +static void +on_notify_action (NotifyNotification *notification, + char *action, + gpointer user_data) +{ + NotificationData *data = (NotificationData *) user_data; + GError *error = NULL; + + data->authorized = (g_strcmp0 (action, ACTION_YES) == 0); + + if (!notify_notification_close (notification, &error)) { + g_dbus_method_invocation_take_error (data->invocation, error); + notification_data_free (data); + } +} + +static void +on_notify_closed (NotifyNotification *notification, + gpointer user_data) +{ + NotificationData *data = (NotificationData *) user_data; + + if (data->authorized) + g_debug ("Authorized %s (%s)", data->title, data->bus_name); + else + g_debug ("%s (%s) not authorized", data->title, data->bus_name); + gclue_agent_complete_authorize_app (data->agent, + data->invocation, + data->authorized); + notification_data_free (data); +} + +static gboolean +gclue_service_agent_handle_authorize_app (GClueAgent *agent, + GDBusMethodInvocation *invocation, + const char *bus_name, + const char *title) +{ + NotifyNotification *notification; + NotificationData *data; + GError *error = NULL; + char *msg; + + msg = g_strdup_printf (_("Allow %s to access your location information?"), + title); + notification = notify_notification_new (_("Geolocation"), msg, "dialog-question"); + g_free (msg); + + data = g_slice_new0 (NotificationData); + data->invocation = invocation; + data->notification = notification; + data->bus_name = g_strdup (bus_name); + data->title = g_strdup (title); + + notify_notification_add_action (notification, + ACTION_YES, + _("Yes"), + on_notify_action, + data, + NULL); + notify_notification_add_action (notification, + ACTION_NO, + _("No"), + on_notify_action, + data, + NULL); + g_signal_connect (notification, + "closed", + G_CALLBACK (on_notify_closed), + data); + + if (!notify_notification_show (notification, &error)) { + g_dbus_method_invocation_take_error (invocation, error); + notification_data_free (data); + + return TRUE; + } + + return TRUE; +} + +static void +gclue_service_agent_agent_iface_init (GClueAgentIface *iface) +{ + iface->handle_authorize_app = gclue_service_agent_handle_authorize_app; +} + +static void +gclue_service_agent_async_initable_init (GAsyncInitableIface *iface) +{ + iface->init_async = gclue_service_agent_init_async; + iface->init_finish = gclue_service_agent_init_finish; +} + +void +gclue_service_agent_new_async (GDBusConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_async_initable_new_async (GCLUE_TYPE_SERVICE_AGENT, + G_PRIORITY_DEFAULT, + cancellable, + callback, + user_data, + "connection", connection, + NULL); +} + +GClueServiceAgent * +gclue_service_agent_new_finish (GAsyncResult *res, + GError **error) +{ + GObject *object; + GObject *source_object; + + source_object = g_async_result_get_source_object (res); + object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), + res, + error); + g_object_unref (source_object); + if (object != NULL) + return GCLUE_SERVICE_AGENT (object); + else + return NULL; +} diff --git a/demo/gclue-service-agent.h b/demo/gclue-service-agent.h new file mode 100644 index 0000000..5849c26 --- /dev/null +++ b/demo/gclue-service-agent.h @@ -0,0 +1,67 @@ +/* vim: set et ts=8 sw=8: */ +/* gclue-service-agent.h + * + * Copyright (C) 2013 Red Hat, Inc. + * + * Geoclue is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * Geoclue 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 General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along + * with Geoclue; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org> + */ + +#ifndef GCLUE_SERVICE_AGENT_H +#define GCLUE_SERVICE_AGENT_H + +#include <glib-object.h> +#include "geoclue-agent-interface.h" + +G_BEGIN_DECLS + +#define GCLUE_TYPE_SERVICE_AGENT (gclue_service_agent_get_type()) +#define GCLUE_SERVICE_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCLUE_TYPE_SERVICE_AGENT, GClueServiceAgent)) +#define GCLUE_SERVICE_AGENT_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCLUE_TYPE_SERVICE_AGENT, GClueServiceAgent const)) +#define GCLUE_SERVICE_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCLUE_TYPE_SERVICE_AGENT, GClueServiceAgentClass)) +#define GCLUE_IS_SERVICE_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCLUE_TYPE_SERVICE_AGENT)) +#define GCLUE_IS_SERVICE_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCLUE_TYPE_SERVICE_AGENT)) +#define GCLUE_SERVICE_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCLUE_TYPE_SERVICE_AGENT, GClueServiceAgentClass)) + +typedef struct _GClueServiceAgent GClueServiceAgent; +typedef struct _GClueServiceAgentClass GClueServiceAgentClass; +typedef struct _GClueServiceAgentPrivate GClueServiceAgentPrivate; + +struct _GClueServiceAgent +{ + GClueAgentSkeleton parent; + + /*< private >*/ + GClueServiceAgentPrivate *priv; +}; + +struct _GClueServiceAgentClass +{ + GClueAgentSkeletonClass parent_class; +}; + +GType gclue_service_agent_get_type (void) G_GNUC_CONST; +void gclue_service_agent_new_async (GDBusConnection *connection, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +GClueServiceAgent * gclue_service_agent_new_finish (GAsyncResult *res, + GError **error); + + +G_END_DECLS + +#endif /* GCLUE_SERVICE_AGENT_H */ |