1 /* vim: set et ts=8 sw=8: */
2 /* where-am-i.c
3  *
4  * Copyright 2013 Red Hat, Inc.
5  *
6  * Geoclue is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free
8  * Software Foundation; either version 2 of the License, or (at your option)
9  * any later version.
10  *
11  * Geoclue is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with Geoclue; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * Author: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
21  */
22 
23 #include <config.h>
24 
25 #include <stdlib.h>
26 #include <locale.h>
27 #include <glib/gi18n.h>
28 #include <geoclue.h>
29 
30 /* Commandline options */
31 static gint timeout = 30; /* seconds */
32 static GClueAccuracyLevel accuracy_level = GCLUE_ACCURACY_LEVEL_EXACT;
33 static gint time_threshold;
34 
35 static GOptionEntry entries[] =
36 {
37         { "timeout",
38           't',
39           0,
40           G_OPTION_ARG_INT,
41           &timeout,
42           N_("Exit after T seconds. Default: 30"),
43           "T" },
44         { "time-threshold",
45           'i',
46           0,
47           G_OPTION_ARG_INT,
48           &time_threshold,
49           N_("Only report location update after T seconds. "
50              "Default: 0 (report new location without any delay)"),
51           "T" },
52         { "accuracy-level",
53           'a',
54           0,
55           G_OPTION_ARG_INT,
56           &accuracy_level,
57           N_("Request accuracy level A. "
58              "Country = 1, "
59              "City = 4, "
60              "Neighborhood = 5, "
61              "Street = 6, "
62              "Exact = 8."),
63           "A" },
64         { NULL }
65 };
66 
67 GClueSimple *simple = NULL;
68 GClueClient *client = NULL;
69 GMainLoop *main_loop;
70 
71 static gboolean
on_location_timeout(gpointer user_data)72 on_location_timeout (gpointer user_data)
73 {
74         g_clear_object (&client);
75         g_clear_object (&simple);
76         g_main_loop_quit (main_loop);
77 
78         return FALSE;
79 }
80 
81 static void
print_location(GClueSimple * simple)82 print_location (GClueSimple *simple)
83 {
84         GClueLocation *location;
85         gdouble altitude, speed, heading;
86         GVariant *timestamp;
87         GTimeVal tv = { 0 };
88         const char *desc;
89 
90         location = gclue_simple_get_location (simple);
91         g_print ("\nNew location:\n");
92         g_print ("Latitude:    %f°\nLongitude:   %f°\nAccuracy:    %f meters\n",
93                  gclue_location_get_latitude (location),
94                  gclue_location_get_longitude (location),
95                  gclue_location_get_accuracy (location));
96 
97         altitude = gclue_location_get_altitude (location);
98         if (altitude != -G_MAXDOUBLE)
99                 g_print ("Altitude:    %f meters\n", altitude);
100         speed = gclue_location_get_speed (location);
101         if (speed >= 0)
102                 g_print ("Speed:       %f meters/second\n", speed);
103         heading = gclue_location_get_heading (location);
104         if (heading >= 0)
105                 g_print ("Heading:     %f°\n", heading);
106 
107         desc = gclue_location_get_description (location);
108         if (strlen (desc) > 0)
109                 g_print ("Description: %s\n", desc);
110 
111         timestamp = gclue_location_get_timestamp (location);
112         if (timestamp) {
113                 GDateTime *date_time;
114                 gchar *str;
115 
116                 g_variant_get (timestamp, "(tt)", &tv.tv_sec, &tv.tv_usec);
117 
118                 date_time = g_date_time_new_from_timeval_local (&tv);
119                 str = g_date_time_format
120                       (date_time,
121                        "%c (%s seconds since the Epoch)");
122                 g_date_time_unref (date_time);
123 
124                 g_print ("Timestamp:   %s\n", str);
125                 g_free (str);
126         }
127 }
128 
129 static void
on_client_active_notify(GClueClient * client,GParamSpec * pspec,gpointer user_data)130 on_client_active_notify (GClueClient *client,
131                          GParamSpec *pspec,
132                          gpointer    user_data)
133 {
134         if (gclue_client_get_active (client))
135                 return;
136 
137         g_print ("Geolocation disabled. Quitting..\n");
138         on_location_timeout (NULL);
139 }
140 
141 static void
on_simple_ready(GObject * source_object,GAsyncResult * res,gpointer user_data)142 on_simple_ready (GObject      *source_object,
143                  GAsyncResult *res,
144                  gpointer      user_data)
145 {
146         GError *error = NULL;
147 
148         simple = gclue_simple_new_finish (res, &error);
149         if (error != NULL) {
150             g_critical ("Failed to connect to GeoClue2 service: %s", error->message);
151 
152             exit (-1);
153         }
154         client = gclue_simple_get_client (simple);
155         g_object_ref (client);
156         g_print ("Client object: %s\n",
157                  g_dbus_proxy_get_object_path (G_DBUS_PROXY (client)));
158         if (time_threshold > 0) {
159                 gclue_client_set_time_threshold (client, time_threshold);
160         }
161 
162         print_location (simple);
163 
164         g_signal_connect (simple,
165                           "notify::location",
166                           G_CALLBACK (print_location),
167                           NULL);
168         g_signal_connect (client,
169                           "notify::active",
170                           G_CALLBACK (on_client_active_notify),
171                           NULL);
172 }
173 
174 gint
main(gint argc,gchar * argv[])175 main (gint argc, gchar *argv[])
176 {
177         GOptionContext *context;
178         GError *error = NULL;
179 
180         setlocale (LC_ALL, "");
181         textdomain (GETTEXT_PACKAGE);
182         bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
183         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
184 
185         context = g_option_context_new ("- Where am I?");
186         g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
187         if (!g_option_context_parse (context, &argc, &argv, &error)) {
188                 g_critical ("option parsing failed: %s\n", error->message);
189                 exit (-1);
190         }
191         g_option_context_free (context);
192 
193         g_timeout_add_seconds (timeout, on_location_timeout, NULL);
194 
195         gclue_simple_new ("geoclue-where-am-i",
196                           accuracy_level,
197                           NULL,
198                           on_simple_ready,
199                           NULL);
200 
201         main_loop = g_main_loop_new (NULL, FALSE);
202         g_main_loop_run (main_loop);
203 
204         return EXIT_SUCCESS;
205 }
206