]> git.0d.be Git - empathy.git/blob - libempathy/empathy-account.c
c6a2184f9d146f354a3dfdd1e2cd064607589fee
[empathy.git] / libempathy / empathy-account.c
1 /*
2  * empathy-account.c - Source for EmpathyAccount
3  * Copyright (C) 2009 Collabora Ltd.
4  * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <telepathy-glib/enums.h>
26
27 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
28 #include <libempathy/empathy-debug.h>
29
30 #include "empathy-account.h"
31 #include "empathy-account-priv.h"
32 #include "empathy-utils.h"
33 #include "empathy-marshal.h"
34
35 /* signals */
36 enum {
37   STATUS_CHANGED,
38   PRESENCE_CHANGED,
39   LAST_SIGNAL
40 };
41
42 static guint signals[LAST_SIGNAL];
43
44 /* properties */
45 enum {
46   PROP_ENABLED = 1,
47   PROP_PRESENCE,
48   PROP_CONNECTION_STATUS,
49   PROP_CONNECTION_STATUS_REASON,
50   PROP_CONNECTION,
51   PROP_UNIQUE_NAME,
52   PROP_DISPLAY_NAME
53 };
54
55 G_DEFINE_TYPE(EmpathyAccount, empathy_account, G_TYPE_OBJECT)
56
57 /* private structure */
58 typedef struct _EmpathyAccountPriv EmpathyAccountPriv;
59
60 struct _EmpathyAccountPriv
61 {
62   gboolean dispose_has_run;
63
64   TpConnection *connection;
65   guint connection_invalidated_id;
66
67   TpConnectionStatus status;
68   TpConnectionStatusReason reason;
69   TpConnectionPresenceType presence;
70
71   gboolean enabled;
72   /* Timestamp when the connection got connected in seconds since the epoch */
73   glong connect_time;
74
75   McAccount *mc_account;
76   McProfile *mc_profile;
77
78   gchar *cm_name;
79   gchar *proto_name;
80   gchar *icon_name;
81 };
82
83 #define GET_PRIV(obj)  EMPATHY_GET_PRIV (obj, EmpathyAccount)
84
85 static void
86 empathy_account_init (EmpathyAccount *obj)
87 {
88   EmpathyAccountPriv *priv;
89
90   priv =  G_TYPE_INSTANCE_GET_PRIVATE (obj,
91     EMPATHY_TYPE_ACCOUNT, EmpathyAccountPriv);
92
93   obj->priv = priv;
94
95   priv->status = TP_CONNECTION_STATUS_DISCONNECTED;
96 }
97
98 static void
99 empathy_account_get_property (GObject *object,
100     guint prop_id,
101     GValue *value,
102     GParamSpec *pspec)
103 {
104   EmpathyAccount *account = EMPATHY_ACCOUNT (object);
105   EmpathyAccountPriv *priv = GET_PRIV (account);
106
107   switch (prop_id)
108     {
109       case PROP_ENABLED:
110         g_value_set_boolean (value, priv->enabled);
111         break;
112       case PROP_PRESENCE:
113         g_value_set_uint (value, priv->presence);
114         break;
115       case PROP_CONNECTION_STATUS:
116         g_value_set_uint (value, priv->status);
117         break;
118       case PROP_CONNECTION_STATUS_REASON:
119         g_value_set_uint (value, priv->reason);
120         break;
121       case PROP_CONNECTION:
122         g_value_set_object (value,
123             empathy_account_get_connection (account));
124         break;
125       case PROP_UNIQUE_NAME:
126         g_value_set_string (value,
127             empathy_account_get_unique_name (account));
128         break;
129       case PROP_DISPLAY_NAME:
130         g_value_set_string (value,
131             empathy_account_get_display_name (account));
132         break;
133       default:
134         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
135         break;
136     }
137 }
138
139 static void empathy_account_dispose (GObject *object);
140 static void empathy_account_finalize (GObject *object);
141
142 static void
143 empathy_account_class_init (EmpathyAccountClass *empathy_account_class)
144 {
145   GObjectClass *object_class = G_OBJECT_CLASS (empathy_account_class);
146
147   g_type_class_add_private (empathy_account_class,
148     sizeof (EmpathyAccountPriv));
149
150   object_class->get_property = empathy_account_get_property;
151   object_class->dispose = empathy_account_dispose;
152   object_class->finalize = empathy_account_finalize;
153
154   g_object_class_install_property (object_class, PROP_ENABLED,
155     g_param_spec_boolean ("enabled",
156       "Enabled",
157       "Whether this account is enabled or not",
158       FALSE,
159       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
160
161   g_object_class_install_property (object_class, PROP_PRESENCE,
162     g_param_spec_uint ("presence",
163       "Presence",
164       "The account connections presence type",
165       0,
166       NUM_TP_CONNECTION_PRESENCE_TYPES,
167       TP_CONNECTION_PRESENCE_TYPE_UNSET,
168       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
169
170   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS,
171     g_param_spec_uint ("status",
172       "ConnectionStatus",
173       "The accounts connections status type",
174       0,
175       NUM_TP_CONNECTION_STATUSES,
176       TP_CONNECTION_STATUS_DISCONNECTED,
177       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
178
179   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON,
180     g_param_spec_uint ("status-reason",
181       "ConnectionStatusReason",
182       "The account connections status reason",
183       0,
184       NUM_TP_CONNECTION_STATUS_REASONS,
185       TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
186       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
187
188   g_object_class_install_property (object_class, PROP_CONNECTION,
189     g_param_spec_object ("connection",
190       "Connection",
191       "The accounts connection",
192       TP_TYPE_CONNECTION,
193       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
194
195   g_object_class_install_property (object_class, PROP_UNIQUE_NAME,
196     g_param_spec_string ("unique-name",
197       "UniqueName",
198       "The accounts unique name",
199       NULL,
200       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
201
202   g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
203     g_param_spec_string ("display-name",
204       "DisplayName",
205       "The accounts display name",
206       NULL,
207       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
208
209   signals[STATUS_CHANGED] = g_signal_new ("status-changed",
210     G_TYPE_FROM_CLASS (object_class),
211     G_SIGNAL_RUN_LAST,
212     0, NULL, NULL,
213     _empathy_marshal_VOID__UINT_UINT_UINT,
214     G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
215
216   signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed",
217     G_TYPE_FROM_CLASS (object_class),
218     G_SIGNAL_RUN_LAST,
219     0, NULL, NULL,
220     _empathy_marshal_VOID__UINT_UINT,
221     G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
222 }
223
224 void
225 empathy_account_dispose (GObject *object)
226 {
227   EmpathyAccount *self = EMPATHY_ACCOUNT (object);
228   EmpathyAccountPriv *priv = GET_PRIV (self);
229
230   if (priv->dispose_has_run)
231     return;
232
233   priv->dispose_has_run = TRUE;
234
235   if (priv->connection_invalidated_id != 0)
236     g_signal_handler_disconnect (priv->connection,
237         priv->connection_invalidated_id);
238   priv->connection_invalidated_id = 0;
239
240   if (priv->connection != NULL)
241     g_object_unref (priv->connection);
242   priv->connection = NULL;
243
244   if (priv->mc_profile != NULL)
245     g_object_unref (priv->mc_profile);
246   priv->mc_profile = NULL;
247
248   /* release any references held by the object here */
249   if (G_OBJECT_CLASS (empathy_account_parent_class)->dispose != NULL)
250     G_OBJECT_CLASS (empathy_account_parent_class)->dispose (object);
251 }
252
253 void
254 empathy_account_finalize (GObject *object)
255 {
256   EmpathyAccountPriv *priv = GET_PRIV (object);
257
258   g_free (priv->cm_name);
259   g_free (priv->proto_name);
260   g_free (priv->icon_name);
261
262   /* free any data held directly by the object here */
263   if (G_OBJECT_CLASS (empathy_account_parent_class)->finalize != NULL)
264     G_OBJECT_CLASS (empathy_account_parent_class)->finalize (object);
265 }
266
267 gboolean
268 empathy_account_is_just_connected (EmpathyAccount *account)
269 {
270   EmpathyAccountPriv *priv = GET_PRIV (account);
271   GTimeVal val;
272
273   if (priv->status != TP_CONNECTION_STATUS_CONNECTED)
274     return FALSE;
275
276   g_get_current_time (&val);
277
278   return (val.tv_sec - priv->connect_time) < 10;
279 }
280
281 /**
282  * empathy_account_get_connection:
283  * @account: a #EmpathyAccount
284  *
285  * Get the connection of the account, or NULL if account is offline or the
286  * connection is not yet ready. This function does not return a new ref.
287  *
288  * Returns: the connection of the account.
289  **/
290 TpConnection *
291 empathy_account_get_connection (EmpathyAccount *account)
292 {
293   EmpathyAccountPriv *priv = GET_PRIV (account);
294
295   if (priv->connection != NULL &&
296       tp_connection_is_ready (priv->connection))
297     return priv->connection;
298
299   return NULL;
300 }
301
302 /**
303  * empathy_account_get_unique_name:
304  * @account: a #EmpathyAccount
305  *
306  * Returns: the unique name of the account.
307  **/
308 const gchar *
309 empathy_account_get_unique_name (EmpathyAccount *account)
310 {
311   EmpathyAccountPriv *priv = GET_PRIV (account);
312
313   return mc_account_get_unique_name (priv->mc_account);
314 }
315
316 /**
317  * empathy_account_get_display_name:
318  * @account: a #EmpathyAccount
319  *
320  * Returns: the display name of the account.
321  **/
322 const gchar *
323 empathy_account_get_display_name (EmpathyAccount *account)
324 {
325   EmpathyAccountPriv *priv = GET_PRIV (account);
326
327   return mc_account_get_display_name (priv->mc_account);
328 }
329
330 gboolean
331 empathy_account_is_valid (EmpathyAccount *account)
332 {
333   EmpathyAccountPriv *priv = GET_PRIV (account);
334
335   return mc_account_is_complete (priv->mc_account);
336 }
337
338 const gchar *
339 empathy_account_get_connection_manager (EmpathyAccount *account)
340 {
341   EmpathyAccountPriv *priv = GET_PRIV (account);
342
343   return priv->cm_name;
344 }
345
346 const gchar *
347 empathy_account_get_protocol (EmpathyAccount *account)
348 {
349   EmpathyAccountPriv *priv = GET_PRIV (account);
350
351   return priv->proto_name;
352 }
353
354 const gchar *
355 empathy_account_get_icon_name (EmpathyAccount *account)
356 {
357   EmpathyAccountPriv *priv = GET_PRIV (account);
358
359   return priv->icon_name;
360 }
361
362 void
363 empathy_account_set_enabled (EmpathyAccount *account, gboolean enabled)
364 {
365   EmpathyAccountPriv *priv = GET_PRIV (account);
366
367   mc_account_set_enabled (priv->mc_account, enabled);
368 }
369
370 gboolean
371 empathy_account_is_enabled (EmpathyAccount *account)
372 {
373   EmpathyAccountPriv *priv = GET_PRIV (account);
374
375   return priv->enabled;
376 }
377
378 void
379 empathy_account_unset_param (EmpathyAccount *account, const gchar *param)
380 {
381   EmpathyAccountPriv *priv = GET_PRIV (account);
382
383   mc_account_unset_param (priv->mc_account, param);
384 }
385
386 gchar *
387 empathy_account_get_param_string (EmpathyAccount *account, const gchar *param)
388 {
389   EmpathyAccountPriv *priv = GET_PRIV (account);
390   gchar *value = NULL;
391
392   mc_account_get_param_string (priv->mc_account, param, &value);
393   return value;
394 }
395
396 gint
397 empathy_account_get_param_int (EmpathyAccount *account, const gchar *param)
398 {
399   EmpathyAccountPriv *priv = GET_PRIV (account);
400   int value;
401
402   mc_account_get_param_int (priv->mc_account, param, &value);
403   return value;
404 }
405
406 gboolean
407 empathy_account_get_param_boolean (EmpathyAccount *account, const gchar *param)
408 {
409   EmpathyAccountPriv *priv = GET_PRIV (account);
410   gboolean value;
411
412   mc_account_get_param_boolean (priv->mc_account, param, &value);
413   return value;
414 }
415
416 void
417 empathy_account_set_param_string (EmpathyAccount *account,
418   const gchar *param,
419   const gchar *value)
420 {
421   EmpathyAccountPriv *priv = GET_PRIV (account);
422   mc_account_set_param_string (priv->mc_account, param, value);
423 }
424
425 void
426 empathy_account_set_param_int (EmpathyAccount *account,
427   const gchar *param,
428   gint value)
429 {
430   EmpathyAccountPriv *priv = GET_PRIV (account);
431   mc_account_set_param_int (priv->mc_account, param, value);
432 }
433
434 void
435 empathy_account_set_param_boolean (EmpathyAccount *account,
436   const gchar *param,
437   gboolean value)
438 {
439   EmpathyAccountPriv *priv = GET_PRIV (account);
440   mc_account_set_param_boolean (priv->mc_account, param, value);
441 }
442
443 void
444 empathy_account_set_display_name (EmpathyAccount *account,
445     const gchar *display_name)
446 {
447   EmpathyAccountPriv *priv = GET_PRIV (account);
448   mc_account_set_display_name (priv->mc_account, display_name);
449 }
450
451 EmpathyAccount *
452 _empathy_account_new (McAccount *mc_account)
453 {
454   EmpathyAccount *account;
455   EmpathyAccountPriv *priv;
456   McProfile *profile;
457   McProtocol *protocol;
458
459
460   account = g_object_new (EMPATHY_TYPE_ACCOUNT, NULL);
461   priv = GET_PRIV (account);
462   priv->mc_account = mc_account;
463
464   profile =  mc_account_get_profile (mc_account);
465   protocol = mc_profile_get_protocol (profile);
466
467   if (protocol != NULL)
468     {
469       McManager *manager = mc_protocol_get_manager (protocol);
470
471       priv->proto_name = g_strdup (mc_protocol_get_name (protocol));
472       priv->cm_name = g_strdup (mc_manager_get_unique_name (manager));
473       priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name);
474
475       g_object_unref (protocol);
476       g_object_unref (manager);
477     }
478   g_object_unref (profile);
479
480   return account;
481 }
482
483 void
484 _empathy_account_set_status (EmpathyAccount *account,
485     TpConnectionStatus status,
486     TpConnectionStatusReason reason,
487     TpConnectionPresenceType presence)
488 {
489   EmpathyAccountPriv *priv = GET_PRIV (account);
490   TpConnectionStatus old_s = priv->status;
491   TpConnectionPresenceType old_p = priv->presence;
492
493   priv->status = status;
494   priv->presence = presence;
495
496   if (priv->status != old_s)
497     {
498       if (priv->status == TP_CONNECTION_STATUS_CONNECTED)
499         {
500           GTimeVal val;
501           g_get_current_time (&val);
502
503           priv->connect_time = val.tv_sec;
504         }
505
506       priv->reason = reason;
507       g_signal_emit (account, signals[STATUS_CHANGED], 0,
508         old_s, priv->status, reason);
509
510       g_object_notify (G_OBJECT (account), "status");
511     }
512
513   if (priv->presence != old_p)
514     {
515       g_signal_emit (account, signals[PRESENCE_CHANGED], 0,
516         old_p, priv->presence);
517       g_object_notify (G_OBJECT (account), "presence");
518     }
519 }
520
521 static void
522 empathy_account_connection_ready_cb (TpConnection *connection,
523     const GError *error,
524     gpointer user_data)
525 {
526   EmpathyAccount *account = EMPATHY_ACCOUNT (user_data);
527   EmpathyAccountPriv *priv = GET_PRIV (account);
528
529   if (error != NULL)
530     {
531       DEBUG ("(%s) Connection failed to become ready: %s",
532         empathy_account_get_unique_name (account), error->message);
533       priv->connection = NULL;
534     }
535   else
536     {
537       DEBUG ("(%s) Connection ready",
538         empathy_account_get_unique_name (account));
539       g_object_notify (G_OBJECT (account), "connection");
540     }
541 }
542
543 static void
544 _empathy_account_connection_invalidated_cb (TpProxy *self,
545   guint    domain,
546   gint     code,
547   gchar   *message,
548   gpointer user_data)
549 {
550   EmpathyAccount *account = EMPATHY_ACCOUNT (user_data);
551   EmpathyAccountPriv *priv = GET_PRIV (account);
552
553   if (priv->connection == NULL)
554     return;
555
556   DEBUG ("(%s) Connection invalidated",
557     empathy_account_get_unique_name (account));
558
559   g_assert (priv->connection == TP_CONNECTION (self));
560
561   g_signal_handler_disconnect (priv->connection,
562     priv->connection_invalidated_id);
563   priv->connection_invalidated_id = 0;
564
565   g_object_unref (priv->connection);
566   priv->connection = NULL;
567
568   g_object_notify (G_OBJECT (account), "connection");
569 }
570
571 void
572 _empathy_account_set_connection (EmpathyAccount *account,
573     TpConnection *connection)
574 {
575   EmpathyAccountPriv *priv = GET_PRIV (account);
576
577   if (priv->connection == connection)
578     return;
579
580   /* Connection already set, don't set the new one */
581   if (connection != NULL && priv->connection != NULL)
582     return;
583
584   if (connection == NULL)
585     {
586       g_signal_handler_disconnect (priv->connection,
587         priv->connection_invalidated_id);
588       priv->connection_invalidated_id = 0;
589
590       g_object_unref (priv->connection);
591       priv->connection = NULL;
592       g_object_notify (G_OBJECT (account), "connection");
593     }
594   else
595     {
596       priv->connection = g_object_ref (connection);
597       priv->connection_invalidated_id = g_signal_connect (priv->connection,
598           "invalidated",
599           G_CALLBACK (_empathy_account_connection_invalidated_cb),
600           account);
601
602       /* notify a change in the connection property when it's ready */
603       tp_connection_call_when_ready (priv->connection,
604         empathy_account_connection_ready_cb, account);
605     }
606 }
607
608 void
609 _empathy_account_set_enabled (EmpathyAccount *account,
610     gboolean enabled)
611 {
612   EmpathyAccountPriv *priv = GET_PRIV (account);
613
614   if (priv->enabled == enabled)
615     return;
616
617   priv->enabled = enabled;
618   g_object_notify (G_OBJECT (account), "enabled");
619 }
620
621 McAccount *
622 _empathy_account_get_mc_account (EmpathyAccount *account)
623 {
624   EmpathyAccountPriv *priv = GET_PRIV (account);
625
626   return priv->mc_account;
627 }