]> git.0d.be Git - empathy.git/blob - libempathy-gtk/empathy-location-manager.c
Merge branch 'sasl'
[empathy.git] / libempathy-gtk / empathy-location-manager.c
1 /*
2  * Copyright (C) 2009 Collabora Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301  USA
18  *
19  * Authors: Pierre-Luc Beaudoin <pierre-luc.beaudoin@collabora.co.uk>
20  */
21
22 #include "config.h"
23
24 #include <string.h>
25 #include <time.h>
26
27 #include <glib/gi18n.h>
28
29 #include <telepathy-glib/account-manager.h>
30 #include <telepathy-glib/util.h>
31
32 #include <geoclue/geoclue-master.h>
33
34 #include <extensions/extensions.h>
35
36 #include "empathy-location-manager.h"
37
38 #include "libempathy/empathy-enum-types.h"
39 #include "libempathy/empathy-gsettings.h"
40 #include "libempathy/empathy-location.h"
41 #include "libempathy/empathy-utils.h"
42
43 #define DEBUG_FLAG EMPATHY_DEBUG_LOCATION
44 #include "libempathy/empathy-debug.h"
45
46 /* Seconds before updating the location */
47 #define TIMEOUT 10
48 static EmpathyLocationManager *location_manager = NULL;
49
50 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLocationManager)
51 typedef struct {
52     gboolean geoclue_is_setup;
53     /* Contains the location to be sent to accounts.  Geoclue is used
54      * to populate it.  This HashTable uses Telepathy's style (string,
55      * GValue). Keys are defined in empathy-location.h
56      */
57     GHashTable *location;
58
59     GSettings *gsettings_loc;
60
61     GeoclueResourceFlags resources;
62     GeoclueMasterClient *gc_client;
63     GeocluePosition *gc_position;
64     GeoclueAddress *gc_address;
65
66     gboolean reduce_accuracy;
67     TpAccountManager *account_manager;
68
69     /* The idle id for publish_on_idle func */
70     guint timeout_id;
71 } EmpathyLocationManagerPriv;
72
73 G_DEFINE_TYPE (EmpathyLocationManager, empathy_location_manager, G_TYPE_OBJECT);
74
75 static GObject *
76 location_manager_constructor (GType type,
77     guint n_construct_params,
78     GObjectConstructParam *construct_params)
79 {
80   GObject *retval;
81
82   if (location_manager == NULL)
83     {
84       retval = G_OBJECT_CLASS (empathy_location_manager_parent_class)->constructor
85           (type, n_construct_params, construct_params);
86
87       location_manager = EMPATHY_LOCATION_MANAGER (retval);
88       g_object_add_weak_pointer (retval, (gpointer) &location_manager);
89     }
90   else
91     {
92       retval = g_object_ref (location_manager);
93     }
94
95   return retval;
96 }
97
98 static void
99 location_manager_dispose (GObject *object)
100 {
101   EmpathyLocationManagerPriv *priv = GET_PRIV (object);
102   void (*dispose) (GObject *) =
103     G_OBJECT_CLASS (empathy_location_manager_parent_class)->dispose;
104
105   if (priv->account_manager != NULL)
106   {
107     g_object_unref (priv->account_manager);
108     priv->account_manager = NULL;
109   }
110
111   if (priv->gsettings_loc != NULL)
112   {
113     g_object_unref (priv->gsettings_loc);
114     priv->gsettings_loc = NULL;
115   }
116
117   if (priv->gc_client != NULL)
118   {
119     g_object_unref (priv->gc_client);
120     priv->gc_client = NULL;
121   }
122
123   if (priv->gc_position != NULL)
124   {
125     g_object_unref (priv->gc_position);
126     priv->gc_position = NULL;
127   }
128
129   if (priv->gc_address != NULL)
130   {
131     g_object_unref (priv->gc_address);
132     priv->gc_address = NULL;
133   }
134
135   if (priv->location != NULL)
136   {
137     g_hash_table_unref (priv->location);
138     priv->location = NULL;
139   }
140
141   if (dispose != NULL)
142     dispose (object);
143 }
144
145 static void
146 location_manager_get_property (GObject *object,
147                       guint param_id,
148                       GValue *value,
149                       GParamSpec *pspec)
150 {
151   /*EmpathyLocationManagerPriv *priv = GET_PRIV (object); */
152
153   switch (param_id)
154     {
155       default:
156         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
157         break;
158     };
159 }
160
161 static void
162 location_manager_set_property (GObject *object,
163                       guint param_id,
164                       const GValue *value,
165                       GParamSpec *pspec)
166 {
167   /* EmpathyLocationManagerPriv *priv = GET_PRIV (object); */
168
169   switch (param_id)
170     {
171       default:
172         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
173         break;
174     };
175 }
176
177 static void
178 empathy_location_manager_class_init (EmpathyLocationManagerClass *class)
179 {
180   GObjectClass *object_class;
181
182   object_class = G_OBJECT_CLASS (class);
183
184   object_class->constructor = location_manager_constructor;
185   object_class->dispose = location_manager_dispose;
186   object_class->get_property = location_manager_get_property;
187   object_class->set_property = location_manager_set_property;
188
189   g_type_class_add_private (object_class, sizeof (EmpathyLocationManagerPriv));
190 }
191
192 static void
193 publish_location_cb (TpConnection *connection,
194                      const GError *error,
195                      gpointer user_data,
196                      GObject *weak_object)
197 {
198   if (error != NULL)
199       DEBUG ("Error setting location: %s", error->message);
200 }
201
202 static void
203 publish_location (EmpathyLocationManager *self,
204     TpConnection *conn,
205     gboolean force_publication)
206 {
207   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
208   guint connection_status = -1;
209
210   if (!conn)
211     return;
212
213   if (!force_publication)
214     {
215       if (!g_settings_get_boolean (priv->gsettings_loc,
216             EMPATHY_PREFS_LOCATION_PUBLISH))
217         return;
218     }
219
220   connection_status = tp_connection_get_status (conn, NULL);
221
222   if (connection_status != TP_CONNECTION_STATUS_CONNECTED)
223     return;
224
225   DEBUG ("Publishing %s location to connection %p",
226       (g_hash_table_size (priv->location) == 0 ? "empty" : ""),
227       conn);
228
229   tp_cli_connection_interface_location_call_set_location (conn, -1,
230       priv->location, publish_location_cb, NULL, NULL, G_OBJECT (self));
231 }
232
233 typedef struct
234 {
235   EmpathyLocationManager *self;
236   gboolean force_publication;
237 } PublishToAllData;
238
239 static void
240 publish_to_all_am_prepared_cb (GObject *source_object,
241     GAsyncResult *result,
242     gpointer user_data)
243 {
244   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
245   PublishToAllData *data = user_data;
246   GList *accounts, *l;
247   GError *error = NULL;
248
249   if (!tp_account_manager_prepare_finish (manager, result, &error))
250     {
251       DEBUG ("Failed to prepare account manager: %s", error->message);
252       g_error_free (error);
253       goto out;
254     }
255
256   accounts = tp_account_manager_get_valid_accounts (manager);
257   for (l = accounts; l; l = l->next)
258     {
259       TpConnection *conn = tp_account_get_connection (TP_ACCOUNT (l->data));
260
261       if (conn != NULL)
262         publish_location (data->self, conn, data->force_publication);
263     }
264   g_list_free (accounts);
265
266 out:
267   g_object_unref (data->self);
268   g_slice_free (PublishToAllData, data);
269 }
270
271 static void
272 publish_to_all_connections (EmpathyLocationManager *self,
273     gboolean force_publication)
274 {
275   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
276   PublishToAllData *data;
277
278   data = g_slice_new0 (PublishToAllData);
279   data->self = g_object_ref (self);
280   data->force_publication = force_publication;
281
282   tp_account_manager_prepare_async (priv->account_manager, NULL,
283       publish_to_all_am_prepared_cb, data);
284 }
285
286 static gboolean
287 publish_on_idle (gpointer user_data)
288 {
289   EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
290   EmpathyLocationManagerPriv *priv = GET_PRIV (manager);
291
292   priv->timeout_id = 0;
293   publish_to_all_connections (manager, TRUE);
294   return FALSE;
295 }
296
297 static void
298 new_connection_cb (TpAccount *account,
299     guint old_status,
300     guint new_status,
301     guint reason,
302     gchar *dbus_error_name,
303     GHashTable *details,
304     gpointer *self)
305 {
306   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
307   TpConnection *conn;
308
309   conn = tp_account_get_connection (account);
310
311   DEBUG ("New connection %p", conn);
312
313   /* Don't publish if it is already planned (ie startup) */
314   if (priv->timeout_id == 0)
315     {
316       publish_location (EMPATHY_LOCATION_MANAGER (self), conn,
317           FALSE);
318     }
319 }
320
321 static void
322 update_timestamp (EmpathyLocationManager *self)
323 {
324   EmpathyLocationManagerPriv *priv= GET_PRIV (self);
325   GValue *new_value;
326   gint64 stamp64;
327   time_t timestamp;
328
329   timestamp = time (NULL);
330   stamp64 = (gint64) timestamp;
331   new_value = tp_g_value_slice_new_int64 (stamp64);
332   g_hash_table_insert (priv->location, g_strdup (EMPATHY_LOCATION_TIMESTAMP),
333       new_value);
334   DEBUG ("\t - Timestamp: %" G_GINT64_FORMAT, stamp64);
335 }
336
337 static void
338 address_changed_cb (GeoclueAddress *address,
339                     int timestamp,
340                     GHashTable *details,
341                     GeoclueAccuracy *accuracy,
342                     gpointer self)
343 {
344   GeoclueAccuracyLevel level;
345   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
346   GHashTableIter iter;
347   gpointer key, value;
348
349   geoclue_accuracy_get_details (accuracy, &level, NULL, NULL);
350   DEBUG ("New address (accuracy level %d):", level);
351   /* FIXME: Publish accuracy level also considering the position's */
352
353   g_hash_table_remove (priv->location, EMPATHY_LOCATION_STREET);
354   g_hash_table_remove (priv->location, EMPATHY_LOCATION_AREA);
355   g_hash_table_remove (priv->location, EMPATHY_LOCATION_REGION);
356   g_hash_table_remove (priv->location, EMPATHY_LOCATION_COUNTRY);
357   g_hash_table_remove (priv->location, EMPATHY_LOCATION_COUNTRY_CODE);
358   g_hash_table_remove (priv->location, EMPATHY_LOCATION_POSTAL_CODE);
359
360   if (g_hash_table_size (details) == 0)
361     {
362       DEBUG ("\t - (Empty)");
363       return;
364     }
365
366   g_hash_table_iter_init (&iter, details);
367   while (g_hash_table_iter_next (&iter, &key, &value))
368     {
369       GValue *new_value;
370       /* Discard street information if reduced accuracy is on */
371       if (priv->reduce_accuracy &&
372           !tp_strdiff (key, EMPATHY_LOCATION_STREET))
373         continue;
374
375       new_value = tp_g_value_slice_new_string (value);
376       g_hash_table_insert (priv->location, g_strdup (key), new_value);
377
378       DEBUG ("\t - %s: %s", (gchar *) key, (gchar *) value);
379     }
380
381   update_timestamp (self);
382   if (priv->timeout_id == 0)
383     priv->timeout_id = g_timeout_add_seconds (TIMEOUT, publish_on_idle, self);
384 }
385
386 static void
387 initial_address_cb (GeoclueAddress *address,
388                     int timestamp,
389                     GHashTable *details,
390                     GeoclueAccuracy *accuracy,
391                     GError *error,
392                     gpointer self)
393 {
394   if (error)
395     {
396       DEBUG ("Error: %s", error->message);
397       g_error_free (error);
398     }
399   else
400     {
401       address_changed_cb (address, timestamp, details, accuracy, self);
402     }
403 }
404
405 static void
406 position_changed_cb (GeocluePosition *position,
407                      GeocluePositionFields fields,
408                      int timestamp,
409                      double latitude,
410                      double longitude,
411                      double altitude,
412                      GeoclueAccuracy *accuracy,
413                      gpointer self)
414 {
415   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
416   GeoclueAccuracyLevel level;
417   gdouble mean, horizontal, vertical;
418   GValue *new_value;
419
420
421   geoclue_accuracy_get_details (accuracy, &level, &horizontal, &vertical);
422   DEBUG ("New position (accuracy level %d)", level);
423   if (level == GEOCLUE_ACCURACY_LEVEL_NONE)
424     return;
425
426   if (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)
427     {
428
429       if (priv->reduce_accuracy)
430         /* Truncate at 1 decimal place */
431         longitude = ((int) (longitude * 10)) / 10.0;
432
433       new_value = tp_g_value_slice_new_double (longitude);
434       g_hash_table_insert (priv->location, g_strdup (EMPATHY_LOCATION_LON),
435           new_value);
436       DEBUG ("\t - Longitude: %f", longitude);
437     }
438   else
439     {
440       g_hash_table_remove (priv->location, EMPATHY_LOCATION_LON);
441     }
442
443   if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE)
444     {
445       if (priv->reduce_accuracy)
446         /* Truncate at 1 decimal place */
447         latitude = ((int) (latitude * 10)) / 10.0;
448
449       new_value = tp_g_value_slice_new_double (latitude);
450       g_hash_table_replace (priv->location, g_strdup (EMPATHY_LOCATION_LAT),
451           new_value);
452       DEBUG ("\t - Latitude: %f", latitude);
453     }
454   else
455     {
456       g_hash_table_remove (priv->location, EMPATHY_LOCATION_LAT);
457     }
458
459   if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE)
460     {
461       new_value = tp_g_value_slice_new_double (altitude);
462       g_hash_table_replace (priv->location, g_strdup (EMPATHY_LOCATION_ALT),
463           new_value);
464       DEBUG ("\t - Altitude: %f", altitude);
465     }
466   else
467     {
468       g_hash_table_remove (priv->location, EMPATHY_LOCATION_ALT);
469     }
470
471   if (level == GEOCLUE_ACCURACY_LEVEL_DETAILED)
472     {
473       mean = (horizontal + vertical) / 2.0;
474       new_value = tp_g_value_slice_new_double (mean);
475       g_hash_table_replace (priv->location,
476           g_strdup (EMPATHY_LOCATION_ACCURACY), new_value);
477       DEBUG ("\t - Accuracy: %f", mean);
478     }
479   else
480     {
481       g_hash_table_remove (priv->location, EMPATHY_LOCATION_ACCURACY);
482     }
483
484   update_timestamp (self);
485   if (priv->timeout_id == 0)
486     priv->timeout_id = g_timeout_add_seconds (TIMEOUT, publish_on_idle, self);
487 }
488
489 static void
490 initial_position_cb (GeocluePosition *position,
491                      GeocluePositionFields fields,
492                      int timestamp,
493                      double latitude,
494                      double longitude,
495                      double altitude,
496                      GeoclueAccuracy *accuracy,
497                      GError *error,
498                      gpointer self)
499 {
500   if (error)
501     {
502       DEBUG ("Error: %s", error->message);
503       g_error_free (error);
504     }
505   else
506     {
507       position_changed_cb (position, fields, timestamp, latitude, longitude,
508           altitude, accuracy, self);
509     }
510 }
511
512 static gboolean
513 set_requirements (EmpathyLocationManager *self)
514 {
515   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
516   GError *error = NULL;
517
518   if (!geoclue_master_client_set_requirements (priv->gc_client,
519           GEOCLUE_ACCURACY_LEVEL_COUNTRY, 0, FALSE, priv->resources,
520           &error))
521     {
522       DEBUG ("set_requirements failed: %s", error->message);
523       g_error_free (error);
524       return FALSE;
525     }
526
527   return TRUE;
528 }
529
530 static void
531 update_resources (EmpathyLocationManager *self)
532 {
533   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
534
535   DEBUG ("Updating resources %d", priv->resources);
536
537   if (!priv->geoclue_is_setup)
538     return;
539
540   /* As per Geoclue bug #15126, using NONE results in no address
541    * being found as geoclue-manual report an empty address with
542    * accuracy = NONE */
543   if (!set_requirements (self))
544     return;
545
546   geoclue_address_get_address_async (priv->gc_address,
547       initial_address_cb, self);
548   geoclue_position_get_position_async (priv->gc_position,
549       initial_position_cb, self);
550 }
551
552 static void
553 setup_geoclue (EmpathyLocationManager *self)
554 {
555   EmpathyLocationManagerPriv *priv = GET_PRIV (self);
556
557   GeoclueMaster *master;
558   GError *error = NULL;
559
560   DEBUG ("Setting up Geoclue");
561   master = geoclue_master_get_default ();
562   priv->gc_client = geoclue_master_create_client (master, NULL, &error);
563   g_object_unref (master);
564
565   if (priv->gc_client == NULL)
566     {
567       DEBUG ("Failed to GeoclueMasterClient: %s", error->message);
568       g_error_free (error);
569       return;
570     }
571
572   if (!set_requirements (self))
573     return;
574
575   /* Get updated when the position is changes */
576   priv->gc_position = geoclue_master_client_create_position (
577       priv->gc_client, &error);
578   if (priv->gc_position == NULL)
579     {
580       DEBUG ("Failed to create GeocluePosition: %s", error->message);
581       g_error_free (error);
582       return;
583     }
584
585   g_signal_connect (G_OBJECT (priv->gc_position), "position-changed",
586       G_CALLBACK (position_changed_cb), self);
587
588   /* Get updated when the address changes */
589   priv->gc_address = geoclue_master_client_create_address (
590       priv->gc_client, &error);
591   if (priv->gc_address == NULL)
592     {
593       DEBUG ("Failed to create GeoclueAddress: %s", error->message);
594       g_error_free (error);
595       return;
596     }
597
598   g_signal_connect (G_OBJECT (priv->gc_address), "address-changed",
599       G_CALLBACK (address_changed_cb), self);
600
601   priv->geoclue_is_setup = TRUE;
602 }
603
604 static void
605 publish_cb (GSettings *gsettings_loc,
606             const gchar *key,
607             gpointer user_data)
608 {
609   EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
610   EmpathyLocationManagerPriv *priv = GET_PRIV (manager);
611
612   DEBUG ("Publish Conf changed");
613
614   if (g_settings_get_boolean (gsettings_loc, key))
615     {
616       if (!priv->geoclue_is_setup)
617         setup_geoclue (manager);
618       /* if still not setup than the init failed */
619       if (!priv->geoclue_is_setup)
620         return;
621
622       geoclue_address_get_address_async (priv->gc_address,
623           initial_address_cb, manager);
624       geoclue_position_get_position_async (priv->gc_position,
625           initial_position_cb, manager);
626     }
627   else
628     {
629       /* As per XEP-0080: send an empty location to have remove current
630        * location from the servers
631        */
632       g_hash_table_remove_all (priv->location);
633       publish_to_all_connections (manager, TRUE);
634     }
635
636 }
637
638 static void
639 resource_cb (GSettings *gsettings_loc,
640              const gchar *key,
641              gpointer user_data)
642 {
643   EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
644   EmpathyLocationManagerPriv *priv = GET_PRIV (manager);
645   GeoclueResourceFlags resource = 0;
646
647   DEBUG ("%s changed", key);
648
649   if (!tp_strdiff (key, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK))
650     resource = GEOCLUE_RESOURCE_NETWORK;
651   if (!tp_strdiff (key, EMPATHY_PREFS_LOCATION_RESOURCE_CELL))
652     resource = GEOCLUE_RESOURCE_CELL;
653   if (!tp_strdiff (key, EMPATHY_PREFS_LOCATION_RESOURCE_GPS))
654     resource = GEOCLUE_RESOURCE_GPS;
655
656   if (g_settings_get_boolean (gsettings_loc, key))
657     priv->resources |= resource;
658   else
659     priv->resources &= ~resource;
660
661   if (priv->geoclue_is_setup)
662     update_resources (manager);
663 }
664
665 static void
666 accuracy_cb (GSettings *gsettings_loc,
667              const gchar *key,
668              gpointer user_data)
669 {
670   EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
671   EmpathyLocationManagerPriv *priv = GET_PRIV (manager);
672
673   DEBUG ("%s changed", key);
674
675   priv->reduce_accuracy = g_settings_get_boolean (gsettings_loc, key);
676
677   if (!priv->geoclue_is_setup)
678     return;
679
680   geoclue_address_get_address_async (priv->gc_address,
681       initial_address_cb, manager);
682   geoclue_position_get_position_async (priv->gc_position,
683       initial_position_cb, manager);
684 }
685
686 static void
687 account_manager_prepared_cb (GObject *source_object,
688     GAsyncResult *result,
689     gpointer user_data)
690 {
691   GList *accounts, *l;
692   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
693   EmpathyLocationManager *self = user_data;
694   GError *error = NULL;
695
696   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
697     {
698       DEBUG ("Failed to prepare account manager: %s", error->message);
699       g_error_free (error);
700       return;
701     }
702
703   accounts = tp_account_manager_get_valid_accounts (account_manager);
704   for (l = accounts; l != NULL; l = l->next)
705     {
706       TpAccount *account = TP_ACCOUNT (l->data);
707
708       tp_g_signal_connect_object (account, "status-changed",
709           G_CALLBACK (new_connection_cb), self, 0);
710     }
711   g_list_free (accounts);
712 }
713
714 static void
715 empathy_location_manager_init (EmpathyLocationManager *self)
716 {
717   EmpathyLocationManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
718       EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManagerPriv);
719
720   self->priv = priv;
721   priv->geoclue_is_setup = FALSE;
722   priv->location = g_hash_table_new_full (g_direct_hash, g_direct_equal,
723       g_free, (GDestroyNotify) tp_g_value_slice_free);
724   priv->gsettings_loc = g_settings_new (EMPATHY_PREFS_LOCATION_SCHEMA);
725
726   /* Setup account status callbacks */
727   priv->account_manager = tp_account_manager_dup ();
728
729   tp_account_manager_prepare_async (priv->account_manager, NULL,
730       account_manager_prepared_cb, self);
731
732   /* Setup settings status callbacks */
733   g_signal_connect (priv->gsettings_loc,
734       "changed::" EMPATHY_PREFS_LOCATION_PUBLISH,
735       G_CALLBACK (publish_cb), self);
736   g_signal_connect (priv->gsettings_loc,
737       "changed::" EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
738       G_CALLBACK (resource_cb), self);
739   g_signal_connect (priv->gsettings_loc,
740       "changed::" EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
741       G_CALLBACK (resource_cb), self);
742   g_signal_connect (priv->gsettings_loc,
743       "changed::" EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
744       G_CALLBACK (resource_cb), self);
745   g_signal_connect (priv->gsettings_loc,
746       "changed::" EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
747       G_CALLBACK (accuracy_cb), self);
748
749   resource_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
750       self);
751   resource_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_RESOURCE_CELL, self);
752   resource_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_RESOURCE_GPS, self);
753   accuracy_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
754       self);
755   publish_cb (priv->gsettings_loc, EMPATHY_PREFS_LOCATION_PUBLISH, self);
756 }
757
758 EmpathyLocationManager *
759 empathy_location_manager_dup_singleton (void)
760 {
761   return EMPATHY_LOCATION_MANAGER (g_object_new (EMPATHY_TYPE_LOCATION_MANAGER,
762       NULL));
763 }