]> git.0d.be Git - empathy.git/blob - libempathy/empathy-account-manager.c
Style fixes.
[empathy.git] / libempathy / empathy-account-manager.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /*
3  * Copyright (C) 2008 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  * 
19  * Authors: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
20  */
21
22 #include <config.h>
23
24 #include <libmissioncontrol/mc-account-monitor.h>
25
26 #include "empathy-account-manager.h"
27 #include "empathy-marshal.h"
28 #include "empathy-utils.h"
29
30 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager)
31
32 typedef struct {
33   McAccountMonitor *monitor;
34   MissionControl   *mc;
35
36   GHashTable       *accounts;
37   int               connected;
38   int               connecting;
39 } EmpathyAccountManagerPriv;
40
41 typedef struct {
42   McPresence presence;
43   TpConnectionStatus connection;
44   gboolean is_enabled;
45
46   guint source_id;
47 } AccountData;
48
49 enum {
50   ACCOUNT_CREATED,
51   ACCOUNT_DELETED,
52   ACCOUNT_ENABLED,
53   ACCOUNT_DISABLED,
54   ACCOUNT_CHANGED,
55   ACCOUNT_CONNECTION_CHANGED,
56   ACCOUNT_PRESENCE_CHANGED,
57   LAST_SIGNAL
58 };
59
60 static guint signals[LAST_SIGNAL];
61 static EmpathyAccountManager *manager = NULL;
62
63 G_DEFINE_TYPE (EmpathyAccountManager, empathy_account_manager, G_TYPE_OBJECT);
64
65 static AccountData *
66 account_data_new (McPresence presence, TpConnectionStatus connection,
67                   gboolean is_enabled)
68 {
69   AccountData *retval;
70
71   retval = g_slice_new0 (AccountData);
72   retval->presence = presence;
73   retval->connection = connection;
74   retval->is_enabled = is_enabled;
75   retval->source_id = 0;
76
77   return retval;
78 }
79
80 static AccountData *
81 account_data_new_default (MissionControl *mc,
82                           McAccount *account)
83 {
84   McPresence actual_p;
85   TpConnectionStatus actual_c;
86   GError *err = NULL;
87
88   actual_p = mission_control_get_presence_actual (mc, &err);
89   if (err) {
90     actual_p = MC_PRESENCE_UNSET;
91     g_clear_error (&err);
92   }
93
94   actual_c = mission_control_get_connection_status (mc,
95                                                     account, &err);
96   if (err) {
97     actual_c = TP_CONNECTION_STATUS_DISCONNECTED;
98   }
99
100   return account_data_new (actual_p, actual_c, mc_account_is_enabled (account));
101 }
102
103 static void
104 account_data_free (AccountData *data)
105 {
106   if (data->source_id > 0) {
107     g_source_remove (data->source_id);
108     data->source_id = 0;
109   }
110
111   g_slice_free (AccountData, data);
112 }
113
114 static void
115 account_created_cb (McAccountMonitor *mon,
116                     gchar *account_name,
117                     EmpathyAccountManager *manager)
118 {
119   McAccount *account;
120   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
121
122   account = mc_account_lookup (account_name);
123
124   if (account) {
125     AccountData *data;
126
127     data = account_data_new_default (priv->mc, account);
128
129     g_hash_table_insert (priv->accounts, account, data);
130
131     g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account);
132   }
133 }
134
135 static void
136 account_deleted_cb (McAccountMonitor *mon,
137                     gchar *account_name,
138                     EmpathyAccountManager *manager)
139 {
140   McAccount *account;
141   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
142
143   account = mc_account_lookup (account_name);
144
145   if (account) {
146     g_signal_emit (manager, signals[ACCOUNT_DELETED], 0, account);
147     
148     g_hash_table_remove (priv->accounts, account);
149     g_object_unref (account);
150   }
151 }
152
153 static void
154 account_changed_cb (McAccountMonitor *mon,
155                     gchar *account_name,
156                     EmpathyAccountManager *manager)
157 {
158   McAccount *account;
159
160   account = mc_account_lookup (account_name);
161
162   if (account) {
163     g_signal_emit (manager, signals[ACCOUNT_CHANGED], 0, account);
164     g_object_unref (account);
165   }
166 }
167
168 static void
169 account_disabled_cb (McAccountMonitor *mon,
170                      gchar *account_name,
171                      EmpathyAccountManager *manager)
172 {
173   McAccount *account;
174   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
175   AccountData *data;
176
177   account = mc_account_lookup (account_name);
178
179   if (account) {
180     data = g_hash_table_lookup (priv->accounts, account);
181     g_assert (data);
182     data->is_enabled = FALSE;
183
184     g_signal_emit (manager, signals[ACCOUNT_DISABLED], 0, account);
185   }
186 }
187
188 static void
189 account_enabled_cb (McAccountMonitor *mon,
190                     gchar *account_name,
191                     EmpathyAccountManager *manager)
192 {
193   McAccount *account;
194   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
195   AccountData *data;
196
197   account = mc_account_lookup (account_name);
198
199   if (account) {
200     data = g_hash_table_lookup (priv->accounts, account);
201     g_assert (data);
202     data->is_enabled = TRUE;
203
204     g_signal_emit (manager, signals[ACCOUNT_ENABLED], 0, account);
205     g_object_unref (account);
206   }
207 }
208
209 static void
210 update_connection_numbers (EmpathyAccountManager *manager,
211                            TpConnectionStatus conn,
212                            TpConnectionStatus old_c)
213 {
214   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
215
216   if (conn == TP_CONNECTION_STATUS_CONNECTED) {
217     priv->connected++;
218     if (old_c == TP_CONNECTION_STATUS_CONNECTING) {
219       priv->connecting--;
220     }
221   }
222
223   if (conn == TP_CONNECTION_STATUS_CONNECTING) {
224     priv->connecting++;
225     if (old_c == TP_CONNECTION_STATUS_CONNECTED) {
226       priv->connected--;
227     }
228   }
229
230   if (conn == TP_CONNECTION_STATUS_DISCONNECTED) {
231     if (old_c == TP_CONNECTION_STATUS_CONNECTED) {
232       priv->connected--;
233     }
234     if (old_c == TP_CONNECTION_STATUS_CONNECTING) {
235       priv->connecting--;
236     }
237   }
238 }
239
240 static gboolean
241 remove_data_timeout (gpointer _data)
242 {
243   AccountData *data = _data;
244
245   data->source_id = 0;
246
247   return FALSE;
248 }
249
250 static void
251 account_status_changed_cb (MissionControl *mc,
252                            TpConnectionStatus connection,
253                            McPresence presence,
254                            TpConnectionStatusReason reason,
255                            const gchar *unique_name,
256                            EmpathyAccountManager *manager)
257 {
258   McAccount *account;
259   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
260   AccountData *data;
261   McPresence old_p;
262   TpConnectionStatus old_c;
263
264   account = mc_account_lookup (unique_name);
265
266   if (account) {
267     data = g_hash_table_lookup (priv->accounts, account);
268     g_assert (data);
269
270     old_p = data->presence;
271     old_c = data->connection;
272
273     if (old_p != presence) {
274       data->presence = presence;
275       g_signal_emit (manager, signals[ACCOUNT_PRESENCE_CHANGED], 0,
276                      account, presence, old_p);
277     }
278
279     if (old_c != connection) {
280       data->connection = connection;
281       update_connection_numbers (manager, connection, old_c);
282
283       g_signal_emit (manager, signals[ACCOUNT_CONNECTION_CHANGED], 0,
284                      account, reason, connection, old_c);
285
286       if (old_c == TP_CONNECTION_STATUS_CONNECTING &&
287           connection == TP_CONNECTION_STATUS_CONNECTED) {
288             if (data->source_id > 0) {
289               g_source_remove (data->source_id);
290               data->source_id = 0;
291             }
292
293             data->source_id = g_timeout_add_seconds (10,
294                                                      remove_data_timeout,
295                                                      data);
296           }
297     }
298
299     g_object_unref (account);
300   }
301 }
302
303 static void
304 empathy_account_manager_init (EmpathyAccountManager *manager)
305 {
306   EmpathyAccountManagerPriv *priv =
307     G_TYPE_INSTANCE_GET_PRIVATE (manager,
308                                  EMPATHY_TYPE_ACCOUNT_MANAGER, EmpathyAccountManagerPriv);
309   GList *mc_accounts, *l;
310   AccountData *data;
311
312   manager->priv = priv;
313   priv->monitor = mc_account_monitor_new ();
314   priv->mc = empathy_mission_control_new ();
315   priv->connected = priv->connecting = 0;
316
317   priv->accounts = g_hash_table_new_full (empathy_account_hash,
318                                           empathy_account_equal,
319                                           g_object_unref, 
320                                           (GDestroyNotify) account_data_free);
321
322   mc_accounts = mc_accounts_list ();
323
324   for (l = mc_accounts; l; l = l->next) {
325     data = account_data_new_default (priv->mc, l->data);
326     
327     g_hash_table_insert (priv->accounts, g_object_ref (l->data),
328                          data);
329   }
330
331   g_signal_connect (priv->monitor, "account-created",
332                     G_CALLBACK (account_created_cb), manager);
333   g_signal_connect (priv->monitor, "account-deleted",
334                     G_CALLBACK (account_deleted_cb), manager);
335   g_signal_connect (priv->monitor, "account-disabled",
336                     G_CALLBACK (account_disabled_cb), manager);
337   g_signal_connect (priv->monitor, "account-enabled",
338                     G_CALLBACK (account_enabled_cb), manager);
339   g_signal_connect (priv->monitor, "account-changed",
340                     G_CALLBACK (account_changed_cb), manager);
341
342   dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
343                                G_CALLBACK (account_status_changed_cb),
344                                manager, NULL);
345 }
346
347 static void
348 disconnect_monitor_signals (McAccountMonitor *monitor,
349                             GObject *obj)
350 {
351   g_signal_handlers_disconnect_by_func (monitor,
352                                         account_created_cb, obj);
353   g_signal_handlers_disconnect_by_func (monitor,
354                                         account_deleted_cb, obj);
355   g_signal_handlers_disconnect_by_func (monitor,
356                                         account_disabled_cb, obj);
357   g_signal_handlers_disconnect_by_func (monitor,
358                                         account_enabled_cb, obj);
359   g_signal_handlers_disconnect_by_func (monitor,
360                                         account_changed_cb, obj);
361 }
362
363 static void
364 do_finalize (GObject *obj)
365 {
366   EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
367   EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
368
369   dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
370                                   "AccountStatusChanged",
371                                   G_CALLBACK (account_status_changed_cb),
372                                   obj);
373
374   disconnect_monitor_signals (priv->monitor, obj);
375
376   g_object_unref (priv->monitor);
377   g_object_unref (priv->mc);
378
379   g_hash_table_destroy (priv->accounts);
380
381   G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj);
382 }
383
384 static void
385 empathy_account_manager_class_init (EmpathyAccountManagerClass *klass)
386 {
387   GObjectClass *oclass = G_OBJECT_CLASS (klass);
388
389   oclass->finalize = do_finalize;
390
391   signals[ACCOUNT_CREATED] =
392     g_signal_new ("account-created",
393                   G_TYPE_FROM_CLASS (klass),
394                   G_SIGNAL_RUN_LAST,
395                   0,
396                   NULL, NULL,
397                   g_cclosure_marshal_VOID__OBJECT,
398                   G_TYPE_NONE,
399                   1, MC_TYPE_ACCOUNT);
400
401   signals[ACCOUNT_DELETED] =
402     g_signal_new ("account-deleted",
403                   G_TYPE_FROM_CLASS (klass),
404                   G_SIGNAL_RUN_LAST,
405                   0,
406                   NULL, NULL,
407                   g_cclosure_marshal_VOID__OBJECT,
408                   G_TYPE_NONE,
409                   1, MC_TYPE_ACCOUNT);
410
411   signals[ACCOUNT_ENABLED] =
412     g_signal_new ("account-enabled",
413                   G_TYPE_FROM_CLASS (klass),
414                   G_SIGNAL_RUN_LAST,
415                   0,
416                   NULL, NULL,
417                   g_cclosure_marshal_VOID__OBJECT,
418                   G_TYPE_NONE,
419                   1, MC_TYPE_ACCOUNT);
420
421   signals[ACCOUNT_DISABLED] =
422     g_signal_new ("account-disabled",
423                   G_TYPE_FROM_CLASS (klass),
424                   G_SIGNAL_RUN_LAST,
425                   0,
426                   NULL, NULL,
427                   g_cclosure_marshal_VOID__OBJECT,
428                   G_TYPE_NONE,
429                   1, MC_TYPE_ACCOUNT);
430
431   signals[ACCOUNT_CHANGED] =
432     g_signal_new ("account-changed",
433                   G_TYPE_FROM_CLASS (klass),
434                   G_SIGNAL_RUN_LAST,
435                   0,
436                   NULL, NULL,
437                   g_cclosure_marshal_VOID__OBJECT,
438                   G_TYPE_NONE,
439                   1, MC_TYPE_ACCOUNT);
440
441   signals[ACCOUNT_CONNECTION_CHANGED] =
442     g_signal_new ("account-connection-changed",
443                   G_TYPE_FROM_CLASS (klass),
444                   G_SIGNAL_RUN_LAST,
445                   0,
446                   NULL, NULL,
447                   _empathy_marshal_VOID__OBJECT_INT_UINT_UINT,
448                   G_TYPE_NONE,
449                   4, MC_TYPE_ACCOUNT,
450                   G_TYPE_INT,   /* reason */
451                   G_TYPE_UINT,  /* actual connection */
452                   G_TYPE_UINT); /* previous connection */
453
454   signals[ACCOUNT_PRESENCE_CHANGED] =
455     g_signal_new ("account-presence-changed",
456                   G_TYPE_FROM_CLASS (klass),
457                   G_SIGNAL_RUN_LAST,
458                   0,
459                   NULL, NULL,
460                   _empathy_marshal_VOID__OBJECT_INT_INT,
461                   G_TYPE_NONE,
462                   3, MC_TYPE_ACCOUNT,
463                   G_TYPE_INT,  /* actual presence */
464                   G_TYPE_INT); /* previous presence */
465   
466   g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv));
467 }
468
469 /* public methods */
470
471 EmpathyAccountManager *
472 empathy_account_manager_new (void)
473 {
474   if (!manager) {
475     manager = g_object_new (EMPATHY_TYPE_ACCOUNT_MANAGER, NULL);
476     g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
477   } else {
478     g_object_ref (manager);
479   }
480
481   return manager;
482 }
483
484 int
485 empathy_account_manager_get_connected_accounts (EmpathyAccountManager *manager)
486 {
487   EmpathyAccountManagerPriv *priv;
488
489   g_assert (EMPATHY_IS_ACCOUNT_MANAGER (manager));
490
491   priv = GET_PRIV (manager);
492
493   return priv->connected;
494 }
495
496 int
497 empathy_account_manager_get_connecting_accounts (EmpathyAccountManager *manager)
498 {
499   EmpathyAccountManagerPriv *priv;
500
501   g_assert (EMPATHY_IS_ACCOUNT_MANAGER (manager));
502
503   priv = GET_PRIV (manager);
504
505   return priv->connecting;
506 }
507
508 gboolean
509 empathy_account_manager_is_account_just_connected (EmpathyAccountManager *manager,
510                                                    McAccount *account)
511 {
512   EmpathyAccountManagerPriv *priv;
513   AccountData *data;
514
515   g_assert (EMPATHY_IS_ACCOUNT_MANAGER (manager));
516
517   priv = GET_PRIV (manager);
518   data = g_hash_table_lookup (priv->accounts, account);
519
520   g_assert (data);
521
522   return (data->source_id > 0);
523 }