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