]> git.0d.be Git - empathy.git/blob - libempathy/empathy-account.c
explain the connect_time struct member
[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 };
77
78 #define GET_PRIV(obj)  EMPATHY_GET_PRIV (obj, EmpathyAccount)
79
80 static void
81 empathy_account_init (EmpathyAccount *obj)
82 {
83   EmpathyAccountPriv *priv;
84
85   priv =  G_TYPE_INSTANCE_GET_PRIVATE (obj,
86     EMPATHY_TYPE_ACCOUNT, EmpathyAccountPriv);
87
88   obj->priv = priv;
89
90   priv->status = TP_CONNECTION_STATUS_DISCONNECTED;
91 }
92
93 static void
94 empathy_account_get_property (GObject *object,
95     guint prop_id,
96     GValue *value,
97     GParamSpec *pspec)
98 {
99   EmpathyAccount *account = EMPATHY_ACCOUNT (object);
100   EmpathyAccountPriv *priv = GET_PRIV (account);
101
102   switch (prop_id)
103     {
104       case PROP_ENABLED:
105         g_value_set_boolean (value, priv->enabled);
106         break;
107       case PROP_PRESENCE:
108         g_value_set_uint (value, priv->presence);
109         break;
110       case PROP_CONNECTION_STATUS:
111         g_value_set_uint (value, priv->status);
112         break;
113       case PROP_CONNECTION_STATUS_REASON:
114         g_value_set_uint (value, priv->reason);
115         break;
116       case PROP_CONNECTION:
117         g_value_set_object (value,
118             empathy_account_get_connection (account));
119         break;
120       case PROP_UNIQUE_NAME:
121         g_value_set_string (value,
122             empathy_account_get_unique_name (account));
123         break;
124       case PROP_DISPLAY_NAME:
125         g_value_set_string (value,
126             empathy_account_get_display_name (account));
127         break;
128       default:
129         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
130         break;
131     }
132 }
133
134 static void empathy_account_dispose (GObject *object);
135 static void empathy_account_finalize (GObject *object);
136
137 static void
138 empathy_account_class_init (EmpathyAccountClass *empathy_account_class)
139 {
140   GObjectClass *object_class = G_OBJECT_CLASS (empathy_account_class);
141
142   g_type_class_add_private (empathy_account_class,
143     sizeof (EmpathyAccountPriv));
144
145   object_class->get_property = empathy_account_get_property;
146   object_class->dispose = empathy_account_dispose;
147   object_class->finalize = empathy_account_finalize;
148
149   g_object_class_install_property (object_class, PROP_ENABLED,
150     g_param_spec_boolean ("enabled",
151       "Enabled",
152       "Whether this account is enabled or not",
153       FALSE,
154       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
155
156   g_object_class_install_property (object_class, PROP_PRESENCE,
157     g_param_spec_uint ("presence",
158       "Presence",
159       "The account connections presence type",
160       0,
161       NUM_TP_CONNECTION_PRESENCE_TYPES,
162       TP_CONNECTION_PRESENCE_TYPE_UNSET,
163       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
164
165   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS,
166     g_param_spec_uint ("status",
167       "ConnectionStatus",
168       "The accounts connections status type",
169       0,
170       NUM_TP_CONNECTION_STATUSES,
171       TP_CONNECTION_STATUS_DISCONNECTED,
172       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
173
174   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON,
175     g_param_spec_uint ("status-reason",
176       "ConnectionStatusReason",
177       "The account connections status reason",
178       0,
179       NUM_TP_CONNECTION_STATUS_REASONS,
180       TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
181       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
182
183   g_object_class_install_property (object_class, PROP_CONNECTION,
184     g_param_spec_object ("connection",
185       "Connection",
186       "The accounts connection",
187       TP_TYPE_CONNECTION,
188       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
189
190   g_object_class_install_property (object_class, PROP_UNIQUE_NAME,
191     g_param_spec_string ("unique-name",
192       "UniqueName",
193       "The accounts unique name",
194       NULL,
195       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
196
197   g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
198     g_param_spec_string ("display-name",
199       "DisplayName",
200       "The accounts display name",
201       NULL,
202       G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
203
204   signals[STATUS_CHANGED] = g_signal_new ("status-changed",
205     G_TYPE_FROM_CLASS (object_class),
206     G_SIGNAL_RUN_LAST,
207     0, NULL, NULL,
208     _empathy_marshal_VOID__UINT_UINT_UINT,
209     G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
210
211   signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed",
212     G_TYPE_FROM_CLASS (object_class),
213     G_SIGNAL_RUN_LAST,
214     0, NULL, NULL,
215     _empathy_marshal_VOID__UINT_UINT,
216     G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
217 }
218
219 void
220 empathy_account_dispose (GObject *object)
221 {
222   EmpathyAccount *self = EMPATHY_ACCOUNT (object);
223   EmpathyAccountPriv *priv = GET_PRIV (self);
224
225   if (priv->dispose_has_run)
226     return;
227
228   priv->dispose_has_run = TRUE;
229
230   if (priv->connection_invalidated_id != 0)
231     g_signal_handler_disconnect (priv->connection,
232         priv->connection_invalidated_id);
233   priv->connection_invalidated_id = 0;
234
235   if (priv->connection != NULL)
236     g_object_unref (priv->connection);
237   priv->connection = NULL;
238
239   /* release any references held by the object here */
240   if (G_OBJECT_CLASS (empathy_account_parent_class)->dispose != NULL)
241     G_OBJECT_CLASS (empathy_account_parent_class)->dispose (object);
242 }
243
244 void
245 empathy_account_finalize (GObject *object)
246 {
247   /* free any data held directly by the object here */
248   if (G_OBJECT_CLASS (empathy_account_parent_class)->finalize != NULL)
249     G_OBJECT_CLASS (empathy_account_parent_class)->finalize (object);
250 }
251
252 gboolean
253 empathy_account_is_just_connected (EmpathyAccount *account)
254 {
255   EmpathyAccountPriv *priv = GET_PRIV (account);
256   GTimeVal val;
257
258   if (priv->status != TP_CONNECTION_STATUS_CONNECTED)
259     return FALSE;
260
261   g_get_current_time (&val);
262
263   return (val.tv_sec - priv->connect_time) < 10;
264 }
265
266 /**
267  * empathy_account_get_connection:
268  * @account: a #EmpathyAccount
269  *
270  * Get the connection of the account, or NULL if account is offline or the
271  * connection is not yet ready. This function does not return a new ref.
272  *
273  * Returns: the connection of the account.
274  **/
275 TpConnection *
276 empathy_account_get_connection (EmpathyAccount *account)
277 {
278   EmpathyAccountPriv *priv = GET_PRIV (account);
279
280   if (priv->connection != NULL &&
281       tp_connection_is_ready (priv->connection))
282     return priv->connection;
283
284   return NULL;
285 }
286
287 /**
288  * empathy_account_get_unique_name:
289  * @account: a #EmpathyAccount
290  *
291  * Returns: the unique name of the account.
292  **/
293 const gchar *
294 empathy_account_get_unique_name (EmpathyAccount *account)
295 {
296   EmpathyAccountPriv *priv = GET_PRIV (account);
297
298   return mc_account_get_unique_name (priv->mc_account);
299 }
300
301 /**
302  * empathy_account_get_display_name:
303  * @account: a #EmpathyAccount
304  *
305  * Returns: the display name of the account.
306  **/
307 const gchar *
308 empathy_account_get_display_name (EmpathyAccount *account)
309 {
310   EmpathyAccountPriv *priv = GET_PRIV (account);
311
312   return mc_account_get_display_name (priv->mc_account);
313 }
314
315 gboolean
316 empathy_account_is_valid (EmpathyAccount *account)
317 {
318   EmpathyAccountPriv *priv = GET_PRIV (account);
319
320   return mc_account_is_complete (priv->mc_account);
321 }
322
323 void
324 empathy_account_set_enabled (EmpathyAccount *account, gboolean enabled)
325 {
326   EmpathyAccountPriv *priv = GET_PRIV (account);
327
328   mc_account_set_enabled (priv->mc_account, enabled);
329 }
330
331 gboolean
332 empathy_account_is_enabled (EmpathyAccount *account)
333 {
334   EmpathyAccountPriv *priv = GET_PRIV (account);
335
336   return priv->enabled;
337 }
338
339 void
340 empathy_account_unset_param (EmpathyAccount *account, const gchar *param)
341 {
342   EmpathyAccountPriv *priv = GET_PRIV (account);
343
344   mc_account_unset_param (priv->mc_account, param);
345 }
346
347 gchar *
348 empathy_account_get_param_string (EmpathyAccount *account, const gchar *param)
349 {
350   EmpathyAccountPriv *priv = GET_PRIV (account);
351   gchar *value = NULL;
352
353   mc_account_get_param_string (priv->mc_account, param, &value);
354   return value;
355 }
356
357 gint
358 empathy_account_get_param_int (EmpathyAccount *account, const gchar *param)
359 {
360   EmpathyAccountPriv *priv = GET_PRIV (account);
361   int value;
362
363   mc_account_get_param_int (priv->mc_account, param, &value);
364   return value;
365 }
366
367 gboolean
368 empathy_account_get_param_boolean (EmpathyAccount *account, const gchar *param)
369 {
370   EmpathyAccountPriv *priv = GET_PRIV (account);
371   gboolean value;
372
373   mc_account_get_param_boolean (priv->mc_account, param, &value);
374   return value;
375 }
376
377 void
378 empathy_account_set_param_string (EmpathyAccount *account,
379   const gchar *param,
380   const gchar *value)
381 {
382   EmpathyAccountPriv *priv = GET_PRIV (account);
383   mc_account_set_param_string (priv->mc_account, param, value);
384 }
385
386 void
387 empathy_account_set_param_int (EmpathyAccount *account,
388   const gchar *param,
389   gint value)
390 {
391   EmpathyAccountPriv *priv = GET_PRIV (account);
392   mc_account_set_param_int (priv->mc_account, param, value);
393 }
394
395 void
396 empathy_account_set_param_boolean (EmpathyAccount *account,
397   const gchar *param,
398   gboolean value)
399 {
400   EmpathyAccountPriv *priv = GET_PRIV (account);
401   mc_account_set_param_boolean (priv->mc_account, param, value);
402 }
403
404 void
405 empathy_account_set_display_name (EmpathyAccount *account,
406     const gchar *display_name)
407 {
408   EmpathyAccountPriv *priv = GET_PRIV (account);
409   mc_account_set_display_name (priv->mc_account, display_name);
410 }
411
412 McProfile *
413 empathy_account_get_profile (EmpathyAccount *account)
414 {
415   EmpathyAccountPriv *priv = GET_PRIV (account);
416   return mc_account_get_profile (priv->mc_account);
417 }
418
419 EmpathyAccount *
420 _empathy_account_new (McAccount *mc_account)
421 {
422   EmpathyAccount *account;
423   EmpathyAccountPriv *priv;
424
425   account = g_object_new (EMPATHY_TYPE_ACCOUNT, NULL);
426   priv = GET_PRIV (account);
427   priv->mc_account = mc_account;
428
429   return account;
430 }
431
432 void
433 _empathy_account_set_status (EmpathyAccount *account,
434     TpConnectionStatus status,
435     TpConnectionStatusReason reason,
436     TpConnectionPresenceType presence)
437 {
438   EmpathyAccountPriv *priv = GET_PRIV (account);
439   TpConnectionStatus old_s = priv->status;
440   TpConnectionPresenceType old_p = priv->presence;
441
442   priv->status = status;
443   priv->presence = presence;
444
445   if (priv->status != old_s)
446     {
447       if (priv->status == TP_CONNECTION_STATUS_CONNECTED)
448         {
449           GTimeVal val;
450           g_get_current_time (&val);
451
452           priv->connect_time = val.tv_sec;
453         }
454
455       priv->reason = reason;
456       g_signal_emit (account, signals[STATUS_CHANGED], 0,
457         old_s, priv->status, reason);
458
459       g_object_notify (G_OBJECT (account), "status");
460     }
461
462   if (priv->presence != old_p)
463     {
464       g_signal_emit (account, signals[PRESENCE_CHANGED], 0,
465         old_p, priv->presence);
466       g_object_notify (G_OBJECT (account), "presence");
467     }
468 }
469
470 static void
471 empathy_account_connection_ready_cb (TpConnection *connection,
472     const GError *error,
473     gpointer user_data)
474 {
475   EmpathyAccount *account = EMPATHY_ACCOUNT (user_data);
476   EmpathyAccountPriv *priv = GET_PRIV (account);
477
478   if (error != NULL)
479     {
480       DEBUG ("(%s) Connection failed to become ready: %s",
481         empathy_account_get_unique_name (account), error->message);
482       priv->connection = NULL;
483     }
484   else
485     {
486       DEBUG ("(%s) Connection ready",
487         empathy_account_get_unique_name (account));
488       g_object_notify (G_OBJECT (account), "connection");
489     }
490 }
491
492 static void
493 _empathy_account_connection_invalidated_cb (TpProxy *self,
494   guint    domain,
495   gint     code,
496   gchar   *message,
497   gpointer user_data)
498 {
499   EmpathyAccount *account = EMPATHY_ACCOUNT (user_data);
500   EmpathyAccountPriv *priv = GET_PRIV (account);
501
502   if (priv->connection == NULL)
503     return;
504
505   DEBUG ("(%s) Connection invalidated",
506     empathy_account_get_unique_name (account));
507
508   g_assert (priv->connection == TP_CONNECTION (self));
509
510   g_signal_handler_disconnect (priv->connection,
511     priv->connection_invalidated_id);
512   priv->connection_invalidated_id = 0;
513
514   g_object_unref (priv->connection);
515   priv->connection = NULL;
516
517   g_object_notify (G_OBJECT (account), "connection");
518 }
519
520 void
521 _empathy_account_set_connection (EmpathyAccount *account,
522     TpConnection *connection)
523 {
524   EmpathyAccountPriv *priv = GET_PRIV (account);
525
526   if (priv->connection == connection)
527     return;
528
529   /* Connection already set, don't set the new one */
530   if (connection != NULL && priv->connection != NULL)
531     return;
532
533   if (connection == NULL)
534     {
535       g_signal_handler_disconnect (priv->connection,
536         priv->connection_invalidated_id);
537       priv->connection_invalidated_id = 0;
538
539       g_object_unref (priv->connection);
540       priv->connection = NULL;
541       g_object_notify (G_OBJECT (account), "connection");
542     }
543   else
544     {
545       priv->connection = g_object_ref (connection);
546       priv->connection_invalidated_id = g_signal_connect (priv->connection,
547           "invalidated",
548           G_CALLBACK (_empathy_account_connection_invalidated_cb),
549           account);
550
551       tp_connection_call_when_ready (priv->connection,
552         empathy_account_connection_ready_cb, account);
553     }
554 }
555
556 void
557 _empathy_account_set_enabled (EmpathyAccount *account,
558     gboolean enabled)
559 {
560   EmpathyAccountPriv *priv = GET_PRIV (account);
561
562   if (priv->enabled == enabled)
563     return;
564
565   priv->enabled = enabled;
566   g_object_notify (G_OBJECT (account), "enabled");
567 }
568
569 McAccount *
570 _empathy_account_get_mc_account (EmpathyAccount *account)
571 {
572   EmpathyAccountPriv *priv = GET_PRIV (account);
573   return priv->mc_account;
574 }