2
* conn.c - an example connection
4
* Copyright Ā© 2007-2009 Collabora Ltd. <http://www.collabora.co.uk/>
5
* Copyright Ā© 2007-2009 Nokia Corporation
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
#include <dbus/dbus-glib.h>
26
#include <telepathy-glib/telepathy-glib.h>
27
#include <telepathy-glib/handle-repo-dynamic.h>
28
#include <telepathy-glib/handle-repo-static.h>
30
#include "call-manager.h"
33
G_DEFINE_TYPE_WITH_CODE (ExampleCallConnection,
34
example_call_connection,
35
TP_TYPE_BASE_CONNECTION,
36
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
37
tp_contacts_mixin_iface_init);
38
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
39
tp_presence_mixin_iface_init);
40
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
41
tp_presence_mixin_simple_presence_iface_init))
46
PROP_SIMULATION_DELAY,
56
static guint signals[N_SIGNALS] = { 0 };
58
struct _ExampleCallConnectionPrivate
61
guint simulation_delay;
63
gchar *presence_message;
67
example_call_connection_init (ExampleCallConnection *self)
69
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
70
EXAMPLE_TYPE_CALL_CONNECTION,
71
ExampleCallConnectionPrivate);
72
self->priv->away = FALSE;
73
self->priv->presence_message = g_strdup ("");
77
get_property (GObject *object,
82
ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object);
87
g_value_set_string (value, self->priv->account);
90
case PROP_SIMULATION_DELAY:
91
g_value_set_uint (value, self->priv->simulation_delay);
95
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
100
set_property (GObject *object,
105
ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object);
110
g_free (self->priv->account);
111
self->priv->account = g_value_dup_string (value);
114
case PROP_SIMULATION_DELAY:
115
self->priv->simulation_delay = g_value_get_uint (value);
119
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
124
finalize (GObject *object)
126
ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (object);
128
tp_contacts_mixin_finalize (object);
129
g_free (self->priv->account);
130
g_free (self->priv->presence_message);
132
G_OBJECT_CLASS (example_call_connection_parent_class)->finalize (object);
136
get_unique_connection_name (TpBaseConnection *conn)
138
ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (conn);
140
return g_strdup_printf ("%s@%p", self->priv->account, self);
144
example_call_normalize_contact (TpHandleRepoIface *repo,
149
gchar *normal = NULL;
151
if (example_call_protocol_check_contact_id (id, &normal, error))
158
create_handle_repos (TpBaseConnection *conn,
159
TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
161
repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new
162
(TP_HANDLE_TYPE_CONTACT, example_call_normalize_contact, NULL);
166
create_channel_managers (TpBaseConnection *conn)
168
ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (conn);
169
GPtrArray *ret = g_ptr_array_sized_new (1);
171
g_ptr_array_add (ret,
172
g_object_new (EXAMPLE_TYPE_CALL_MANAGER,
174
"simulation-delay", self->priv->simulation_delay,
181
start_connecting (TpBaseConnection *conn,
184
ExampleCallConnection *self = EXAMPLE_CALL_CONNECTION (conn);
185
TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
186
TP_HANDLE_TYPE_CONTACT);
188
/* In a real connection manager we'd ask the underlying implementation to
189
* start connecting, then go to state CONNECTED when finished, but here
190
* we can do it immediately. */
192
conn->self_handle = tp_handle_ensure (contact_repo, self->priv->account,
195
if (conn->self_handle == 0)
198
tp_base_connection_change_status (conn, TP_CONNECTION_STATUS_CONNECTED,
199
TP_CONNECTION_STATUS_REASON_REQUESTED);
205
shut_down (TpBaseConnection *conn)
207
/* In a real connection manager we'd ask the underlying implementation to
208
* start shutting down, then call this function when finished, but here
209
* we can do it immediately. */
210
tp_base_connection_finish_shutdown (conn);
214
constructed (GObject *object)
216
TpBaseConnection *base = TP_BASE_CONNECTION (object);
217
void (*chain_up) (GObject *) =
218
G_OBJECT_CLASS (example_call_connection_parent_class)->constructed;
220
if (chain_up != NULL)
223
tp_contacts_mixin_init (object,
224
G_STRUCT_OFFSET (ExampleCallConnection, contacts_mixin));
225
tp_base_connection_register_with_contacts_mixin (base);
227
tp_presence_mixin_init (object,
228
G_STRUCT_OFFSET (ExampleCallConnection, presence_mixin));
229
tp_presence_mixin_simple_presence_register_with_contacts_mixin (object);
233
status_available (GObject *object,
236
TpBaseConnection *base = TP_BASE_CONNECTION (object);
238
if (base->status != TP_CONNECTION_STATUS_CONNECTED)
245
get_contact_statuses (GObject *object,
246
const GArray *contacts,
249
ExampleCallConnection *self =
250
EXAMPLE_CALL_CONNECTION (object);
251
TpBaseConnection *base = TP_BASE_CONNECTION (object);
253
GHashTable *result = g_hash_table_new_full (g_direct_hash, g_direct_equal,
254
NULL, (GDestroyNotify) tp_presence_status_free);
256
for (i = 0; i < contacts->len; i++)
258
TpHandle contact = g_array_index (contacts, guint, i);
259
ExampleCallPresence presence;
260
GHashTable *parameters;
262
parameters = g_hash_table_new_full (g_str_hash,
263
g_str_equal, NULL, (GDestroyNotify) tp_g_value_slice_free);
265
/* we know our own status from the connection; for this example CM,
266
* everyone else's status is assumed to be "available" */
267
if (contact == base->self_handle)
269
presence = (self->priv->away ? EXAMPLE_CALL_PRESENCE_AWAY
270
: EXAMPLE_CALL_PRESENCE_AVAILABLE);
272
if (self->priv->presence_message[0] != '\0')
273
g_hash_table_insert (parameters, "message",
274
tp_g_value_slice_new_string (self->priv->presence_message));
278
presence = EXAMPLE_CALL_PRESENCE_AVAILABLE;
281
g_hash_table_insert (result, GUINT_TO_POINTER (contact),
282
tp_presence_status_new (presence, parameters));
283
g_hash_table_unref (parameters);
290
set_own_status (GObject *object,
291
const TpPresenceStatus *status,
294
ExampleCallConnection *self =
295
EXAMPLE_CALL_CONNECTION (object);
296
TpBaseConnection *base = TP_BASE_CONNECTION (object);
297
GHashTable *presences;
298
const gchar *message = "";
300
if (status->optional_arguments != NULL)
302
GValue *v = g_hash_table_lookup (status->optional_arguments, "message");
304
if (v != NULL && G_VALUE_HOLDS_STRING (v))
306
message = g_value_get_string (v);
313
if (status->index == EXAMPLE_CALL_PRESENCE_AWAY)
315
if (self->priv->away && !tp_strdiff (message,
316
self->priv->presence_message))
319
self->priv->away = TRUE;
323
if (!self->priv->away && !tp_strdiff (message,
324
self->priv->presence_message))
327
self->priv->away = FALSE;
330
g_free (self->priv->presence_message);
331
self->priv->presence_message = g_strdup (message);
333
presences = g_hash_table_new_full (g_direct_hash, g_direct_equal,
335
g_hash_table_insert (presences, GUINT_TO_POINTER (base->self_handle),
337
tp_presence_mixin_emit_presence_update (object, presences);
338
g_hash_table_unref (presences);
340
if (!self->priv->away)
342
g_signal_emit (self, signals[SIGNAL_AVAILABLE], 0, message);
348
static const TpPresenceStatusOptionalArgumentSpec can_have_message[] = {
349
{ "message", "s", NULL, NULL },
353
/* Must be kept in sync with ExampleCallPresence enum in header */
354
static const TpPresenceStatusSpec presence_statuses[] = {
355
{ "offline", TP_CONNECTION_PRESENCE_TYPE_OFFLINE, FALSE, NULL },
356
{ "unknown", TP_CONNECTION_PRESENCE_TYPE_UNKNOWN, FALSE, NULL },
357
{ "error", TP_CONNECTION_PRESENCE_TYPE_ERROR, FALSE, NULL },
358
{ "away", TP_CONNECTION_PRESENCE_TYPE_AWAY, TRUE, can_have_message },
359
{ "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE, TRUE,
364
static const gchar *interfaces_always_present[] = {
365
TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
366
TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
367
TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
368
TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
371
const gchar * const *
372
example_call_connection_get_possible_interfaces (void)
374
/* in this example CM we don't have any extra interfaces that are sometimes,
375
* but not always, present */
376
return interfaces_always_present;
380
example_call_connection_class_init (
381
ExampleCallConnectionClass *klass)
383
TpBaseConnectionClass *base_class = (TpBaseConnectionClass *) klass;
384
GObjectClass *object_class = (GObjectClass *) klass;
385
GParamSpec *param_spec;
387
object_class->get_property = get_property;
388
object_class->set_property = set_property;
389
object_class->constructed = constructed;
390
object_class->finalize = finalize;
391
g_type_class_add_private (klass,
392
sizeof (ExampleCallConnectionPrivate));
394
base_class->create_handle_repos = create_handle_repos;
395
base_class->get_unique_connection_name = get_unique_connection_name;
396
base_class->create_channel_managers = create_channel_managers;
397
base_class->start_connecting = start_connecting;
398
base_class->shut_down = shut_down;
399
base_class->interfaces_always_present = interfaces_always_present;
401
param_spec = g_param_spec_string ("account", "Account name",
402
"The username of this user", NULL,
403
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
404
g_object_class_install_property (object_class, PROP_ACCOUNT, param_spec);
406
param_spec = g_param_spec_uint ("simulation-delay", "Simulation delay",
407
"Delay between simulated network events",
408
0, G_MAXUINT32, 1000,
409
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
410
g_object_class_install_property (object_class, PROP_SIMULATION_DELAY,
413
/* Used in the call manager, to simulate an incoming call when we become
415
signals[SIGNAL_AVAILABLE] = g_signal_new ("available",
416
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
417
g_cclosure_marshal_VOID__STRING,
418
G_TYPE_NONE, 1, G_TYPE_STRING);
420
tp_contacts_mixin_class_init (object_class,
421
G_STRUCT_OFFSET (ExampleCallConnectionClass, contacts_mixin));
422
tp_presence_mixin_class_init (object_class,
423
G_STRUCT_OFFSET (ExampleCallConnectionClass, presence_mixin),
424
status_available, get_contact_statuses, set_own_status,
426
tp_presence_mixin_simple_presence_init_dbus_properties (object_class);