]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-tube.c
Rename EmpathyTube to EmpathyTpTube and remove EmpathyTubes.
[empathy.git] / libempathy / empathy-tp-tube.c
1 /*
2  * Copyright (C) 2008 Collabora Ltd.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Guillaume Desmottes <guillaume.desmottes@collabora.co.uk>
19  *          Elliot Fairweather <elliot.fairweather@collabora.co.uk>
20  */
21
22 #include <config.h>
23
24 #include <telepathy-glib/connection.h>
25
26 #include "empathy-contact.h"
27 #include "empathy-contact-factory.h"
28 #include "empathy-debug.h"
29 #include "empathy-enum-types.h"
30 #include "empathy-tp-tube.h"
31 #include "empathy-utils.h"
32
33 #define DEBUG_DOMAIN "TpTube"
34
35 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_TP_TUBE, \
36     EmpathyTpTubePriv))
37
38 typedef struct _EmpathyTpTubePriv EmpathyTpTubePriv;
39
40 struct _EmpathyTpTubePriv
41 {
42   TpChannel *channel;
43   guint id;
44   guint initiator;
45   guint type;
46   gchar *service;
47   GHashTable *parameters;
48   guint state;
49   EmpathyContact *initiator_contact;
50   EmpathyContactFactory *factory;
51 };
52
53 enum
54 {
55   PROP_0,
56   PROP_CHANNEL,
57   PROP_TP_TUBES,
58   PROP_ID,
59   PROP_INITIATOR,
60   PROP_TYPE,
61   PROP_SERVICE,
62   PROP_PARAMETERS,
63   PROP_STATE,
64   PROP_INITIATOR_CONTACT
65 };
66
67 enum
68 {
69   DESTROY,
70   LAST_SIGNAL
71 };
72
73 static guint signals[LAST_SIGNAL];
74
75 G_DEFINE_TYPE (EmpathyTpTube, empathy_tp_tube, G_TYPE_OBJECT)
76
77 static void
78 tp_tube_state_changed_cb (TpChannel *channel,
79                           guint id,
80                           guint state,
81                           gpointer user_data,
82                           GObject *tube)
83 {
84   EmpathyTpTubePriv *priv = GET_PRIV (tube);
85
86   if (id != priv->id)
87       return;
88
89   empathy_debug (DEBUG_DOMAIN, "Tube state changed");
90
91   priv->state = state;
92   g_object_notify (tube, "state");
93 }
94
95 static void
96 tp_tube_invalidated_cb (TpChannel     *channel,
97                         GQuark         domain,
98                         gint           code,
99                         gchar         *message,
100                         EmpathyTpTube *tube)
101 {
102   empathy_debug (DEBUG_DOMAIN, "Channel invalidated: %s", message);
103   g_signal_emit (tube, signals[DESTROY], 0);
104 }
105
106 static void
107 tp_tube_closed_cb (TpChannel *channel,
108                    guint id,
109                    gpointer user_data,
110                    GObject *tube)
111 {
112   EmpathyTpTubePriv *priv = GET_PRIV (tube);
113
114   if (id != priv->id)
115       return;
116
117   empathy_debug (DEBUG_DOMAIN, "Tube closed");
118   g_signal_emit (tube, signals[DESTROY], 0);
119 }
120
121 static void
122 tp_tube_async_cb (TpChannel *channel,
123                   const GError *error,
124                   gpointer user_data,
125                   GObject *tube)
126 {
127   if (error)
128       empathy_debug (DEBUG_DOMAIN, "Error %s: %s", user_data, error->message);
129 }
130
131 static void
132 tp_tube_set_property (GObject *object,
133                       guint prop_id,
134                       const GValue *value,
135                       GParamSpec *pspec)
136 {
137   EmpathyTpTubePriv *priv = GET_PRIV (object);
138
139   switch (prop_id)
140     {
141       case PROP_CHANNEL:
142         priv->channel = g_value_dup_object (value);
143         break;
144       case PROP_ID:
145         priv->id = g_value_get_uint (value);
146         break;
147       case PROP_INITIATOR:
148         priv->initiator = g_value_get_uint (value);
149         break;
150       case PROP_TYPE:
151         priv->type = g_value_get_uint (value);
152         break;
153       case PROP_SERVICE:
154         priv->service = g_value_dup_string (value);
155         break;
156       case PROP_PARAMETERS:
157         priv->parameters = g_value_dup_boxed (value);
158         break;
159       case PROP_STATE:
160         priv->state = g_value_get_uint (value);
161         break;
162       default:
163         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
164         break;
165   }
166 }
167
168 static void
169 tp_tube_get_property (GObject *object,
170                       guint prop_id,
171                       GValue *value,
172                       GParamSpec *pspec)
173 {
174   EmpathyTpTubePriv *priv = GET_PRIV (object);
175
176   switch (prop_id)
177     {
178       case PROP_CHANNEL:
179         g_value_set_object (value, priv->channel);
180         break;
181       case PROP_ID:
182         g_value_set_uint (value, priv->id);
183         break;
184       case PROP_INITIATOR:
185         g_value_set_uint (value, priv->initiator);
186         break;
187       case PROP_TYPE:
188         g_value_set_uint (value, priv->type);
189         break;
190       case PROP_SERVICE:
191         g_value_set_string (value, priv->service);
192         break;
193       case PROP_PARAMETERS:
194         g_value_set_boxed (value, priv->parameters);
195         break;
196       case PROP_STATE:
197         g_value_set_uint (value, priv->state);
198         break;
199       case PROP_INITIATOR_CONTACT:
200         g_value_set_object (value, priv->initiator_contact);
201         break;
202       default:
203         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
204         break;
205   }
206 }
207
208 static GObject *
209 tp_tube_constructor (GType type,
210                      guint n_props,
211                      GObjectConstructParam *props)
212 {
213   GObject *self;
214   EmpathyTpTubePriv *priv;
215   TpConnection *connection;
216   MissionControl *mc;
217   McAccount *account;
218
219   self = G_OBJECT_CLASS (empathy_tp_tube_parent_class)->constructor (
220       type, n_props, props);
221   priv = GET_PRIV (self);
222
223   g_object_get (priv->channel, "connection", &connection, NULL);
224   mc = empathy_mission_control_new ();
225   account = mission_control_get_account_for_tpconnection (mc, connection, NULL);
226
227   priv->factory = empathy_contact_factory_new ();
228   priv->initiator_contact = empathy_contact_factory_get_from_handle (priv->factory,
229       account, priv->initiator);
230   g_object_ref (priv->initiator_contact);
231
232   g_signal_connect (priv->channel, "invalidated",
233       G_CALLBACK (tp_tube_invalidated_cb), self);
234
235   tp_cli_channel_type_tubes_connect_to_tube_closed (priv->channel,
236       tp_tube_closed_cb, NULL, NULL, self, NULL);
237   tp_cli_channel_type_tubes_connect_to_tube_state_changed (priv->channel,
238       tp_tube_state_changed_cb, NULL, NULL, self, NULL);
239
240   g_object_unref (connection);
241   g_object_unref (mc);
242   g_object_unref (account);
243
244   return self;
245 }
246
247 static void
248 tp_tube_finalize (GObject *object)
249 {
250   EmpathyTpTubePriv *priv = GET_PRIV (object);
251
252   empathy_debug (DEBUG_DOMAIN, "Finalizing: %p", object);
253
254   if (priv->channel)
255     {
256       g_signal_handlers_disconnect_by_func (priv->channel,
257           tp_tube_invalidated_cb, object);
258       tp_cli_channel_type_tubes_call_close_tube (priv->channel, -1, priv->id,
259           tp_tube_async_cb, "closing tube", NULL, NULL);
260       g_object_unref (priv->channel);
261     }
262   if (priv->initiator_contact)
263       g_object_unref (priv->initiator_contact);
264   if (priv->factory)
265       g_object_unref (priv->factory);
266
267   g_free (priv->service);
268   g_hash_table_destroy (priv->parameters);
269
270   G_OBJECT_CLASS (empathy_tp_tube_parent_class)->finalize (object);
271 }
272
273 static void
274 empathy_tp_tube_class_init (EmpathyTpTubeClass *klass)
275 {
276   GObjectClass *object_class = G_OBJECT_CLASS (klass);
277
278   object_class->constructor = tp_tube_constructor;
279   object_class->finalize = tp_tube_finalize;
280   object_class->set_property = tp_tube_set_property;
281   object_class->get_property = tp_tube_get_property;
282
283   g_object_class_install_property (object_class, PROP_CHANNEL,
284       g_param_spec_object ("channel", "channel", "channel", TP_TYPE_CHANNEL,
285       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME |
286         G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
287
288   g_object_class_install_property (object_class, PROP_ID,
289       g_param_spec_uint ("id", "id", "id", 0, G_MAXUINT, 0,
290         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME |
291         G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
292
293   g_object_class_install_property (object_class, PROP_INITIATOR,
294       g_param_spec_uint ("initiator", "initiator", "initiator",
295         0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
296         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
297
298   g_object_class_install_property (object_class, PROP_TYPE,
299       g_param_spec_uint ("type", "type", "type", 0, G_MAXUINT, 0,
300         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME |
301         G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
302
303   g_object_class_install_property (object_class, PROP_SERVICE,
304       g_param_spec_string ("service", "service", "service", NULL,
305       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME |
306       G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
307
308   g_object_class_install_property (object_class, PROP_PARAMETERS,
309       g_param_spec_boxed ("parameters", "parameters", "parameters",
310       G_TYPE_HASH_TABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
311       G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
312
313   g_object_class_install_property (object_class, PROP_STATE,
314       g_param_spec_uint ("state", "state", "state", 0, G_MAXUINT, 0,
315         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
316         G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
317
318   g_object_class_install_property (object_class, PROP_INITIATOR_CONTACT,
319      g_param_spec_object ("initiator-contact", "initiator contact",
320      "initiator contact", EMPATHY_TYPE_CONTACT, G_PARAM_READABLE |
321      G_PARAM_STATIC_NAME |  G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
322
323   signals[DESTROY] = g_signal_new ("destroy",
324       G_TYPE_FROM_CLASS (klass),
325       G_SIGNAL_RUN_LAST,
326       0, NULL, NULL,
327       g_cclosure_marshal_VOID__VOID,
328       G_TYPE_NONE, 0);
329
330   g_type_class_add_private (klass, sizeof (EmpathyTpTubePriv));
331 }
332
333 static void
334 empathy_tp_tube_init (EmpathyTpTube *tp_tubes)
335 {
336 }
337
338 EmpathyTpTube *
339 empathy_tp_tube_new (TpChannel *channel, guint tube_id)
340 {
341   EmpathyTpTube *tube = NULL;
342   GPtrArray *tubes;
343   guint i;
344   GError *error = NULL;
345
346   g_return_val_if_fail (TP_IS_CHANNEL (channel), NULL);
347
348   if (!tp_cli_channel_type_tubes_run_list_tubes (channel, -1, &tubes,
349       &error, NULL))
350     {
351       empathy_debug (DEBUG_DOMAIN, "Couldn't list tubes: %s",
352           error->message);
353       g_clear_error (&error);
354       return NULL;
355     }
356
357   for (i = 0; i < tubes->len; i++)
358     {
359       GValueArray *values;
360       guint id;
361
362       values = g_ptr_array_index (tubes, i);
363       id = g_value_get_uint (g_value_array_get_nth (values, 0));
364
365       if (id != tube_id)
366         {
367           g_value_array_free (values);
368           continue;
369         }
370
371       tube = g_object_new (EMPATHY_TYPE_TP_TUBE,
372           "channel", channel,
373           "id", id,
374           "initiator", g_value_get_uint (g_value_array_get_nth (values, 1)),
375           "type", g_value_get_uint (g_value_array_get_nth (values, 2)),
376           "service", g_value_get_string (g_value_array_get_nth (values, 3)),
377           "parameters", g_value_get_boxed (g_value_array_get_nth (values, 4)),
378           "state", g_value_get_uint (g_value_array_get_nth (values, 5)),
379           NULL);
380
381       g_value_array_free (values);
382     }
383   g_ptr_array_free (tubes, TRUE);
384
385   return tube;
386 }
387
388 static void
389 tp_tube_accept_stream_cb (TpChannel *proxy,
390                           const GValue *address,
391                           const GError *error,
392                           gpointer user_data,
393                           GObject *weak_object)
394 {
395   if (error)
396       empathy_debug (DEBUG_DOMAIN, "Error accepting tube: %s", error->message);
397 }
398
399 static void
400 tp_tube_accept_stream_tube (EmpathyTpTube *tube,
401                             TpSocketAddressType address_type,
402                             TpSocketAccessControl access_type,
403                             GValue *control_param)
404 {
405   EmpathyTpTubePriv *priv = GET_PRIV (tube);
406
407   empathy_debug (DEBUG_DOMAIN, "Accepting stream tube - id: %d", priv->id);
408
409   tp_cli_channel_type_tubes_call_accept_stream_tube (priv->channel, -1, priv->id,
410       address_type, access_type, control_param,
411       tp_tube_accept_stream_cb, NULL, NULL, G_OBJECT (tube));
412 }
413
414 void
415 empathy_tp_tube_accept_unix_stream_tube (EmpathyTpTube *tube)
416 {
417   GValue control_param = {0, };
418
419   g_return_if_fail (EMPATHY_IS_TP_TUBE (tube));
420
421   g_value_init (&control_param, G_TYPE_STRING);
422   tp_tube_accept_stream_tube (tube, TP_SOCKET_ADDRESS_TYPE_UNIX,
423       TP_SOCKET_ACCESS_CONTROL_LOCALHOST, &control_param);
424
425   g_value_reset (&control_param);
426 }
427
428 void
429 empathy_tp_tube_accept_ipv4_stream_tube (EmpathyTpTube *tube)
430 {
431   GValue control_param = {0, };
432
433   g_return_if_fail (EMPATHY_IS_TP_TUBE (tube));
434
435   g_value_init (&control_param, G_TYPE_STRING);
436   tp_tube_accept_stream_tube (tube, TP_SOCKET_ADDRESS_TYPE_IPV4,
437       TP_SOCKET_ACCESS_CONTROL_LOCALHOST, &control_param);
438
439   g_value_reset (&control_param);
440 }
441
442 gchar *
443 empathy_tp_tube_get_unix_socket (EmpathyTpTube *tube)
444 {
445   EmpathyTpTubePriv *priv = GET_PRIV (tube);
446   GValue *address = g_new0 (GValue, 1);;
447   guint address_type;
448   gchar *address_name = NULL;
449   GError *error = NULL;
450
451   g_return_val_if_fail (EMPATHY_IS_TP_TUBE (tube), NULL);
452
453   empathy_debug (DEBUG_DOMAIN, "Getting stream tube socket address");
454
455   /* FIXME: We shouldn't use _run_ here because the user may not expect to
456    * reenter the mainloop.
457    * FIXME: Do we have to give an initialised GValue for address? Are we
458    * freeing it correctly? */
459   if (!tp_cli_channel_type_tubes_run_get_stream_tube_socket_address (priv->channel,
460       -1, priv->id, &address_type, &address, &error, NULL))
461     {
462       empathy_debug (DEBUG_DOMAIN, "Couldn't get socket address: %s",
463           error->message);
464       g_clear_error (&error);
465       return NULL;
466     }
467
468   dbus_g_type_struct_get (address, 0, &address_name, G_MAXUINT);
469   g_free (address);
470
471   empathy_debug (DEBUG_DOMAIN, "UNIX Socket - %s", address_name);
472
473   return address_name;
474 }
475
476 void
477 empathy_tp_tube_get_ipv4_socket (EmpathyTpTube *tube,
478                                  gchar **hostname,
479                                  guint *port)
480 {
481   EmpathyTpTubePriv *priv = GET_PRIV (tube);
482   GValue *address = g_new0 (GValue, 1);
483   guint address_type;
484   GError *error = NULL;
485
486   g_return_if_fail (EMPATHY_IS_TP_TUBE (tube));
487
488   empathy_debug (DEBUG_DOMAIN, "Getting stream tube socket address");
489
490   if (!tp_cli_channel_type_tubes_run_get_stream_tube_socket_address (priv->channel,
491       -1, priv->id, &address_type, &address, &error, NULL))
492     {
493       empathy_debug (DEBUG_DOMAIN, "Couldn't get socket address: %s",
494           error->message);
495       g_clear_error (&error);
496       return;
497     }
498
499   dbus_g_type_struct_get (address, 0, hostname, 1, port, G_MAXUINT);
500
501   g_free (address);
502 }
503