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