Fixes: NB#247133 - Skype contacts should not get displayed in contact list when the...
[qtcontacts-tracker:jensg-contactsd.git] / tests / libtelepathy / simple-account.c
1 /*
2  * simple-account.c - a simple account service.
3  *
4  * Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
5  *
6  * Copying and distribution of this file, with or without modification,
7  * are permitted in any medium without royalty provided the copyright
8  * notice and this notice are preserved.
9  */
10
11 #include "simple-account.h"
12
13 #include <telepathy-glib/connection.h>
14 #include <telepathy-glib/contact.h>
15 #include <telepathy-glib/dbus.h>
16 #include <telepathy-glib/defs.h>
17 #include <telepathy-glib/enums.h>
18 #include <telepathy-glib/gtypes.h>
19 #include <telepathy-glib/interfaces.h>
20 #include <telepathy-glib/util.h>
21 #include <telepathy-glib/svc-generic.h>
22 #include <telepathy-glib/svc-account.h>
23
24 static void account_iface_init (gpointer, gpointer);
25
26 G_DEFINE_TYPE_WITH_CODE (TpTestsSimpleAccount,
27     tp_tests_simple_account,
28     G_TYPE_OBJECT,
29     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_ACCOUNT,
30         account_iface_init);
31     G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
32         tp_dbus_properties_mixin_iface_init)
33     )
34
35 /* TP_IFACE_ACCOUNT is implied */
36 static const char *ACCOUNT_INTERFACES[] = { NULL };
37
38 enum
39 {
40   PROP_0,
41   PROP_INTERFACES,
42   PROP_DISPLAY_NAME,
43   PROP_ICON,
44   PROP_VALID,
45   PROP_ENABLED,
46   PROP_NICKNAME,
47   PROP_PARAMETERS,
48   PROP_AUTOMATIC_PRESENCE,
49   PROP_CONNECT_AUTO,
50   PROP_CONNECTION,
51   PROP_CONNECTION_STATUS,
52   PROP_CONNECTION_STATUS_REASON,
53   PROP_CURRENT_PRESENCE,
54   PROP_REQUESTED_PRESENCE,
55   PROP_NORMALIZED_NAME,
56   PROP_HAS_BEEN_ONLINE,
57 };
58
59 struct _TpTestsSimpleAccountPrivate
60 {
61   TpConnection *connection;
62   TpConnectionStatus connection_status;
63   TpConnectionStatusReason connection_status_reason;
64   gboolean has_been_online;
65   gboolean enabled;
66
67   GHashTable *parameters;
68
69   TpContact *self_contact;
70   gchar *nickname;
71   gchar *normalized_name;
72   GValueArray *current_presence;
73 };
74
75 static void connection_invalidated_cb (TpProxy *proxy, guint domain, gint code,
76     gchar *message, TpTestsSimpleAccount *self);
77
78 static void
79 account_iface_init (gpointer klass,
80     gpointer unused G_GNUC_UNUSED)
81 {
82 #define IMPLEMENT(x) tp_svc_account_implement_##x (\
83   klass, tp_tests_simple_account_##x)
84   /* TODO */
85 #undef IMPLEMENT
86 }
87
88
89 static void
90 tp_tests_simple_account_init (TpTestsSimpleAccount *self)
91 {
92   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, TP_TESTS_TYPE_SIMPLE_ACCOUNT,
93       TpTestsSimpleAccountPrivate);
94
95   self->priv->connection_status = TP_CONNECTION_STATUS_DISCONNECTED;
96   self->priv->connection_status_reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
97   self->priv->has_been_online = FALSE;
98   self->priv->enabled = TRUE;
99
100   self->priv->parameters = g_hash_table_new (NULL, NULL);
101
102   self->priv->nickname = g_strdup ("");
103   self->priv->normalized_name = g_strdup ("");
104   self->priv->current_presence = tp_value_array_build (3,
105       G_TYPE_UINT, TP_CONNECTION_PRESENCE_TYPE_OFFLINE,
106       G_TYPE_STRING, "offline",
107       G_TYPE_STRING, "",
108       G_TYPE_INVALID);
109 }
110
111 static void
112 tp_tests_simple_account_get_property (GObject *object,
113               guint property_id,
114               GValue *value,
115               GParamSpec *spec)
116 {
117   TpTestsSimpleAccount *self = TP_TESTS_SIMPLE_ACCOUNT (object);
118   GValueArray *offline_presence;
119
120   offline_presence = tp_value_array_build (3,
121       G_TYPE_UINT, TP_CONNECTION_PRESENCE_TYPE_OFFLINE,
122       G_TYPE_STRING, "offline",
123       G_TYPE_STRING, "",
124       G_TYPE_INVALID);
125
126   switch (property_id) {
127     case PROP_INTERFACES:
128       g_value_set_boxed (value, ACCOUNT_INTERFACES);
129       break;
130     case PROP_DISPLAY_NAME:
131       g_value_set_string (value, "Fake Account");
132       break;
133     case PROP_ICON:
134       g_value_set_string (value, "");
135       break;
136     case PROP_VALID:
137       g_value_set_boolean (value, TRUE);
138       break;
139     case PROP_ENABLED:
140       g_value_set_boolean (value, self->priv->enabled);
141       break;
142     case PROP_NICKNAME:
143       g_value_set_string (value, self->priv->nickname);
144       break;
145     case PROP_PARAMETERS:
146       g_value_set_boxed (value, self->priv->parameters);
147       break;
148     case PROP_AUTOMATIC_PRESENCE:
149       g_value_set_boxed (value, offline_presence);
150       break;
151     case PROP_CONNECT_AUTO:
152       g_value_set_boolean (value, FALSE);
153       break;
154     case PROP_CONNECTION:
155       if (self->priv->connection != NULL)
156         g_value_set_boxed (value, tp_proxy_get_object_path (self->priv->connection));
157       else
158         g_value_set_boxed (value, "/");
159       break;
160     case PROP_CONNECTION_STATUS:
161       g_value_set_uint (value, self->priv->connection_status);
162       break;
163     case PROP_CONNECTION_STATUS_REASON:
164       g_value_set_uint (value, self->priv->connection_status_reason);
165       break;
166     case PROP_CURRENT_PRESENCE:
167       g_value_set_boxed (value, self->priv->current_presence);
168       break;
169     case PROP_REQUESTED_PRESENCE:
170       g_value_set_boxed (value, offline_presence);
171       break;
172     case PROP_NORMALIZED_NAME:
173       g_value_set_string (value, self->priv->normalized_name);
174       break;
175     case PROP_HAS_BEEN_ONLINE:
176       g_value_set_boolean (value, self->priv->has_been_online);
177       break;
178     default:
179       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
180       break;
181   }
182
183   g_boxed_free (TP_STRUCT_TYPE_SIMPLE_PRESENCE, offline_presence);
184 }
185
186 static void
187 tp_tests_simple_account_set_property (GObject *object,
188               guint property_id,
189               const GValue *value,
190               GParamSpec *spec)
191 {
192   TpTestsSimpleAccount *self = TP_TESTS_SIMPLE_ACCOUNT (object);
193
194   switch (property_id) {
195     case PROP_PARAMETERS:
196       if (g_value_get_boxed (value) != NULL)
197         {
198           if (self->priv->parameters)
199             g_hash_table_unref (self->priv->parameters);
200           self->priv->parameters = g_value_dup_boxed (value);
201         }
202       else
203         {
204           g_hash_table_remove_all (self->priv->parameters);
205         }
206       break;
207     default:
208       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
209       break;
210   }
211 }
212
213 static void
214 tp_tests_simple_account_finalize (GObject *object)
215 {
216   TpTestsSimpleAccount *self = TP_TESTS_SIMPLE_ACCOUNT (object);
217
218   if (self->priv->connection)
219     {
220       g_signal_handlers_disconnect_by_func (self->priv->connection,
221           connection_invalidated_cb, self);
222       g_object_unref (self->priv->connection);
223     }
224
225   if (self->priv->parameters)
226     g_hash_table_unref (self->priv->parameters);
227
228   if (self->priv->self_contact != NULL)
229     g_object_unref (self->priv->self_contact);
230
231   g_free (self->priv->nickname);
232   g_free (self->priv->normalized_name);
233   g_value_array_free (self->priv->current_presence);
234
235   G_OBJECT_CLASS (tp_tests_simple_account_parent_class)->finalize(object);
236 }
237
238 /**
239   * This class currently only provides the minimum for
240   * tp_account_prepare to succeed. This turns out to be only a working
241   * Properties.GetAll().
242   */
243 static void
244 tp_tests_simple_account_class_init (TpTestsSimpleAccountClass *klass)
245 {
246   GObjectClass *object_class = (GObjectClass *) klass;
247   GParamSpec *param_spec;
248
249   static TpDBusPropertiesMixinPropImpl a_props[] = {
250         { "Interfaces", "interfaces", NULL },
251         { "DisplayName", "display-name", NULL },
252         { "Icon", "icon", NULL },
253         { "Valid", "valid", NULL },
254         { "Enabled", "enabled", NULL },
255         { "Nickname", "nickname", NULL },
256         { "Parameters", "parameters", NULL },
257         { "AutomaticPresence", "automatic-presence", NULL },
258         { "ConnectAutomatically", "connect-automatically", NULL },
259         { "Connection", "connection", NULL },
260         { "ConnectionStatus", "connection-status", NULL },
261         { "ConnectionStatusReason", "connection-status-reason", NULL },
262         { "CurrentPresence", "current-presence", NULL },
263         { "RequestedPresence", "requested-presence", NULL },
264         { "NormalizedName", "normalized-name", NULL },
265         { "HasBeenOnline", "has-been-online", NULL },
266         { NULL }
267   };
268
269   static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
270         { TP_IFACE_ACCOUNT,
271           tp_dbus_properties_mixin_getter_gobject_properties,
272           NULL,
273           a_props
274         },
275         { NULL },
276   };
277
278   g_type_class_add_private (klass, sizeof (TpTestsSimpleAccountPrivate));
279   object_class->set_property = tp_tests_simple_account_set_property;
280   object_class->get_property = tp_tests_simple_account_get_property;
281   object_class->finalize = tp_tests_simple_account_finalize;
282
283   param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
284       "In this case we only implement Account, so none.",
285       G_TYPE_STRV,
286       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
287   g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
288
289   param_spec = g_param_spec_string ("display-name", "display name",
290       "DisplayName property",
291       NULL,
292       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
293   g_object_class_install_property (object_class, PROP_DISPLAY_NAME, param_spec);
294
295   param_spec = g_param_spec_string ("icon", "icon",
296       "Icon property",
297       NULL,
298       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
299   g_object_class_install_property (object_class, PROP_ICON, param_spec);
300
301   param_spec = g_param_spec_boolean ("valid", "valid",
302       "Valid property",
303       FALSE,
304       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
305   g_object_class_install_property (object_class, PROP_VALID, param_spec);
306
307   param_spec = g_param_spec_boolean ("enabled", "enabled",
308       "Enabled property",
309       FALSE,
310       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
311   g_object_class_install_property (object_class, PROP_ENABLED, param_spec);
312
313   param_spec = g_param_spec_string ("nickname", "nickname",
314       "Nickname property",
315       NULL,
316       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
317   g_object_class_install_property (object_class, PROP_NICKNAME, param_spec);
318
319   param_spec = g_param_spec_boxed ("parameters", "parameters",
320       "Parameters property",
321       TP_HASH_TYPE_STRING_VARIANT_MAP,
322       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
323   g_object_class_install_property (object_class, PROP_PARAMETERS, param_spec);
324
325   param_spec = g_param_spec_boxed ("automatic-presence", "automatic presence",
326       "AutomaticPresence property",
327       TP_STRUCT_TYPE_SIMPLE_PRESENCE,
328       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
329   g_object_class_install_property (object_class, PROP_AUTOMATIC_PRESENCE,
330       param_spec);
331
332   param_spec = g_param_spec_boolean ("connect-automatically",
333       "connect automatically", "ConnectAutomatically property",
334       FALSE,
335       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
336   g_object_class_install_property (object_class, PROP_CONNECT_AUTO, param_spec);
337
338   param_spec = g_param_spec_boxed ("connection", "connection",
339       "Connection property",
340       DBUS_TYPE_G_OBJECT_PATH,
341       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
342   g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
343
344   param_spec = g_param_spec_uint ("connection-status", "connection status",
345       "ConnectionStatus property",
346       0, NUM_TP_CONNECTION_STATUSES, TP_CONNECTION_STATUS_DISCONNECTED,
347       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
348   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS,
349       param_spec);
350
351   param_spec = g_param_spec_uint ("connection-status-reason",
352       "connection status reason", "ConnectionStatusReason property",
353       0, NUM_TP_CONNECTION_STATUS_REASONS,
354       TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
355       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
356   g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON,
357       param_spec);
358
359   param_spec = g_param_spec_boxed ("current-presence", "current presence",
360       "CurrentPresence property",
361       TP_STRUCT_TYPE_SIMPLE_PRESENCE,
362       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
363   g_object_class_install_property (object_class, PROP_CURRENT_PRESENCE,
364       param_spec);
365
366   param_spec = g_param_spec_boxed ("requested-presence", "requested presence",
367       "RequestedPresence property",
368       TP_STRUCT_TYPE_SIMPLE_PRESENCE,
369       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
370   g_object_class_install_property (object_class, PROP_REQUESTED_PRESENCE,
371       param_spec);
372
373   param_spec = g_param_spec_string ("normalized-name", "normalized name",
374       "NormalizedName property",
375       NULL,
376       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
377   g_object_class_install_property (object_class, PROP_NORMALIZED_NAME,
378       param_spec);
379
380   param_spec = g_param_spec_boolean ("has-been-online", "has been online",
381       "HasBeenOnline property",
382       FALSE,
383       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
384   g_object_class_install_property (object_class, PROP_HAS_BEEN_ONLINE,
385       param_spec);
386
387   klass->dbus_props_class.interfaces = prop_interfaces;
388   tp_dbus_properties_mixin_class_init (object_class,
389       G_STRUCT_OFFSET (TpTestsSimpleAccountClass, dbus_props_class));
390 }
391
392 static void
393 remove_connection (TpTestsSimpleAccount *self)
394 {
395   GHashTable *change;
396
397   self->priv->connection_status = tp_connection_get_status (self->priv->connection,
398       &self->priv->connection_status_reason);
399
400   g_signal_handlers_disconnect_by_func (self->priv->connection,
401       connection_invalidated_cb, self);
402   g_object_unref (self->priv->connection);
403   self->priv->connection = NULL;
404
405   if (self->priv->self_contact != NULL)
406     {
407       g_object_unref (self->priv->self_contact);
408       self->priv->self_contact = NULL;
409     }
410
411   g_value_array_free (self->priv->current_presence);
412   self->priv->current_presence = tp_value_array_build (3,
413       G_TYPE_UINT, TP_CONNECTION_PRESENCE_TYPE_OFFLINE,
414       G_TYPE_STRING, "offline",
415       G_TYPE_STRING, "",
416       G_TYPE_INVALID);
417
418   change = tp_asv_new (NULL, NULL);
419   tp_asv_set_object_path (change, "Connection", "/");
420   tp_asv_set_uint32 (change, "ConnectionStatus", self->priv->connection_status);
421   tp_asv_set_uint32 (change, "ConnectionStatusReason", self->priv->connection_status_reason);
422   tp_asv_set_boxed (change, "CurrentPresence", TP_STRUCT_TYPE_SIMPLE_PRESENCE, self->priv->current_presence);
423   tp_svc_account_emit_account_property_changed (self, change);
424   g_hash_table_unref (change);
425 }
426
427 static void
428 connection_invalidated_cb (TpProxy *proxy,
429     guint domain,
430     gint code,
431     gchar *message,
432     TpTestsSimpleAccount *self)
433 {
434   remove_connection (self);
435 }
436
437 static void
438 on_alias_notify_cb (TpContact *self_contact,
439     GParamSpec *pspec,
440     TpTestsSimpleAccount *self)
441 {
442   GHashTable *change;
443
444   g_free (self->priv->nickname);
445   self->priv->nickname = g_strdup (tp_contact_get_alias (self->priv->self_contact));
446
447   change = tp_asv_new (NULL, NULL);
448   tp_asv_set_string (change, "Nickname", self->priv->nickname);
449   tp_svc_account_emit_account_property_changed (self, change);
450   g_hash_table_unref (change);
451 }
452
453 static void
454 on_presence_changed_cb (TpContact *self_contact,
455     guint type,
456     gchar *status,
457     gchar *message,
458     TpTestsSimpleAccount *self)
459 {
460   GHashTable *change;
461
462   g_value_array_free (self->priv->current_presence);
463   self->priv->current_presence = tp_value_array_build (3,
464       G_TYPE_UINT, tp_contact_get_presence_type (self->priv->self_contact),
465       G_TYPE_STRING, tp_contact_get_presence_status (self->priv->self_contact),
466       G_TYPE_STRING, tp_contact_get_presence_message (self->priv->self_contact),
467       G_TYPE_INVALID);
468
469   change = tp_asv_new (NULL, NULL);
470   tp_asv_set_boxed (change, "CurrentPresence", TP_STRUCT_TYPE_SIMPLE_PRESENCE, self->priv->current_presence);
471   tp_svc_account_emit_account_property_changed (self, change);
472   g_hash_table_unref (change);
473 }
474
475 static void
476 got_self_contact_cb (TpConnection *connection,
477     guint n_contacts,
478     TpContact * const *contacts,
479     guint n_failed,
480     const TpHandle *failed,
481     const GError *error,
482     gpointer user_data,
483     GObject *weak_object)
484 {
485   TpTestsSimpleAccount *self = user_data;
486   GHashTable *change;
487
488   if (n_failed != 0)
489     return;
490
491   self->priv->self_contact = g_object_ref (contacts[0]);
492   self->priv->connection_status = tp_connection_get_status (self->priv->connection,
493       &self->priv->connection_status_reason);
494   self->priv->has_been_online = TRUE;
495
496   g_free (self->priv->normalized_name);
497   self->priv->normalized_name = g_strdup (tp_contact_get_identifier (self->priv->self_contact));
498
499   g_free (self->priv->nickname);
500   self->priv->nickname = g_strdup (tp_contact_get_alias (self->priv->self_contact));
501   g_signal_connect (self->priv->self_contact, "notify::alias",
502       G_CALLBACK (on_alias_notify_cb), self);
503
504   g_value_array_free (self->priv->current_presence);
505   self->priv->current_presence = tp_value_array_build (3,
506       G_TYPE_UINT, tp_contact_get_presence_type (self->priv->self_contact),
507       G_TYPE_STRING, tp_contact_get_presence_status (self->priv->self_contact),
508       G_TYPE_STRING, tp_contact_get_presence_message (self->priv->self_contact),
509       G_TYPE_INVALID);
510   g_signal_connect (self->priv->self_contact, "presence-changed",
511       G_CALLBACK (on_presence_changed_cb), self);
512
513   change = tp_asv_new (NULL, NULL);
514   tp_asv_set_object_path (change, "Connection", tp_proxy_get_object_path (self->priv->connection));
515   tp_asv_set_uint32 (change, "ConnectionStatus", self->priv->connection_status);
516   tp_asv_set_uint32 (change, "ConnectionStatusReason", self->priv->connection_status_reason);
517   tp_asv_set_boolean (change, "HasBeenOnline", self->priv->has_been_online);
518   tp_asv_set_boxed (change, "CurrentPresence", TP_STRUCT_TYPE_SIMPLE_PRESENCE, self->priv->current_presence);
519   tp_asv_set_string (change, "Nickname", self->priv->nickname);
520   tp_asv_set_string (change, "NormalizedName", self->priv->normalized_name);
521   tp_svc_account_emit_account_property_changed (self, change);
522   g_hash_table_unref (change);
523 }
524
525 static void
526 connection_ready_cb (TpConnection *connection,
527     const GError *error,
528     gpointer user_data)
529 {
530   TpTestsSimpleAccount *self = user_data;
531   TpHandle self_handle;
532   TpContactFeature features[] = { TP_CONTACT_FEATURE_ALIAS, TP_CONTACT_FEATURE_PRESENCE };
533
534   if (error != NULL)
535     return;
536
537   self_handle = tp_connection_get_self_handle (self->priv->connection);
538   tp_connection_get_contacts_by_handle (self->priv->connection,
539       1, &self_handle, G_N_ELEMENTS (features), features,
540       got_self_contact_cb, self, NULL, G_OBJECT (self));
541 }
542
543 void
544 tp_tests_simple_account_set_connection (TpTestsSimpleAccount *self,
545     const gchar *object_path)
546 {
547   if (self->priv->connection != NULL)
548     remove_connection (self);
549
550   if (object_path != NULL && tp_strdiff (object_path, "/"))
551     {
552       TpDBusDaemon *dbus = tp_dbus_daemon_dup (NULL);
553       self->priv->connection = tp_connection_new (dbus, NULL, object_path, NULL);
554       g_signal_connect (self->priv->connection, "invalidated",
555           G_CALLBACK (connection_invalidated_cb), self);
556       tp_connection_call_when_ready (self->priv->connection,
557           connection_ready_cb, self);
558       g_object_unref (dbus);
559     }
560 }
561
562 void
563 tp_tests_simple_account_removed (TpTestsSimpleAccount *self)
564 {
565   tp_svc_account_emit_removed (self);
566 }
567
568 void
569 tp_tests_simple_account_set_enabled (TpTestsSimpleAccount *self, gboolean enabled)
570 {
571   GHashTable *change;
572   self->priv->enabled = enabled;
573   change = tp_asv_new (NULL, NULL);
574   tp_asv_set_boolean (change, "Enabled", enabled);
575   tp_svc_account_emit_account_property_changed(self, change);
576   g_hash_table_unref (change);
577 }