]> git.0d.be Git - empathy.git/blob - libempathy/empathy-account-manager.c
Fix some coding style issues
[empathy.git] / libempathy / empathy-account-manager.c
1 /*
2  * Copyright (C) 2008 Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
19  *          Sjoerd Simons <sjoerd.simons@collabora.co.uk>
20  */
21
22 #include "config.h"
23
24 #include <telepathy-glib/util.h>
25 #include <telepathy-glib/account-manager.h>
26 #include <telepathy-glib/enums.h>
27 #include <telepathy-glib/defs.h>
28 #include <telepathy-glib/dbus.h>
29 #include <telepathy-glib/interfaces.h>
30
31 #include "empathy-account-manager.h"
32 #include "empathy-marshal.h"
33 #include "empathy-utils.h"
34
35 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
36 #include <libempathy/empathy-debug.h>
37
38 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager)
39
40 #define MC5_BUS_NAME "org.freedesktop.Telepathy.MissionControl5"
41
42 typedef struct {
43   /* (owned) unique name -> (reffed) EmpathyAccount */
44   GHashTable       *accounts;
45   int               connected;
46   int               connecting;
47   gboolean          dispose_run;
48   gboolean          ready;
49   TpAccountManager *tp_manager;
50   TpDBusDaemon *dbus;
51
52   /* global presence */
53   EmpathyAccount *global_account;
54
55   TpConnectionPresenceType global_presence;
56   gchar *global_status;
57   gchar *global_status_message;
58 } EmpathyAccountManagerPriv;
59
60 enum {
61   ACCOUNT_CREATED,
62   ACCOUNT_DELETED,
63   ACCOUNT_ENABLED,
64   ACCOUNT_DISABLED,
65   ACCOUNT_CHANGED,
66   ACCOUNT_CONNECTION_CHANGED,
67   GLOBAL_PRESENCE_CHANGED,
68   NEW_CONNECTION,
69   LAST_SIGNAL
70 };
71
72 enum {
73   PROP_READY = 1,
74 };
75
76 static guint signals[LAST_SIGNAL];
77 static EmpathyAccountManager *manager_singleton = NULL;
78
79 G_DEFINE_TYPE (EmpathyAccountManager, empathy_account_manager, G_TYPE_OBJECT);
80
81 static void
82 emp_account_connection_cb (EmpathyAccount *account,
83   GParamSpec *spec,
84   gpointer manager)
85 {
86   TpConnection *connection = empathy_account_get_connection (account);
87
88   DEBUG ("Signalling connection %p of account %s",
89       connection, empathy_account_get_unique_name (account));
90
91   if (connection != NULL)
92     g_signal_emit (manager, signals[NEW_CONNECTION], 0, connection);
93 }
94
95 static void
96 emp_account_enabled_cb (EmpathyAccount *account,
97   GParamSpec *spec,
98   gpointer manager)
99 {
100   if (empathy_account_is_enabled (account))
101     g_signal_emit (manager, signals[ACCOUNT_ENABLED], 0, account);
102   else
103     g_signal_emit (manager, signals[ACCOUNT_DISABLED], 0, account);
104 }
105
106 static void
107 emp_account_status_changed_cb (EmpathyAccount *account,
108   TpConnectionStatus old,
109   TpConnectionStatus new,
110   TpConnectionStatusReason reason,
111   gpointer user_data)
112 {
113   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
114   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
115
116   switch (old)
117     {
118       case TP_CONNECTION_STATUS_CONNECTING:
119         priv->connecting--;
120         break;
121       case TP_CONNECTION_STATUS_CONNECTED:
122         priv->connected--;
123         break;
124       default:
125         break;
126     }
127
128   switch (new)
129     {
130       case TP_CONNECTION_STATUS_CONNECTING:
131         priv->connecting++;
132         break;
133       case TP_CONNECTION_STATUS_CONNECTED:
134         priv->connected++;
135         break;
136       default:
137         break;
138     }
139
140   g_signal_emit (manager, signals[ACCOUNT_CONNECTION_CHANGED], 0,
141     account, reason, new, old);
142 }
143
144 static void
145 emp_account_manager_update_global_presence (EmpathyAccountManager *manager)
146 {
147   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
148   TpConnectionPresenceType presence = TP_CONNECTION_PRESENCE_TYPE_OFFLINE;
149   EmpathyAccount *account = NULL;
150   GHashTableIter iter;
151   gpointer value;
152
153   /* Make the global presence is equal to the presence of the account with the
154    * highest availability */
155
156   g_hash_table_iter_init (&iter, priv->accounts);
157   while (g_hash_table_iter_next (&iter, NULL, &value))
158     {
159       EmpathyAccount *a = EMPATHY_ACCOUNT (value);
160       TpConnectionPresenceType p;
161
162       g_object_get (a, "presence", &p, NULL);
163
164       if (tp_connection_presence_type_cmp_availability (p, presence) > 0)
165         {
166           account = a;
167           presence = p;
168         }
169     }
170
171   priv->global_account = account;
172   g_free (priv->global_status);
173   g_free (priv->global_status_message);
174
175   if (account == NULL)
176     {
177       priv->global_status = NULL;
178       priv->global_status_message = NULL;
179       return;
180     }
181
182   g_object_get (account,
183     "presence", &priv->global_presence,
184     "status", &priv->global_status,
185     "status-message", &priv->global_status_message,
186     NULL);
187 }
188
189 static void
190 emp_account_presence_changed_cb (EmpathyAccount *account,
191   TpConnectionPresenceType presence,
192   const gchar *status,
193   const gchar *status_message,
194   gpointer user_data)
195 {
196   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
197   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
198
199   if (tp_connection_presence_type_cmp_availability (presence,
200       priv->global_presence) > 0)
201     {
202       priv->global_account = account;
203
204       priv->global_presence = presence;
205
206       g_free (priv->global_status);
207       priv->global_status = g_strdup (status);
208
209       g_free (priv->global_status_message);
210       priv->global_status_message = g_strdup (status_message);
211
212       goto signal;
213     }
214   else if (priv->global_account == account)
215     {
216       emp_account_manager_update_global_presence (manager);
217       goto signal;
218     }
219
220   return;
221 signal:
222     g_signal_emit (manager, signals[GLOBAL_PRESENCE_CHANGED], 0,
223       priv->global_presence, priv->global_status, priv->global_status_message);
224 }
225
226 static void
227 emp_account_removed_cb (EmpathyAccount *account, gpointer user_data)
228 {
229   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
230   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
231
232   g_object_ref (account);
233   g_hash_table_remove (priv->accounts,
234     empathy_account_get_unique_name (account));
235
236   g_signal_emit (manager, signals[ACCOUNT_DELETED], 0, account);
237   g_object_unref (account);
238 }
239
240 static void
241 empathy_account_manager_check_ready (EmpathyAccountManager *manager)
242 {
243   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
244   GHashTableIter iter;
245   gpointer value;
246
247   if (priv->ready)
248     return;
249
250   g_hash_table_iter_init (&iter, priv->accounts);
251   while (g_hash_table_iter_next (&iter, NULL, &value))
252     {
253       EmpathyAccount *account = EMPATHY_ACCOUNT (value);
254       gboolean ready;
255
256       g_object_get (account, "ready", &ready, NULL);
257
258       if (!ready)
259         return;
260     }
261
262   priv->ready = TRUE;
263   g_object_notify (G_OBJECT (manager), "ready");
264 }
265
266 static void
267 emp_account_ready_cb (GObject *obj, GParamSpec *spec, gpointer user_data)
268 {
269   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
270   EmpathyAccount *account = EMPATHY_ACCOUNT (obj);
271   gboolean ready;
272
273   g_object_get (account, "ready", &ready, NULL);
274
275   if (!ready)
276     return;
277
278   g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account);
279
280   g_signal_connect (account, "notify::connection",
281     G_CALLBACK (emp_account_connection_cb), manager);
282
283   g_signal_connect (account, "notify::enabled",
284     G_CALLBACK (emp_account_enabled_cb), manager);
285
286   g_signal_connect (account, "status-changed",
287     G_CALLBACK (emp_account_status_changed_cb), manager);
288
289   g_signal_connect (account, "presence-changed",
290     G_CALLBACK (emp_account_presence_changed_cb), manager);
291
292   g_signal_connect (account, "removed",
293     G_CALLBACK (emp_account_removed_cb), manager);
294
295   empathy_account_manager_check_ready (manager);
296 }
297
298 static EmpathyAccount *
299 account_manager_add_account (EmpathyAccountManager *manager,
300   const gchar *path)
301 {
302   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
303   EmpathyAccount *account;
304
305   account = g_hash_table_lookup (priv->accounts, path);
306   if (account != NULL)
307     return account;
308
309   account = empathy_account_new (priv->dbus, path);
310   g_hash_table_insert (priv->accounts, g_strdup (path), account);
311
312   g_signal_connect (account, "notify::ready",
313     G_CALLBACK (emp_account_ready_cb), manager);
314
315   return account;
316 }
317
318 static void
319 account_manager_got_all_cb (TpProxy *proxy,
320     GHashTable *properties,
321     const GError *error,
322     gpointer user_data,
323     GObject *weak_object)
324 {
325   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (weak_object);
326   GPtrArray *accounts;
327   int i;
328
329   if (error != NULL)
330     {
331       DEBUG ("Failed to get account manager properties: %s", error->message);
332       return;
333     }
334
335   accounts = tp_asv_get_boxed (properties, "ValidAccounts",
336     EMPATHY_ARRAY_TYPE_OBJECT);
337
338   for (i = 0; i < accounts->len; i++)
339     {
340       gchar *name = g_ptr_array_index (accounts, i);
341
342       account_manager_add_account (manager, name);
343     }
344
345   empathy_account_manager_check_ready (manager);
346 }
347
348 static void
349 account_validity_changed_cb (TpAccountManager *proxy,
350     const gchar *path,
351     gboolean valid,
352     gpointer user_data,
353     GObject *weak_object)
354 {
355   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (weak_object);
356
357   if (!valid)
358     return;
359
360   account_manager_add_account (manager, path);
361 }
362
363 static void
364 account_manager_name_owner_cb (TpDBusDaemon *proxy,
365     const gchar *name,
366     const gchar *new_owner,
367     gpointer user_data)
368 {
369   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
370   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
371
372   tp_dbus_daemon_cancel_name_owner_watch (proxy, name,
373     account_manager_name_owner_cb, user_data);
374
375   priv->tp_manager = tp_account_manager_new (priv->dbus);
376
377   tp_cli_account_manager_connect_to_account_validity_changed (
378       priv->tp_manager,
379       account_validity_changed_cb,
380       NULL,
381       NULL,
382       G_OBJECT (manager),
383       NULL);
384
385   tp_cli_dbus_properties_call_get_all (priv->tp_manager, -1,
386     TP_IFACE_ACCOUNT_MANAGER,
387     account_manager_got_all_cb,
388     NULL,
389     NULL,
390     G_OBJECT (manager));
391 }
392
393 static void
394 empathy_account_manager_init (EmpathyAccountManager *manager)
395 {
396   EmpathyAccountManagerPriv *priv;
397   TpProxy *mc5_proxy;
398
399   priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
400       EMPATHY_TYPE_ACCOUNT_MANAGER, EmpathyAccountManagerPriv);
401
402   manager->priv = priv;
403   priv->connected = priv->connecting = 0;
404   priv->global_presence = TP_CONNECTION_PRESENCE_TYPE_UNSET;
405
406   priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
407       g_free, (GDestroyNotify) g_object_unref);
408
409   priv->dbus = tp_dbus_daemon_dup (NULL);
410
411   tp_dbus_daemon_watch_name_owner (priv->dbus,
412       TP_ACCOUNT_MANAGER_BUS_NAME,
413       account_manager_name_owner_cb,
414       manager,
415       NULL);
416
417   /* trigger MC5 starting */
418   mc5_proxy = g_object_new (TP_TYPE_PROXY,
419     "dbus-daemon", priv->dbus,
420     "dbus-connection", tp_proxy_get_dbus_connection (TP_PROXY (priv->dbus)),
421     "bus-name", MC5_BUS_NAME,
422     "object-path", "/",
423     NULL);
424
425   tp_cli_dbus_peer_call_ping (mc5_proxy, -1, NULL, NULL, NULL, NULL);
426
427   g_object_unref (mc5_proxy);
428 }
429
430 static void
431 do_finalize (GObject *obj)
432 {
433   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
434   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
435
436   g_hash_table_destroy (priv->accounts);
437
438   G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj);
439 }
440
441 static void
442 do_dispose (GObject *obj)
443 {
444   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
445   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
446
447   if (priv->dispose_run)
448     return;
449
450   priv->dispose_run = TRUE;
451
452   tp_dbus_daemon_cancel_name_owner_watch (priv->dbus,
453       TP_ACCOUNT_MANAGER_BUS_NAME, account_manager_name_owner_cb, manager);
454
455   if (priv->dbus == NULL)
456     g_object_unref (priv->dbus);
457   priv->dbus = NULL;
458
459   G_OBJECT_CLASS (empathy_account_manager_parent_class)->dispose (obj);
460 }
461
462 static GObject *
463 do_constructor (GType type,
464                 guint n_construct_params,
465                 GObjectConstructParam *construct_params)
466 {
467   GObject *retval;
468
469   if (!manager_singleton)
470     {
471       retval = G_OBJECT_CLASS (empathy_account_manager_parent_class)->constructor (type,
472                                                                                    n_construct_params,
473                                                                                    construct_params);
474       manager_singleton = EMPATHY_ACCOUNT_MANAGER (retval);
475       g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
476     }
477   else
478     {
479       retval = g_object_ref (manager_singleton);
480     }
481
482   return retval;
483 }
484
485 static void
486 do_get_property (GObject *object,
487     guint prop_id,
488     GValue *value,
489     GParamSpec *pspec)
490 {
491   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (object);
492   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
493
494   switch (prop_id)
495     {
496       case PROP_READY:
497         g_value_set_boolean (value, priv->ready);
498         break;
499       default:
500         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
501         break;
502     }
503 }
504
505 static void
506 empathy_account_manager_class_init (EmpathyAccountManagerClass *klass)
507 {
508   GObjectClass *oclass = G_OBJECT_CLASS (klass);
509
510   oclass->finalize = do_finalize;
511   oclass->dispose = do_dispose;
512   oclass->constructor = do_constructor;
513   oclass->get_property = do_get_property;
514
515   g_object_class_install_property (oclass, PROP_READY,
516     g_param_spec_boolean ("ready",
517       "Ready",
518       "Whether the initial state dump from the account manager is finished",
519       FALSE,
520       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
521
522   signals[ACCOUNT_CREATED] =
523     g_signal_new ("account-created",
524                   G_TYPE_FROM_CLASS (klass),
525                   G_SIGNAL_RUN_LAST,
526                   0,
527                   NULL, NULL,
528                   g_cclosure_marshal_VOID__OBJECT,
529                   G_TYPE_NONE,
530                   1, EMPATHY_TYPE_ACCOUNT);
531
532   signals[ACCOUNT_DELETED] =
533     g_signal_new ("account-deleted",
534                   G_TYPE_FROM_CLASS (klass),
535                   G_SIGNAL_RUN_LAST,
536                   0,
537                   NULL, NULL,
538                   g_cclosure_marshal_VOID__OBJECT,
539                   G_TYPE_NONE,
540                   1, EMPATHY_TYPE_ACCOUNT);
541
542   signals[ACCOUNT_ENABLED] =
543     g_signal_new ("account-enabled",
544                   G_TYPE_FROM_CLASS (klass),
545                   G_SIGNAL_RUN_LAST,
546                   0,
547                   NULL, NULL,
548                   g_cclosure_marshal_VOID__OBJECT,
549                   G_TYPE_NONE,
550                   1, EMPATHY_TYPE_ACCOUNT);
551
552   signals[ACCOUNT_DISABLED] =
553     g_signal_new ("account-disabled",
554                   G_TYPE_FROM_CLASS (klass),
555                   G_SIGNAL_RUN_LAST,
556                   0,
557                   NULL, NULL,
558                   g_cclosure_marshal_VOID__OBJECT,
559                   G_TYPE_NONE,
560                   1, EMPATHY_TYPE_ACCOUNT);
561
562   signals[ACCOUNT_CHANGED] =
563     g_signal_new ("account-changed",
564                   G_TYPE_FROM_CLASS (klass),
565                   G_SIGNAL_RUN_LAST,
566                   0,
567                   NULL, NULL,
568                   g_cclosure_marshal_VOID__OBJECT,
569                   G_TYPE_NONE,
570                   1, EMPATHY_TYPE_ACCOUNT);
571
572   signals[ACCOUNT_CONNECTION_CHANGED] =
573     g_signal_new ("account-connection-changed",
574                   G_TYPE_FROM_CLASS (klass),
575                   G_SIGNAL_RUN_LAST,
576                   0,
577                   NULL, NULL,
578                   _empathy_marshal_VOID__OBJECT_INT_UINT_UINT,
579                   G_TYPE_NONE,
580                   4, EMPATHY_TYPE_ACCOUNT,
581                   G_TYPE_INT,   /* reason */
582                   G_TYPE_UINT,  /* actual connection */
583                   G_TYPE_UINT); /* previous connection */
584
585   signals[GLOBAL_PRESENCE_CHANGED] =
586     g_signal_new ("global-presence-changed",
587                   G_TYPE_FROM_CLASS (klass),
588                   G_SIGNAL_RUN_LAST,
589                   0,
590                   NULL, NULL,
591                   _empathy_marshal_VOID__UINT_STRING_STRING,
592                   G_TYPE_NONE,
593                   3, G_TYPE_UINT, /* Presence type */
594                   G_TYPE_STRING,  /* status */
595                   G_TYPE_STRING); /* stauts message*/
596
597   signals[NEW_CONNECTION] =
598     g_signal_new ("new-connection",
599                   G_TYPE_FROM_CLASS (klass),
600                   G_SIGNAL_RUN_LAST,
601                   0,
602                   NULL, NULL,
603                   g_cclosure_marshal_VOID__OBJECT,
604                   G_TYPE_NONE,
605                   1, TP_TYPE_CONNECTION);
606
607   g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv));
608 }
609
610 /* public methods */
611
612 EmpathyAccountManager *
613 empathy_account_manager_dup_singleton (void)
614 {
615   return g_object_new (EMPATHY_TYPE_ACCOUNT_MANAGER, NULL);
616 }
617
618 gboolean
619 empathy_account_manager_is_ready (EmpathyAccountManager *manager)
620 {
621   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
622
623   return priv->ready;
624 }
625
626 int
627 empathy_account_manager_get_connected_accounts (EmpathyAccountManager *manager)
628 {
629   EmpathyAccountManagerPriv *priv;
630
631   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
632
633   priv = GET_PRIV (manager);
634
635   return priv->connected;
636 }
637
638 int
639 empathy_account_manager_get_connecting_accounts (EmpathyAccountManager *manager)
640 {
641   EmpathyAccountManagerPriv *priv;
642
643   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
644
645   priv = GET_PRIV (manager);
646
647   return priv->connecting;
648 }
649
650 /**
651  * empathy_account_manager_get_count:
652  * @manager: a #EmpathyAccountManager
653  *
654  * Get the number of accounts.
655  *
656  * Returns: the number of accounts.
657  **/
658 int
659 empathy_account_manager_get_count (EmpathyAccountManager *manager)
660 {
661   EmpathyAccountManagerPriv *priv;
662
663   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
664
665   priv = GET_PRIV (manager);
666
667   return g_hash_table_size (priv->accounts);
668 }
669
670 EmpathyAccount *
671 empathy_account_manager_get_account_for_connection (
672     EmpathyAccountManager *manager,
673     TpConnection          *connection)
674 {
675   EmpathyAccountManagerPriv *priv;
676   GHashTableIter iter;
677   gpointer value;
678
679   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
680
681   priv = GET_PRIV (manager);
682
683   g_hash_table_iter_init (&iter, priv->accounts);
684   while (g_hash_table_iter_next (&iter, NULL, &value))
685     {
686       EmpathyAccount *account = EMPATHY_ACCOUNT (value);
687
688       if (connection == empathy_account_get_connection (account))
689           return account;
690     }
691
692   return NULL;
693 }
694
695 EmpathyAccount *
696 empathy_account_manager_get_account (EmpathyAccountManager *manager,
697     const gchar *unique_name)
698 {
699   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
700
701   return g_hash_table_lookup (priv->accounts, unique_name);
702 }
703
704 GList *
705 empathy_account_manager_dup_accounts (EmpathyAccountManager *manager)
706 {
707   EmpathyAccountManagerPriv *priv;
708   GList *ret;
709
710   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL);
711
712   priv = GET_PRIV (manager);
713
714   ret = g_hash_table_get_values (priv->accounts);
715   g_list_foreach (ret, (GFunc) g_object_ref, NULL);
716
717   return ret;
718 }
719
720 /**
721  * empathy_account_manager_dup_connections:
722  * @manager: a #EmpathyAccountManager
723  *
724  * Get a #GList of all ready #TpConnection. The list must be freed with
725  * g_list_free, and its elements must be unreffed.
726  *
727  * Returns: the list of connections
728  **/
729 GList *
730 empathy_account_manager_dup_connections (EmpathyAccountManager *manager)
731 {
732   EmpathyAccountManagerPriv *priv;
733   GHashTableIter iter;
734   gpointer value;
735   GList *ret = NULL;
736
737   g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL);
738
739   priv = GET_PRIV (manager);
740
741   g_hash_table_iter_init (&iter, priv->accounts);
742   while (g_hash_table_iter_next (&iter, NULL, &value))
743     {
744       EmpathyAccount *account = EMPATHY_ACCOUNT (value);
745       TpConnection *connection;
746
747       connection = empathy_account_get_connection (account);
748       if (connection != NULL)
749         ret = g_list_prepend (ret, g_object_ref (connection));
750     }
751
752   return ret;
753 }
754
755 void
756 empathy_account_manager_remove (EmpathyAccountManager *manager,
757     EmpathyAccount *account)
758 {
759   /* FIXME */
760 }
761
762
763 void
764 empathy_account_manager_request_global_presence (
765   EmpathyAccountManager *manager,
766   TpConnectionPresenceType type,
767   const gchar *status,
768   const gchar *message)
769 {
770   /* FIXME should remember requested presence and set it on new accounts
771      as well */
772   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
773   GHashTableIter iter;
774   gpointer value;
775
776   g_hash_table_iter_init (&iter, priv->accounts);
777   while (g_hash_table_iter_next (&iter, NULL, &value))
778     {
779       EmpathyAccount *account = EMPATHY_ACCOUNT (value);
780       gboolean ready;
781
782       g_object_get (account, "ready", &ready, NULL);
783
784       if (ready)
785         empathy_account_request_presence (account, type, status, message);
786     }
787 }
788
789 TpConnectionPresenceType
790 empathy_account_manager_get_global_presence (
791   EmpathyAccountManager *manager,
792   gchar **status,
793   gchar **message)
794 {
795   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
796
797   if (status != NULL)
798     *status = g_strdup (priv->global_status);
799   if (message != NULL)
800     *message = g_strdup (priv->global_status_message);
801
802   return priv->global_presence;
803 }
804
805 static void
806 empathy_account_manager_created_ready_cb (EmpathyAccount *account,
807   GParamSpec *spec, gpointer user_data)
808 {
809   GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
810
811   if (!empathy_account_is_ready (account))
812     return;
813
814   g_simple_async_result_set_op_res_gpointer (
815     G_SIMPLE_ASYNC_RESULT (result), account, NULL);
816
817   g_simple_async_result_complete (result);
818   g_object_unref (G_OBJECT (result));
819 }
820
821 static void
822 empathy_account_manager_created_cb (TpAccountManager *proxy,
823     const gchar *account_path,
824     const GError *error,
825     gpointer user_data,
826     GObject *weak_object)
827 {
828   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (weak_object);
829   GSimpleAsyncResult *result = G_SIMPLE_ASYNC_RESULT (user_data);
830   EmpathyAccount *account;
831
832   if (error != NULL)
833     {
834       g_simple_async_result_set_from_error (result, (GError *) error);
835       g_simple_async_result_complete (result);
836       g_object_unref (G_OBJECT (result));
837       return;
838     }
839
840   account = account_manager_add_account (manager, account_path);
841   if (empathy_account_is_ready (account))
842     empathy_account_manager_created_ready_cb (account, NULL, result);
843   else
844     g_signal_connect (account, "notify::ready",
845       G_CALLBACK (empathy_account_manager_created_ready_cb), result);
846 }
847
848 void
849 empathy_account_manager_create_account_async (EmpathyAccountManager *manager,
850     const gchar *connection_manager,
851     const gchar *protocol,
852     const gchar *display_name,
853     GHashTable *parameters,
854     GHashTable *properties,
855     GAsyncReadyCallback callback,
856     gpointer user_data)
857 {
858   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
859   GSimpleAsyncResult *result = g_simple_async_result_new (G_OBJECT (manager),
860       callback, user_data, empathy_account_manager_create_account_finish);
861
862   tp_cli_account_manager_call_create_account (priv->tp_manager,
863       -1,
864       connection_manager,
865       protocol,
866       display_name,
867       parameters,
868       properties,
869       empathy_account_manager_created_cb,
870       result,
871       NULL,
872       G_OBJECT (manager));
873 }
874
875 EmpathyAccount *
876 empathy_account_manager_create_account_finish (
877   EmpathyAccountManager *manager, GAsyncResult *result, GError **error)
878 {
879   if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
880       error))
881     return NULL;
882
883   g_return_val_if_fail (g_simple_async_result_is_valid (result,
884     G_OBJECT (manager), empathy_account_manager_create_account_finish), NULL);
885
886   return EMPATHY_ACCOUNT (g_simple_async_result_get_op_res_gpointer (
887     G_SIMPLE_ASYNC_RESULT (result)));
888 }
889