1 /*
2 * /dev/null as a text channel
3 *
4 * Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
5 * Copyright (C) 2008 Nokia Corporation
6 *
7 * Copying and distribution of this file, with or without modification,
8 * are permitted in any medium without royalty provided the copyright
9 * notice and this notice are preserved.
10 */
11
12 #include "config.h"
13
14 #include "textchan-null.h"
15
16 #include <telepathy-glib/base-connection.h>
17 #include <telepathy-glib/channel-iface.h>
18 #include <telepathy-glib/dbus.h>
19 #include <telepathy-glib/dbus-properties-mixin.h>
20 #include <telepathy-glib/interfaces.h>
21 #include <telepathy-glib/svc-channel.h>
22 #include <telepathy-glib/svc-generic.h>
23
24 /* This is for text-mixin unit tests, others should be using ExampleEcho2Channel
25 * which uses newer TpMessageMixin */
26 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
27
28 static void text_iface_init (gpointer iface, gpointer data);
29 static void channel_iface_init (gpointer iface, gpointer data);
30
31 G_DEFINE_TYPE_WITH_CODE (TpTestsTextChannelNull,
32 tp_tests_text_channel_null,
33 G_TYPE_OBJECT,
34 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL, channel_iface_init);
35 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, text_iface_init);
36 G_IMPLEMENT_INTERFACE (TP_TYPE_CHANNEL_IFACE, NULL))
37
38 G_DEFINE_TYPE_WITH_CODE (TpTestsPropsTextChannel,
39 tp_tests_props_text_channel,
40 TP_TESTS_TYPE_TEXT_CHANNEL_NULL,
41 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
42 tp_dbus_properties_mixin_iface_init))
43
44 G_DEFINE_TYPE_WITH_CODE (TpTestsPropsGroupTextChannel,
45 tp_tests_props_group_text_channel,
46 TP_TESTS_TYPE_PROPS_TEXT_CHANNEL,
47 G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_GROUP,
48 tp_group_mixin_iface_init))
49
50 static const char *tp_tests_text_channel_null_interfaces[] = { NULL };
51
52 /* type definition stuff */
53
54 enum
55 {
56 PROP_OBJECT_PATH = 1,
57 PROP_CHANNEL_TYPE,
58 PROP_HANDLE_TYPE,
59 PROP_HANDLE,
60 PROP_TARGET_ID,
61 PROP_CONNECTION,
62 PROP_INTERFACES,
63 PROP_REQUESTED,
64 PROP_INITIATOR_HANDLE,
65 PROP_INITIATOR_ID,
66 N_PROPS
67 };
68
69 struct _TpTestsTextChannelNullPrivate
70 {
71 TpBaseConnection *conn;
72 gchar *object_path;
73 TpHandle handle;
74
75 unsigned closed:1;
76 unsigned disposed:1;
77 };
78
79 static void
tp_tests_text_channel_null_init(TpTestsTextChannelNull * self)80 tp_tests_text_channel_null_init (TpTestsTextChannelNull *self)
81 {
82 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
83 TP_TESTS_TYPE_TEXT_CHANNEL_NULL, TpTestsTextChannelNullPrivate);
84 }
85
86 static void
tp_tests_props_text_channel_init(TpTestsPropsTextChannel * self)87 tp_tests_props_text_channel_init (TpTestsPropsTextChannel *self)
88 {
89 self->dbus_property_interfaces_retrieved = g_hash_table_new (NULL, NULL);
90 }
91
92 static GObject *
constructor(GType type,guint n_props,GObjectConstructParam * props)93 constructor (GType type,
94 guint n_props,
95 GObjectConstructParam *props)
96 {
97 GObject *object =
98 G_OBJECT_CLASS (tp_tests_text_channel_null_parent_class)->constructor (type,
99 n_props, props);
100 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
101 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles
102 (self->priv->conn, TP_HANDLE_TYPE_CONTACT);
103
104 tp_handle_ref (contact_repo, self->priv->handle);
105
106 tp_dbus_daemon_register_object (
107 tp_base_connection_get_dbus_daemon (self->priv->conn),
108 self->priv->object_path, self);
109
110 tp_text_mixin_init (object, G_STRUCT_OFFSET (TpTestsTextChannelNull, text),
111 contact_repo);
112
113 tp_text_mixin_set_message_types (object,
114 TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
115 TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION,
116 TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
117 G_MAXUINT);
118
119 return object;
120 }
121
122 static void
get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)123 get_property (GObject *object,
124 guint property_id,
125 GValue *value,
126 GParamSpec *pspec)
127 {
128 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
129
130 switch (property_id)
131 {
132 case PROP_OBJECT_PATH:
133 g_value_set_string (value, self->priv->object_path);
134 break;
135 case PROP_CHANNEL_TYPE:
136 g_value_set_static_string (value, TP_IFACE_CHANNEL_TYPE_TEXT);
137 break;
138 case PROP_HANDLE_TYPE:
139 g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
140 break;
141 case PROP_HANDLE:
142 g_value_set_uint (value, self->priv->handle);
143 break;
144 case PROP_TARGET_ID:
145 {
146 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
147 self->priv->conn, TP_HANDLE_TYPE_CONTACT);
148
149 g_value_set_string (value,
150 tp_handle_inspect (contact_repo, self->priv->handle));
151 }
152 break;
153 case PROP_REQUESTED:
154 g_value_set_boolean (value, TRUE);
155 break;
156 case PROP_INITIATOR_HANDLE:
157 g_value_set_uint (value, tp_base_connection_get_self_handle (
158 self->priv->conn));
159 break;
160 case PROP_INITIATOR_ID:
161 {
162 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
163 self->priv->conn, TP_HANDLE_TYPE_CONTACT);
164
165 g_value_set_string (value,
166 tp_handle_inspect (contact_repo,
167 tp_base_connection_get_self_handle (self->priv->conn)));
168 }
169 break;
170 case PROP_INTERFACES:
171 g_value_set_boxed (value, tp_tests_text_channel_null_interfaces);
172 break;
173 case PROP_CONNECTION:
174 g_value_set_object (value, self->priv->conn);
175 break;
176 default:
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
178 break;
179 }
180 }
181
182 static void
set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)183 set_property (GObject *object,
184 guint property_id,
185 const GValue *value,
186 GParamSpec *pspec)
187 {
188 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
189
190 switch (property_id)
191 {
192 case PROP_OBJECT_PATH:
193 g_free (self->priv->object_path);
194 self->priv->object_path = g_value_dup_string (value);
195 break;
196 case PROP_HANDLE:
197 /* we don't ref it here because we don't necessarily have access to the
198 * contact repo yet - instead we ref it in the constructor.
199 */
200 self->priv->handle = g_value_get_uint (value);
201 break;
202 case PROP_HANDLE_TYPE:
203 case PROP_CHANNEL_TYPE:
204 /* these properties are writable in the interface, but not actually
205 * meaningfully changeable on this channel, so we do nothing */
206 break;
207 case PROP_CONNECTION:
208 self->priv->conn = g_value_get_object (value);
209 break;
210 default:
211 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
212 break;
213 }
214 }
215
216 void
tp_tests_text_channel_null_close(TpTestsTextChannelNull * self)217 tp_tests_text_channel_null_close (TpTestsTextChannelNull *self)
218 {
219 if (!self->priv->closed)
220 {
221 self->priv->closed = TRUE;
222 tp_svc_channel_emit_closed (self);
223 tp_dbus_daemon_unregister_object (
224 tp_base_connection_get_dbus_daemon (self->priv->conn), self);
225 }
226 }
227
228 static void
dispose(GObject * object)229 dispose (GObject *object)
230 {
231 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
232
233 if (self->priv->disposed)
234 return;
235
236 self->priv->disposed = TRUE;
237 tp_tests_text_channel_null_close (self);
238
239 ((GObjectClass *) tp_tests_text_channel_null_parent_class)->dispose (object);
240 }
241
242 static void
finalize(GObject * object)243 finalize (GObject *object)
244 {
245 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (object);
246 TpHandleRepoIface *contact_handles = tp_base_connection_get_handles
247 (self->priv->conn, TP_HANDLE_TYPE_CONTACT);
248
249 tp_handle_unref (contact_handles, self->priv->handle);
250 g_free (self->priv->object_path);
251
252 tp_text_mixin_finalize (object);
253
254 ((GObjectClass *) tp_tests_text_channel_null_parent_class)->finalize (object);
255 }
256
257 static void
tp_tests_text_channel_null_class_init(TpTestsTextChannelNullClass * klass)258 tp_tests_text_channel_null_class_init (TpTestsTextChannelNullClass *klass)
259 {
260 GObjectClass *object_class = (GObjectClass *) klass;
261 GParamSpec *param_spec;
262
263 g_type_class_add_private (klass, sizeof (TpTestsTextChannelNullPrivate));
264
265 object_class->constructor = constructor;
266 object_class->set_property = set_property;
267 object_class->get_property = get_property;
268 object_class->dispose = dispose;
269 object_class->finalize = finalize;
270
271 g_object_class_override_property (object_class, PROP_OBJECT_PATH,
272 "object-path");
273 g_object_class_override_property (object_class, PROP_CHANNEL_TYPE,
274 "channel-type");
275 g_object_class_override_property (object_class, PROP_HANDLE_TYPE,
276 "handle-type");
277 g_object_class_override_property (object_class, PROP_HANDLE, "handle");
278
279 param_spec = g_param_spec_object ("connection", "TpBaseConnection object",
280 "Connection object that owns this channel",
281 TP_TYPE_BASE_CONNECTION,
282 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
283 g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
284
285 param_spec = g_param_spec_boxed ("interfaces", "Extra D-Bus interfaces",
286 "Additional Channel.Interface.* interfaces",
287 G_TYPE_STRV,
288 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
289 g_object_class_install_property (object_class, PROP_INTERFACES, param_spec);
290
291 param_spec = g_param_spec_string ("target-id", "Peer's ID",
292 "The string obtained by inspecting the target handle",
293 NULL,
294 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
295 g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec);
296
297 param_spec = g_param_spec_uint ("initiator-handle", "Initiator's handle",
298 "The contact who initiated the channel",
299 0, G_MAXUINT32, 0,
300 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
301 g_object_class_install_property (object_class, PROP_INITIATOR_HANDLE,
302 param_spec);
303
304 param_spec = g_param_spec_string ("initiator-id", "Initiator's ID",
305 "The string obtained by inspecting the initiator-handle",
306 NULL,
307 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
308 g_object_class_install_property (object_class, PROP_INITIATOR_ID,
309 param_spec);
310
311 param_spec = g_param_spec_boolean ("requested", "Requested?",
312 "True if this channel was requested by the local user",
313 FALSE,
314 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
315 g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
316
317 tp_text_mixin_class_init (object_class,
318 G_STRUCT_OFFSET (TpTestsTextChannelNullClass, text_class));
319 }
320
321 static void
tp_tests_props_text_channel_getter_gobject_properties(GObject * object,GQuark interface,GQuark name,GValue * value,gpointer getter_data)322 tp_tests_props_text_channel_getter_gobject_properties (GObject *object,
323 GQuark interface,
324 GQuark name,
325 GValue *value,
326 gpointer getter_data)
327 {
328 TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object);
329
330 g_hash_table_insert (self->dbus_property_interfaces_retrieved,
331 GUINT_TO_POINTER (interface), GUINT_TO_POINTER (interface));
332
333 tp_dbus_properties_mixin_getter_gobject_properties (object, interface, name,
334 value, getter_data);
335 }
336
337 static void
props_finalize(GObject * object)338 props_finalize (GObject *object)
339 {
340 TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object);
341
342 g_hash_table_unref (self->dbus_property_interfaces_retrieved);
343
344 ((GObjectClass *) tp_tests_props_text_channel_parent_class)->finalize (object);
345 }
346
347 static void
tp_tests_props_text_channel_class_init(TpTestsPropsTextChannelClass * klass)348 tp_tests_props_text_channel_class_init (TpTestsPropsTextChannelClass *klass)
349 {
350 GObjectClass *object_class = (GObjectClass *) klass;
351 static TpDBusPropertiesMixinPropImpl channel_props[] = {
352 { "TargetHandleType", "handle-type", NULL },
353 { "TargetHandle", "handle", NULL },
354 { "ChannelType", "channel-type", NULL },
355 { "Interfaces", "interfaces", NULL },
356 { "TargetID", "target-id", NULL },
357 { "Requested", "requested", NULL },
358 { "InitiatorHandle", "initiator-handle", NULL },
359 { "InitiatorID", "initiator-id", NULL },
360 { NULL }
361 };
362 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
363 { TP_IFACE_CHANNEL,
364 tp_tests_props_text_channel_getter_gobject_properties,
365 NULL,
366 channel_props,
367 },
368 { NULL }
369 };
370
371 object_class->finalize = props_finalize;
372
373 klass->dbus_properties_class.interfaces = prop_interfaces;
374 tp_dbus_properties_mixin_class_init (object_class,
375 G_STRUCT_OFFSET (TpTestsPropsTextChannelClass, dbus_properties_class));
376 }
377
378 static void
tp_tests_props_group_text_channel_init(TpTestsPropsGroupTextChannel * self)379 tp_tests_props_group_text_channel_init (TpTestsPropsGroupTextChannel *self)
380 {
381 }
382
383 static void
group_constructed(GObject * self)384 group_constructed (GObject *self)
385 {
386 TpBaseConnection *conn = TP_TESTS_TEXT_CHANNEL_NULL (self)->priv->conn;
387 void (*chain_up) (GObject *) =
388 ((GObjectClass *) tp_tests_props_group_text_channel_parent_class)->constructed;
389
390 if (chain_up != NULL)
391 chain_up (self);
392
393 tp_group_mixin_init (self,
394 G_STRUCT_OFFSET (TpTestsPropsGroupTextChannel, group),
395 tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT),
396 tp_base_connection_get_self_handle (conn));
397 tp_group_mixin_change_flags (self, TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0);
398 }
399
400 static void
group_finalize(GObject * self)401 group_finalize (GObject *self)
402 {
403 tp_group_mixin_finalize (self);
404
405 ((GObjectClass *) tp_tests_props_group_text_channel_parent_class)->finalize (self);
406 }
407
408 static gboolean
dummy_add_remove_member(GObject * obj,TpHandle handle,const gchar * message,GError ** error)409 dummy_add_remove_member (GObject *obj,
410 TpHandle handle,
411 const gchar *message,
412 GError **error)
413 {
414 return TRUE;
415 }
416
417 static void
group_iface_props_getter(GObject * object,GQuark interface,GQuark name,GValue * value,gpointer getter_data)418 group_iface_props_getter (GObject *object,
419 GQuark interface,
420 GQuark name,
421 GValue *value,
422 gpointer getter_data)
423 {
424 TpTestsPropsTextChannel *self = TP_TESTS_PROPS_TEXT_CHANNEL (object);
425
426 g_hash_table_insert (self->dbus_property_interfaces_retrieved,
427 GUINT_TO_POINTER (interface), GUINT_TO_POINTER (interface));
428
429 tp_group_mixin_get_dbus_property (object, interface, name, value, getter_data);
430 }
431
432 static void
tp_tests_props_group_text_channel_class_init(TpTestsPropsGroupTextChannelClass * klass)433 tp_tests_props_group_text_channel_class_init (TpTestsPropsGroupTextChannelClass *klass)
434 {
435 GObjectClass *object_class = (GObjectClass *) klass;
436 static TpDBusPropertiesMixinPropImpl group_props[] = {
437 { "GroupFlags", NULL, NULL },
438 { "HandleOwners", NULL, NULL },
439 { "LocalPendingMembers", NULL, NULL },
440 { "Members", NULL, NULL },
441 { "RemotePendingMembers", NULL, NULL },
442 { "SelfHandle", NULL, NULL },
443 { NULL }
444 };
445
446 object_class->constructed = group_constructed;
447 object_class->finalize = group_finalize;
448
449 tp_group_mixin_class_init (object_class,
450 G_STRUCT_OFFSET (TpTestsPropsGroupTextChannelClass, group_class),
451 dummy_add_remove_member,
452 dummy_add_remove_member);
453 tp_dbus_properties_mixin_implement_interface (object_class,
454 TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP, group_iface_props_getter, NULL,
455 group_props);
456 }
457
458 static void
channel_close(TpSvcChannel * iface,DBusGMethodInvocation * context)459 channel_close (TpSvcChannel *iface,
460 DBusGMethodInvocation *context)
461 {
462 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
463
464 tp_tests_text_channel_null_close (self);
465 tp_svc_channel_return_from_close (context);
466 }
467
468 static void
channel_get_channel_type(TpSvcChannel * iface,DBusGMethodInvocation * context)469 channel_get_channel_type (TpSvcChannel *iface,
470 DBusGMethodInvocation *context)
471 {
472 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
473
474 self->get_channel_type_called++;
475
476 tp_svc_channel_return_from_get_channel_type (context,
477 TP_IFACE_CHANNEL_TYPE_TEXT);
478 }
479
480 static void
channel_get_handle(TpSvcChannel * iface,DBusGMethodInvocation * context)481 channel_get_handle (TpSvcChannel *iface,
482 DBusGMethodInvocation *context)
483 {
484 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
485
486 self->get_handle_called++;
487
488 tp_svc_channel_return_from_get_handle (context, TP_HANDLE_TYPE_CONTACT,
489 self->priv->handle);
490 }
491
492 static void
channel_get_interfaces(TpSvcChannel * iface,DBusGMethodInvocation * context)493 channel_get_interfaces (TpSvcChannel *iface,
494 DBusGMethodInvocation *context)
495 {
496 TpTestsTextChannelNull *self = TP_TESTS_TEXT_CHANNEL_NULL (iface);
497
498 self->get_interfaces_called++;
499
500 tp_svc_channel_return_from_get_interfaces (context,
501 tp_tests_text_channel_null_interfaces);
502 }
503
504 static void
channel_iface_init(gpointer iface,gpointer data)505 channel_iface_init (gpointer iface,
506 gpointer data)
507 {
508 TpSvcChannelClass *klass = iface;
509
510 #define IMPLEMENT(x) tp_svc_channel_implement_##x (klass, channel_##x)
511 IMPLEMENT (close);
512 IMPLEMENT (get_channel_type);
513 IMPLEMENT (get_handle);
514 IMPLEMENT (get_interfaces);
515 #undef IMPLEMENT
516 }
517
518 static void
text_send(TpSvcChannelTypeText * iface,guint type,const gchar * text,DBusGMethodInvocation * context)519 text_send (TpSvcChannelTypeText *iface,
520 guint type,
521 const gchar *text,
522 DBusGMethodInvocation *context)
523 {
524 /* silently swallow the message */
525 tp_svc_channel_type_text_return_from_send (context);
526 }
527
528 static void
text_iface_init(gpointer iface,gpointer data)529 text_iface_init (gpointer iface,
530 gpointer data)
531 {
532 TpSvcChannelTypeTextClass *klass = iface;
533
534 tp_text_mixin_iface_init (iface, data);
535 #define IMPLEMENT(x) tp_svc_channel_type_text_implement_##x (klass, text_##x)
536 IMPLEMENT (send);
537 #undef IMPLEMENT
538 }
539
540 GHashTable *
tp_tests_text_channel_get_props(TpTestsTextChannelNull * self)541 tp_tests_text_channel_get_props (TpTestsTextChannelNull *self)
542 {
543 GHashTable *props;
544 TpHandleType handle_type;
545 TpHandle handle;
546 gchar *target_id;
547 gboolean requested;
548 TpHandle initiator_handle;
549 gchar *initiator_id;
550 GStrv interfaces;
551
552 g_object_get (self,
553 "handle-type", &handle_type,
554 "handle", &handle,
555 "target-id", &target_id,
556 "requested", &requested,
557 "initiator-handle", &initiator_handle,
558 "initiator-id", &initiator_id,
559 "interfaces", &interfaces,
560 NULL);
561
562 props = tp_asv_new (
563 TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING, TP_IFACE_CHANNEL_TYPE_TEXT,
564 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, handle_type,
565 TP_PROP_CHANNEL_TARGET_HANDLE, G_TYPE_UINT, handle,
566 TP_PROP_CHANNEL_TARGET_ID, G_TYPE_STRING, target_id,
567 TP_PROP_CHANNEL_REQUESTED, G_TYPE_BOOLEAN, requested,
568 TP_PROP_CHANNEL_INITIATOR_HANDLE, G_TYPE_UINT, initiator_handle,
569 TP_PROP_CHANNEL_INITIATOR_ID, G_TYPE_STRING, initiator_id,
570 TP_PROP_CHANNEL_INTERFACES, G_TYPE_STRV, interfaces,
571 NULL);
572
573 g_free (target_id);
574 g_free (initiator_id);
575 g_strfreev (interfaces);
576 return props;
577 }
578
579 G_GNUC_END_IGNORE_DEPRECATIONS
580