1 /*
2  * bytestream-factory.c - Source for GabbleBytestreamFactory
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "config.h"
21 #include "bytestream-factory.h"
22 
23 #include <string.h>
24 #include <stdlib.h>
25 
26 #include <dbus/dbus-glib.h>
27 #include <dbus/dbus-glib-lowlevel.h>
28 #include <wocky/wocky.h>
29 #include <telepathy-glib/telepathy-glib.h>
30 #include <telepathy-glib/telepathy-glib-dbus.h>
31 
32 #define DEBUG_FLAG GABBLE_DEBUG_BYTESTREAM
33 
34 #include "bytestream-ibb.h"
35 #include "bytestream-iface.h"
36 #include "bytestream-muc.h"
37 #include "bytestream-multiple.h"
38 #include "bytestream-socks5.h"
39 #include "connection.h"
40 #include "conn-util.h"
41 #include "debug.h"
42 #include "disco.h"
43 #include "namespaces.h"
44 #include "presence-cache.h"
45 #include "private-tubes-factory.h"
46 #include "util.h"
47 
48 G_DEFINE_TYPE (GabbleBytestreamFactory, gabble_bytestream_factory,
49     G_TYPE_OBJECT);
50 
51 /* The number of proxy we'll try to have at a minimum in the cache. */
52 #define NB_MIN_SOCKS5_PROXIES 3
53 #define FALLBACK_PROXY_CACHE_SIZE 5
54 #define SOCKS5_PROXY_TIMEOUT 10
55 
56 #define TELEPATHY_PROXIES_SERVICE "proxies.telepathy.im"
57 /* The life time (in seconds) of the proxies list discovered using
58  * TELEPATHY_PROXIES_SERVICE */
59 /* 6 hours */
60 #define PROXIES_LIST_LIFE_TIME 6 * 60 * 60
61 
62 /* properties */
63 enum
64 {
65   PROP_CONNECTION = 1,
66   LAST_PROPERTY
67 };
68 
69 typedef struct
70 {
71   gchar *jid;
72   gchar *stream;
73 } BytestreamIdentifier;
74 
75 typedef struct
76 {
77   const gchar *jid;
78   const gchar *stream;
79 } ConstBytestreamIdentifier;
80 
81 static gboolean
bytestream_id_equal(gconstpointer v1,gconstpointer v2)82 bytestream_id_equal (gconstpointer v1,
83                      gconstpointer v2)
84 {
85   const ConstBytestreamIdentifier *left = v1;
86   const ConstBytestreamIdentifier *right = v2;
87 
88   return (!tp_strdiff (left->jid, right->jid)) &&
89       (!tp_strdiff (left->stream, right->stream));
90 }
91 
92 static guint
bytestream_id_hash(gconstpointer v)93 bytestream_id_hash (gconstpointer v)
94 {
95   const ConstBytestreamIdentifier *bsid = v;
96 
97   return g_str_hash (bsid->jid) ^ g_str_hash (bsid->stream);
98 }
99 
100 static BytestreamIdentifier *
bytestream_id_new(GabbleBytestreamIface * bytestream)101 bytestream_id_new (GabbleBytestreamIface *bytestream)
102 {
103   BytestreamIdentifier *bsid = g_slice_new (BytestreamIdentifier);
104 
105   g_object_get (bytestream,
106       "stream-id", &(bsid->stream),
107       "peer-jid", &(bsid->jid),
108       NULL);
109   return bsid;
110 }
111 
112 static void
bytestream_id_free(gpointer v)113 bytestream_id_free (gpointer v)
114 {
115   BytestreamIdentifier *bsid = v;
116 
117   g_free (bsid->jid);
118   g_free (bsid->stream);
119   g_slice_free (BytestreamIdentifier, bsid);
120 }
121 
122 static GabbleSocks5Proxy *
gabble_socks5_proxy_new(const gchar * jid,const gchar * host,guint16 port)123 gabble_socks5_proxy_new (const gchar *jid,
124                          const gchar *host,
125                          guint16 port)
126 {
127   GabbleSocks5Proxy *proxy;
128 
129   proxy = g_slice_new (GabbleSocks5Proxy);
130   proxy->jid = g_strdup (jid);
131   proxy->host = g_strdup (host);
132   proxy->port = port;
133 
134   return proxy;
135 }
136 
137 static void
gabble_socks5_proxy_free(GabbleSocks5Proxy * proxy)138 gabble_socks5_proxy_free (GabbleSocks5Proxy *proxy)
139 {
140   g_free (proxy->jid);
141   g_free (proxy->host);
142 
143   g_slice_free (GabbleSocks5Proxy, proxy);
144 }
145 
146 struct _GabbleBytestreamFactoryPrivate
147 {
148   GabbleConnection *conn;
149   guint iq_si_cb;
150   guint iq_ibb_cb;
151   guint iq_socks5_cb;
152   guint msg_data_cb;
153 
154   /* SI-initiated bytestreams - data sent by normal messages, IQs used to
155    * open and close.
156    *
157    * BytestreamIdentifier -> GabbleBytestreamIBB */
158   GHashTable *ibb_bytestreams;
159   /* BytestreamIdentifier -> GabbleBytestreamSocks5 */
160   GHashTable *socks5_bytestreams;
161 
162   /* MUC pseudo-IBB - data sent by groupchat messages, IQs not allowed.
163    *
164    * BytestreamIdentifier -> GabbleBytestreamMuc */
165   GHashTable *muc_bytestreams;
166 
167   /* SI-initiated bytestreams - real data sent through another bytestream.
168    *
169    * BytestreamIdentifier -> GabbleBytestreamMultiple */
170   GHashTable *multiple_bytestreams;
171 
172   /* List of GabbleSocks5Proxy discovered on the connection */
173   GSList *socks5_proxies;
174   /* List of GabbleSocks5Proxy found using the fallback-socks5-proxies param */
175   GSList *socks5_fallback_proxies;
176   /* List of SOCKS5's jids that have not been queried yet */
177   GSList *socks5_potential_proxies;
178   /* Next proxy on socks5_potential_proxies that we'll query */
179   GSList *next_query;
180 
181   /* Time stamp of the proxies list received from TELEPATHY_PROXIES_SERVICE */
182   GTimeVal proxies_list_stamp;
183 
184   gboolean dispose_has_run;
185 };
186 
187 #define GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE(obj) ((obj)->priv)
188 
189 static gboolean bytestream_factory_msg_data_cb (
190     WockyPorter *porter,
191     WockyStanza *msg,
192     gpointer user_data);
193 
194 static gboolean bytestream_factory_iq_si_cb (
195     WockyPorter *porter,
196     WockyStanza *msg,
197     gpointer user_data);
198 
199 static gboolean bytestream_factory_iq_ibb_cb (
200     WockyPorter *porter,
201     WockyStanza *msg,
202     gpointer user_data);
203 
204 static gboolean handle_socks5_query_iq (
205     WockyPorter *porter,
206     WockyStanza *msg,
207     gpointer user_data);
208 
209 static void query_proxies (GabbleBytestreamFactory *self,
210     guint nb_proxies_needed);
211 
212 static GSList * randomize_g_slist (GSList *list);
213 
214 static void
gabble_bytestream_factory_init(GabbleBytestreamFactory * self)215 gabble_bytestream_factory_init (GabbleBytestreamFactory *self)
216 {
217   GabbleBytestreamFactoryPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
218       GABBLE_TYPE_BYTESTREAM_FACTORY, GabbleBytestreamFactoryPrivate);
219 
220   self->priv = priv;
221 
222   priv->ibb_bytestreams = g_hash_table_new_full (bytestream_id_hash,
223       bytestream_id_equal, bytestream_id_free, g_object_unref);
224 
225   priv->muc_bytestreams = g_hash_table_new_full (bytestream_id_hash,
226       bytestream_id_equal, bytestream_id_free, g_object_unref);
227 
228   priv->socks5_bytestreams = g_hash_table_new_full (bytestream_id_hash,
229       bytestream_id_equal, bytestream_id_free, g_object_unref);
230 
231   priv->multiple_bytestreams = g_hash_table_new_full (bytestream_id_hash,
232       bytestream_id_equal, bytestream_id_free, g_object_unref);
233 
234   memset (&priv->proxies_list_stamp, 0, sizeof (GTimeVal));
235 }
236 
237 static gint
cmp_proxy(gconstpointer a,gconstpointer b)238 cmp_proxy (gconstpointer a,
239     gconstpointer b)
240 {
241   GabbleSocks5Proxy *proxy_a = (GabbleSocks5Proxy *) a;
242   GabbleSocks5Proxy *proxy_b = (GabbleSocks5Proxy *) b;
243 
244   /* Streamhost are identified by their jid */
245   return strcmp (proxy_a->jid, proxy_b->jid);
246 }
247 
248 static void
add_proxy_to_list(GabbleBytestreamFactory * self,GabbleSocks5Proxy * proxy,gboolean fallback)249 add_proxy_to_list (GabbleBytestreamFactory *self,
250     GabbleSocks5Proxy *proxy,
251     gboolean fallback)
252 {
253   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
254       self);
255   GSList **list;
256   GSList *found;
257 
258   if (fallback)
259     {
260       list = &priv->socks5_fallback_proxies;
261     }
262   else
263     {
264       list = &priv->socks5_proxies;
265     }
266 
267   found = g_slist_find_custom (*list, proxy, cmp_proxy);
268   if (found != NULL)
269     {
270       DEBUG ("%s SOCKS5 proxy (%s %s:%d) is already known; "
271           "move it to the head of the list",
272           fallback ? "Fallback": "Discovered",
273           proxy->jid, proxy->host, proxy->port);
274 
275       *list = g_slist_delete_link (*list, found);
276     }
277   else
278     {
279       DEBUG ("Add %s SOCKS5 proxy: %s %s:%d",
280           fallback ? "fallback": "discovered",
281           proxy->jid, proxy->host, proxy->port);
282 
283       if (fallback && g_slist_length (*list) >= FALLBACK_PROXY_CACHE_SIZE)
284         {
285           GSList *last;
286           GabbleSocks5Proxy *oldest;
287 
288           last = g_slist_last (*list);
289           oldest = last->data;
290 
291           DEBUG ("Proxy cache is full, remove the oldest entry (%s)",
292               oldest->jid);
293 
294           *list = g_slist_delete_link (*list, last);
295           gabble_socks5_proxy_free (oldest);
296         }
297     }
298 
299   *list = g_slist_prepend (*list, proxy);
300 }
301 
302 static void
socks5_proxy_query_reply_cb(GabbleConnection * conn,WockyStanza * sent_msg,WockyStanza * reply_msg,GObject * obj,gpointer user_data)303 socks5_proxy_query_reply_cb (GabbleConnection *conn,
304                              WockyStanza *sent_msg,
305                              WockyStanza *reply_msg,
306                              GObject *obj,
307                              gpointer user_data)
308 {
309   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (obj);
310   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
311       self);
312   WockyNode *query, *streamhost;
313   const gchar *from;
314   const gchar *jid, *host, *portstr;
315   gint64 port;
316   GabbleSocks5Proxy *proxy;
317   gboolean fallback = GPOINTER_TO_INT (user_data);
318   GSList *found = NULL;
319 
320   from = wocky_node_get_attribute (
321     wocky_stanza_get_top_node (reply_msg), "from");
322   if (from == NULL)
323     goto fail;
324 
325   if (wocky_stanza_extract_errors (reply_msg, NULL, NULL, NULL, NULL))
326     goto fail;
327 
328   query = wocky_node_get_child_ns (
329       wocky_stanza_get_top_node (reply_msg), "query", NS_BYTESTREAMS);
330   if (query == NULL)
331     goto fail;
332 
333   streamhost = wocky_node_get_child (query, "streamhost");
334   if (streamhost == NULL)
335     goto fail;
336 
337   jid = wocky_node_get_attribute (streamhost, "jid");
338   host = wocky_node_get_attribute (streamhost, "host");
339   portstr = wocky_node_get_attribute (streamhost, "port");
340 
341   if (jid == NULL || host == NULL || portstr == NULL)
342     goto fail;
343 
344   port = g_ascii_strtoll (portstr, NULL, 10);
345 
346   if (port <= 0 || port > G_MAXUINT16)
347     goto fail;
348 
349   proxy = gabble_socks5_proxy_new (jid, host, port);
350 
351   add_proxy_to_list (self , proxy, fallback);
352 
353   return;
354 
355 fail:
356   if (fallback && from != NULL)
357     {
358       /* Remove the buggy proxy so we won't query it anymore */
359       found = g_slist_find_custom (priv->socks5_potential_proxies,
360           from, (GCompareFunc) strcmp);
361 
362       if (found != NULL)
363         {
364           DEBUG ("remove proxy %s", from);
365           g_free (found->data);
366 
367           priv->socks5_potential_proxies = g_slist_delete_link (
368               priv->socks5_potential_proxies, found);
369         }
370     }
371 
372   /* Try to get another proxy as this one failed */
373   query_proxies (self, 1);
374 }
375 
376 static void
send_proxy_query(GabbleBytestreamFactory * self,const gchar * jid,gboolean fallback)377 send_proxy_query (GabbleBytestreamFactory *self,
378                   const gchar *jid,
379                   gboolean fallback)
380 {
381   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
382       self);
383   WockyStanza *query;
384 
385   DEBUG ("send SOCKS5 query to %s", jid);
386 
387   query = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_GET,
388       NULL, jid,
389       '(', "query",
390         ':', NS_BYTESTREAMS,
391       ')', NULL);
392 
393   _gabble_connection_send_with_reply (priv->conn, query,
394       socks5_proxy_query_reply_cb, G_OBJECT (self), GINT_TO_POINTER (fallback),
395       NULL);
396 
397   g_object_unref (query);
398 }
399 
400 static void
disco_item_found_cb(GabbleDisco * disco,GabbleDiscoItem * item,GabbleBytestreamFactory * self)401 disco_item_found_cb (GabbleDisco *disco,
402                      GabbleDiscoItem *item,
403                      GabbleBytestreamFactory *self)
404 {
405   if (tp_strdiff (item->category, "proxy") ||
406       tp_strdiff (item->type, "bytestreams"))
407     return;
408 
409   send_proxy_query (self, item->jid, FALSE);
410 }
411 
412 static void
query_proxies(GabbleBytestreamFactory * self,guint nb_proxies_needed)413 query_proxies (GabbleBytestreamFactory *self,
414     guint nb_proxies_needed)
415 {
416   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
417       self);
418   guint i;
419 
420   /* We don't want to query more than once the same proxy */
421   nb_proxies_needed = MIN (nb_proxies_needed,
422       g_slist_length (priv->socks5_potential_proxies));
423 
424   for (i = 0; i < nb_proxies_needed; i++)
425     {
426       gchar *jid;
427 
428       if (priv->next_query == NULL)
429         priv->next_query = priv->socks5_potential_proxies;
430 
431       jid = priv->next_query->data;
432       send_proxy_query (self, jid, TRUE);
433 
434       priv->next_query = g_slist_next (priv->next_query);
435     }
436 }
437 
438 static void
proxies_disco_cb(GabbleDisco * disco,GabbleDiscoRequest * request,const gchar * j,const gchar * n,WockyNode * query_result,GError * error,gpointer user_data)439 proxies_disco_cb (GabbleDisco *disco,
440     GabbleDiscoRequest *request,
441     const gchar *j,
442     const gchar *n,
443     WockyNode *query_result,
444     GError *error,
445     gpointer user_data)
446 {
447   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
448   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
449       self);
450   WockyNodeIter i;
451   WockyNode *node;
452   GSList *new_list = NULL;
453 
454   if (error != NULL)
455     {
456       DEBUG ("disco failed: %s", error->message);
457       return;
458     }
459 
460   wocky_node_iter_init (&i, query_result, "item", NULL);
461   while (wocky_node_iter_next (&i, &node))
462     {
463       const gchar *jid = wocky_node_get_attribute (node, "jid");
464       if (jid == NULL)
465         continue;
466 
467       DEBUG ("Discovered proxy %s", jid);
468 
469       new_list = g_slist_prepend (new_list, g_strdup (jid));
470     }
471 
472   g_get_current_time (&priv->proxies_list_stamp);
473 
474   if (new_list == NULL)
475     return;
476 
477   /* replace the old list by the new one */
478   g_slist_foreach (priv->socks5_potential_proxies, (GFunc) g_free, NULL);
479   g_slist_free (priv->socks5_potential_proxies);
480 
481   /* randomize the list to not always use the same proxies */
482   priv->socks5_potential_proxies = randomize_g_slist (new_list);
483   priv->next_query = priv->socks5_potential_proxies;
484 
485   gabble_bytestream_factory_query_socks5_proxies (self);
486 }
487 
488 /* Query TELEPATHY_PROXIES_SERVICE to get a list of proxies */
489 static void
get_proxies_list(GabbleBytestreamFactory * self)490 get_proxies_list (GabbleBytestreamFactory *self)
491 {
492   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
493       self);
494 
495   DEBUG ("Ask %s for proxies", TELEPATHY_PROXIES_SERVICE);
496 
497   gabble_disco_request (priv->conn->disco, GABBLE_DISCO_TYPE_ITEMS,
498       TELEPATHY_PROXIES_SERVICE, NULL, proxies_disco_cb, self, G_OBJECT (self),
499       NULL);
500 }
501 
502 /* ask to the factory to try to find more proxies if needed */
503 void
gabble_bytestream_factory_query_socks5_proxies(GabbleBytestreamFactory * self)504 gabble_bytestream_factory_query_socks5_proxies (GabbleBytestreamFactory *self)
505 {
506   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
507       self);
508   guint nb_proxies_found;
509   guint nb_proxies_needed;
510   GTimeVal now;
511 
512   if (priv->socks5_potential_proxies == NULL)
513     {
514       DEBUG ("No proxies list; request one");
515       get_proxies_list (self);
516       return;
517     }
518 
519   g_get_current_time (&now);
520   if (now.tv_sec - priv->proxies_list_stamp.tv_sec > PROXIES_LIST_LIFE_TIME)
521     {
522       DEBUG ("Proxies list has expired; request a new one");
523       get_proxies_list (self);
524     }
525 
526   nb_proxies_found = g_slist_length (priv->socks5_proxies) +
527     g_slist_length (priv->socks5_fallback_proxies);
528 
529   if (nb_proxies_found >= NB_MIN_SOCKS5_PROXIES)
530     {
531       DEBUG ("we already have discovered enough proxies (%u); "
532           "request just one to refresh our cache",
533           nb_proxies_found);
534       nb_proxies_needed = 1;
535     }
536   else
537     {
538       nb_proxies_needed = NB_MIN_SOCKS5_PROXIES - nb_proxies_found;
539       DEBUG ("Need %u more proxies", nb_proxies_needed);
540     }
541 
542   query_proxies (self, nb_proxies_needed);
543 }
544 
545 static GSList *
randomize_g_slist(GSList * list)546 randomize_g_slist (GSList *list)
547 {
548   guint len;
549   guint i;
550   GSList *new_head, *new_tail;
551 
552   len = g_slist_length (list);
553   if (len <= 1)
554     return list;
555 
556   i = g_random_int_range (0, len);
557   if (i == 0)
558     return list;
559 
560   /* Cut the list at the i th position and make it the new head of the
561    * list */
562   new_tail = g_slist_nth (list, i - 1);
563   g_assert (new_tail != NULL);
564 
565   new_head = new_tail->next;
566   g_assert (new_head != NULL);
567 
568   new_tail->next = NULL;
569 
570   return g_slist_concat (new_head, list);
571 }
572 
573 static void
porter_available_cb(GabbleConnection * conn,WockyPorter * porter,gpointer user_data)574 porter_available_cb (
575     GabbleConnection *conn,
576     WockyPorter *porter,
577     gpointer user_data)
578 {
579   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
580   GabbleBytestreamFactoryPrivate *priv = self->priv;
581 
582   priv->msg_data_cb = wocky_porter_register_handler_from_anyone (porter,
583       WOCKY_STANZA_TYPE_MESSAGE, WOCKY_STANZA_SUB_TYPE_NONE,
584       WOCKY_PORTER_HANDLER_PRIORITY_MAX,
585       bytestream_factory_msg_data_cb, self,
586       NULL);
587 
588   priv->iq_si_cb = wocky_porter_register_handler_from_anyone (porter,
589       WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
590       WOCKY_PORTER_HANDLER_PRIORITY_MAX,
591       bytestream_factory_iq_si_cb, self,
592       '(', "si", ':', NS_SI,
593       ')',
594       NULL);
595 
596   priv->iq_ibb_cb = wocky_porter_register_handler_from_anyone (porter,
597       WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_NONE,
598       WOCKY_PORTER_HANDLER_PRIORITY_MAX,
599       bytestream_factory_iq_ibb_cb, self,
600       NULL);
601 
602   priv->iq_socks5_cb = wocky_porter_register_handler_from_anyone (porter,
603       WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
604       WOCKY_PORTER_HANDLER_PRIORITY_MAX,
605       handle_socks5_query_iq, self,
606       '(', "query", ':', NS_BYTESTREAMS, ')',
607       NULL);
608 }
609 
610 static void
conn_status_changed_cb(GabbleConnection * conn,TpConnectionStatus status,TpConnectionStatusReason reason,gpointer user_data)611 conn_status_changed_cb (GabbleConnection *conn,
612                         TpConnectionStatus status,
613                         TpConnectionStatusReason reason,
614                         gpointer user_data)
615 {
616   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
617   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
618       self);
619 
620   if (status == TP_CONNECTION_STATUS_CONNECTED)
621     {
622       GStrv jids;
623       guint i;
624 
625       /* we can't intialize socks5_potential_proxies in the constructor
626        * because Connection's properties are not set yet at this point */
627       g_object_get (priv->conn, "fallback-socks5-proxies", &jids, NULL);
628 
629       for (i = 0; jids != NULL && jids[i] != NULL; i++)
630         {
631           priv->socks5_potential_proxies = g_slist_prepend (
632               priv->socks5_potential_proxies, g_strdup (jids[i]));
633         }
634 
635       /* randomize the list to not always use the same proxies */
636       priv->socks5_potential_proxies = randomize_g_slist (
637               priv->socks5_potential_proxies);
638 
639       priv->next_query = priv->socks5_potential_proxies;
640 
641       g_strfreev (jids);
642     }
643 }
644 
645 static GObject *
gabble_bytestream_factory_constructor(GType type,guint n_props,GObjectConstructParam * props)646 gabble_bytestream_factory_constructor (GType type,
647                                        guint n_props,
648                                        GObjectConstructParam *props)
649 {
650   GObject *obj;
651   GabbleBytestreamFactory *self;
652   GabbleBytestreamFactoryPrivate *priv;
653 
654   obj = G_OBJECT_CLASS (gabble_bytestream_factory_parent_class)->
655            constructor (type, n_props, props);
656 
657   self = GABBLE_BYTESTREAM_FACTORY (obj);
658   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
659 
660   /* Track SOCKS5 proxy available on the connection */
661   gabble_signal_connect_weak (priv->conn->disco, "item-found",
662       G_CALLBACK (disco_item_found_cb), G_OBJECT (self));
663 
664   gabble_signal_connect_weak (priv->conn, "status-changed",
665       G_CALLBACK (conn_status_changed_cb), G_OBJECT (self));
666   tp_g_signal_connect_object (priv->conn, "porter-available",
667       G_CALLBACK (porter_available_cb), self, 0);
668 
669   return obj;
670 }
671 
672 static void
gabble_bytestream_factory_dispose(GObject * object)673 gabble_bytestream_factory_dispose (GObject *object)
674 {
675   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (object);
676   GabbleBytestreamFactoryPrivate *priv =
677     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
678   GSList *proxies, *l;
679 
680   if (priv->dispose_has_run)
681     return;
682 
683   DEBUG ("dispose called");
684   priv->dispose_has_run = TRUE;
685 
686   if (priv->msg_data_cb != 0)
687     {
688       WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
689 
690       wocky_porter_unregister_handler (porter, priv->msg_data_cb);
691       wocky_porter_unregister_handler (porter, priv->iq_si_cb);
692       wocky_porter_unregister_handler (porter, priv->iq_ibb_cb);
693       wocky_porter_unregister_handler (porter, priv->iq_socks5_cb);
694     }
695 
696   g_hash_table_unref (priv->ibb_bytestreams);
697   priv->ibb_bytestreams = NULL;
698 
699   g_hash_table_unref (priv->muc_bytestreams);
700   priv->muc_bytestreams = NULL;
701 
702   g_hash_table_unref (priv->socks5_bytestreams);
703   priv->socks5_bytestreams = NULL;
704 
705   g_hash_table_unref (priv->multiple_bytestreams);
706   priv->multiple_bytestreams = NULL;
707 
708   proxies = g_slist_concat (priv->socks5_proxies,
709       priv->socks5_fallback_proxies);
710 
711   for (l = proxies; l != NULL; l = g_slist_next (l))
712     {
713       GabbleSocks5Proxy *proxy = (GabbleSocks5Proxy *) l->data;
714 
715       gabble_socks5_proxy_free (proxy);
716     }
717   g_slist_free (proxies);
718 
719   priv->socks5_proxies = NULL;
720   priv->socks5_fallback_proxies = NULL;
721 
722   g_slist_foreach (priv->socks5_potential_proxies, (GFunc) g_free, NULL);
723   g_slist_free (priv->socks5_potential_proxies);
724   priv->socks5_potential_proxies = NULL;
725 
726   if (G_OBJECT_CLASS (gabble_bytestream_factory_parent_class)->dispose)
727     G_OBJECT_CLASS (gabble_bytestream_factory_parent_class)->dispose (object);
728 }
729 
730 static void
gabble_bytestream_factory_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)731 gabble_bytestream_factory_get_property (GObject *object,
732                                         guint property_id,
733                                         GValue *value,
734                                         GParamSpec *pspec)
735 {
736   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (object);
737   GabbleBytestreamFactoryPrivate *priv =
738     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
739 
740   switch (property_id)
741     {
742       case PROP_CONNECTION:
743         g_value_set_object (value, priv->conn);
744         break;
745       default:
746         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
747         break;
748     }
749 }
750 
751 static void
gabble_bytestream_factory_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)752 gabble_bytestream_factory_set_property (GObject *object,
753                                         guint property_id,
754                                         const GValue *value,
755                                         GParamSpec *pspec)
756 {
757   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (object);
758   GabbleBytestreamFactoryPrivate *priv =
759     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
760 
761   switch (property_id)
762     {
763       case PROP_CONNECTION:
764         priv->conn = g_value_get_object (value);
765         break;
766       default:
767         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
768         break;
769     }
770 }
771 
772 static void
gabble_bytestream_factory_class_init(GabbleBytestreamFactoryClass * gabble_bytestream_factory_class)773 gabble_bytestream_factory_class_init (
774     GabbleBytestreamFactoryClass *gabble_bytestream_factory_class)
775 {
776   GObjectClass *object_class =
777     G_OBJECT_CLASS (gabble_bytestream_factory_class);
778   GParamSpec *param_spec;
779 
780   g_type_class_add_private (gabble_bytestream_factory_class,
781       sizeof (GabbleBytestreamFactoryPrivate));
782 
783   object_class->constructor = gabble_bytestream_factory_constructor;
784   object_class->dispose = gabble_bytestream_factory_dispose;
785 
786   object_class->get_property = gabble_bytestream_factory_get_property;
787   object_class->set_property = gabble_bytestream_factory_set_property;
788 
789   param_spec = g_param_spec_object (
790       "connection",
791       "GabbleConnection object",
792       "Gabble connection object that owns this bytestream factory object.",
793       GABBLE_TYPE_CONNECTION,
794       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
795   g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
796 }
797 
798 static void
remove_bytestream(GabbleBytestreamFactory * self,GabbleBytestreamIface * bytestream)799 remove_bytestream (GabbleBytestreamFactory *self,
800                    GabbleBytestreamIface *bytestream)
801 {
802   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE
803     (self);
804   BytestreamIdentifier bsid = { NULL, NULL };
805   guint handle_type;
806   GHashTable *table = NULL;
807 
808   g_object_get (bytestream,
809       "stream-id", &(bsid.stream),
810       "peer-jid", &(bsid.jid),
811       "peer-handle-type", &handle_type,
812       NULL);
813 
814   if (handle_type == TP_HANDLE_TYPE_ROOM)
815     {
816       table = priv->muc_bytestreams;
817     }
818   else
819     {
820       if (GABBLE_IS_BYTESTREAM_IBB (bytestream))
821         table = priv->ibb_bytestreams;
822       else if (GABBLE_IS_BYTESTREAM_SOCKS5 (bytestream))
823         table = priv->socks5_bytestreams;
824       else if (GABBLE_IS_BYTESTREAM_MULTIPLE (bytestream))
825         table = priv->multiple_bytestreams;
826     }
827 
828   if (table == NULL)
829     return;
830 
831   DEBUG ("removing bytestream: <%s> from <%s>", bsid.stream, bsid.jid);
832   g_hash_table_remove (table, &bsid);
833 
834   g_free (bsid.stream);
835   g_free (bsid.jid);
836 }
837 
838 /**
839  * streaminit_parse_request
840  *
841  * Parses a SI request, or returns FALSE if it can't be parsed.
842  *
843  * The items in the linked list of stream methods are borrowed
844  * from the message; their lifetime is only as long as that of the
845  * message.
846  */
847 static gboolean
streaminit_parse_request(WockyStanza * message,WockyNode * si,const gchar ** profile,const gchar ** from,const gchar ** stream_id,const gchar ** stream_init_id,const gchar ** mime_type,GSList ** stream_methods,gboolean * multiple)848 streaminit_parse_request (WockyStanza *message,
849                           WockyNode *si,
850                           const gchar **profile,
851                           const gchar **from,
852                           const gchar **stream_id,
853                           const gchar **stream_init_id,
854                           const gchar **mime_type,
855                           GSList **stream_methods,
856                           gboolean *multiple)
857 {
858   WockyNode *iq = wocky_stanza_get_top_node (message);
859   WockyNode *feature, *x, *si_multiple, *field;
860   WockyNodeIter i, j;
861 
862   *stream_init_id = wocky_node_get_attribute (iq, "id");
863 
864   *from = wocky_node_get_attribute (iq, "from");
865   if (*from == NULL)
866     {
867       STANZA_DEBUG (message, "got a message without a from field");
868       return FALSE;
869     }
870 
871   /* Parse <si> */
872 
873   *stream_id = wocky_node_get_attribute (si, "id");
874   if (*stream_id == NULL)
875     {
876       STANZA_DEBUG (message, "got a SI request without a stream id field");
877       return FALSE;
878     }
879 
880   *mime_type = wocky_node_get_attribute (si, "mime-type");
881   /* if no mime_type is defined, XEP-0095 says to assume "binary/octect-stream"
882    * which is presumably a typo for "application/octet-stream" */
883 
884   *profile = wocky_node_get_attribute (si, "profile");
885   if (*profile == NULL)
886     {
887       STANZA_DEBUG (message, "got a SI request without a profile field");
888       return FALSE;
889     }
890 
891   /* Parse <feature> */
892   feature = wocky_node_get_child_ns (si, "feature",
893       NS_FEATURENEG);
894   if (feature == NULL)
895     {
896       STANZA_DEBUG (message, "got a SI request without a feature field");
897       return FALSE;
898     }
899 
900   x = wocky_node_get_child_ns (feature, "x", NS_X_DATA);
901   if (x == NULL)
902     {
903       STANZA_DEBUG (message, "got a SI request without a X data field");
904       return FALSE;
905     }
906 
907   wocky_node_iter_init (&i, x, NULL, NULL);
908   while (wocky_node_iter_next (&i, &field))
909     {
910       WockyNode *stream_method;
911 
912       if (tp_strdiff (wocky_node_get_attribute (field, "var"),
913             "stream-method"))
914         /* some future field, ignore it */
915         continue;
916 
917       if (tp_strdiff (wocky_node_get_attribute (field, "type"),
918             "list-single"))
919         {
920           STANZA_DEBUG (message, "SI request's stream-method field was "
921               "not of type list-single");
922           return FALSE;
923         }
924 
925       /* Get the stream methods offered */
926       *stream_methods = NULL;
927       wocky_node_iter_init (&j, field, NULL, NULL);
928       while (wocky_node_iter_next (&j, &stream_method))
929         {
930           WockyNode *value;
931           const gchar *stream_method_str;
932 
933           value = wocky_node_get_child (stream_method, "value");
934           if (value == NULL)
935             continue;
936 
937           stream_method_str = value->content;
938           if (!tp_strdiff (stream_method_str, ""))
939             continue;
940 
941           DEBUG ("Got stream-method %s", stream_method_str);
942 
943           /* Append to the stream_methods list */
944           *stream_methods = g_slist_append (*stream_methods,
945               (gchar *) stream_method_str);
946         }
947 
948       /* no need to parse the rest of the fields, we've found the one we
949        * wanted */
950       break;
951     }
952 
953   if (*stream_methods == NULL)
954     {
955       STANZA_DEBUG (message,
956           "got a SI request without stream method proposed");
957       return FALSE;
958     }
959 
960   si_multiple = wocky_node_get_child_ns (si, "si-multiple", NS_SI_MULTIPLE);
961   if (si_multiple == NULL)
962     *multiple = FALSE;
963   else
964     *multiple = TRUE;
965 
966   return TRUE;
967 }
968 
969 /**
970  * gabble_bytestream_factory_make_stream_init_iq
971  *
972  * @full_jid: the full jid of the contact to whom we want to offer the stream
973  * @stream_id: the stream ID of the new stream
974  * @profile: the profile associated with the stream
975  *
976  * Create a SI request IQ as described in XEP-0095.
977  *
978  * The MIME type is not set - the receiving client will assume
979  * application/octet-stream unless the caller sets a MIME type explicitly.
980  */
981 WockyStanza *
gabble_bytestream_factory_make_stream_init_iq(const gchar * full_jid,const gchar * stream_id,const gchar * profile)982 gabble_bytestream_factory_make_stream_init_iq (const gchar *full_jid,
983                                                const gchar *stream_id,
984                                                const gchar *profile)
985 {
986   return wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_SET,
987       NULL, full_jid,
988       '(', "si",
989         ':', NS_SI,
990         '@', "id", stream_id,
991         '@', "profile", profile,
992         '(', "feature",
993           ':', NS_FEATURENEG,
994           '(', "x",
995             ':', NS_X_DATA,
996             '@', "type", "form",
997             '(', "field",
998               '@', "var", "stream-method",
999               '@', "type", "list-single",
1000               '(', "option",
1001                 '(', "value", '$', NS_BYTESTREAMS,
1002                 ')',
1003               ')',
1004               '(', "option",
1005                 '(', "value", '$', NS_IBB,
1006                 ')',
1007               ')',
1008             ')',
1009           ')',
1010         ')',
1011         '(', "si-multiple",
1012           ':', NS_SI_MULTIPLE,
1013         ')',
1014       ')', NULL);
1015 }
1016 
1017 static gboolean
stream_method_supported(const gchar * stream_method)1018 stream_method_supported (const gchar *stream_method)
1019 {
1020   /* IBB */
1021   if (!tp_strdiff (stream_method, NS_IBB))
1022     return TRUE;
1023 
1024   /* Sock5 */
1025   if (!tp_strdiff (stream_method, NS_BYTESTREAMS))
1026     return TRUE;
1027 
1028   return FALSE;
1029 }
1030 
1031 static GabbleBytestreamMultiple *gabble_bytestream_factory_create_multiple (
1032     GabbleBytestreamFactory *self, TpHandle peer_handle,
1033     const gchar *stream_id, const gchar *stream_init_id,
1034     const gchar *peer_resource, const gchar *self_jid,
1035     GabbleBytestreamState state);
1036 
1037 static GabbleBytestreamIBB *gabble_bytestream_factory_create_ibb (
1038     GabbleBytestreamFactory *fac, TpHandle peer_handle, const gchar *stream_id,
1039     const gchar *stream_init_id, const gchar *peer_resource,
1040     GabbleBytestreamState state);
1041 
1042 static GabbleBytestreamSocks5 *gabble_bytestream_factory_create_socks5 (
1043     GabbleBytestreamFactory *fac, TpHandle peer_handle, const gchar *stream_id,
1044     const gchar *stream_init_id, const gchar *peer_resource,
1045     const gchar *self_jid, GabbleBytestreamState state);
1046 
1047 static void
si_tube_received(GabbleBytestreamFactory * self,WockyStanza * msg,WockyNode * si,GabbleBytestreamIface * bytestream,TpHandle peer_handle,TpHandle room_handle,const gchar * stream_id)1048 si_tube_received (GabbleBytestreamFactory *self,
1049                   WockyStanza *msg,
1050                   WockyNode *si,
1051                   GabbleBytestreamIface *bytestream,
1052                   TpHandle peer_handle,
1053                   TpHandle room_handle,
1054                   const gchar *stream_id)
1055 {
1056   GabbleBytestreamFactoryPrivate *priv =
1057     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1058 
1059   /* A Tubes SI request can be:
1060    *  - a 1-1 new tube offer
1061    *  - a 1-1 tube extra bytestream offer
1062    *  - a muc tube extra bytestream offer
1063    */
1064   if (wocky_node_get_child_ns (si, "tube", NS_TUBES) != NULL)
1065     {
1066       /* The SI request is a tube offer */
1067        gabble_private_tubes_factory_handle_si_tube_request (
1068            priv->conn->private_tubes_factory, bytestream, peer_handle,
1069            stream_id, msg);
1070     }
1071   else if (wocky_node_get_child_ns (si, "stream", NS_TUBES)
1072       != NULL)
1073     {
1074       /* The SI request is an extra bytestream for a 1-1 tube */
1075       gabble_private_tubes_factory_handle_si_stream_request (
1076           priv->conn->private_tubes_factory, bytestream, peer_handle,
1077           stream_id, msg);
1078     }
1079   else if (wocky_node_get_child_ns (si, "muc-stream",
1080         NS_TUBES) != NULL)
1081     {
1082       /* The SI request is an extra bytestream for a muc tube */
1083 
1084       if (room_handle == 0)
1085         {
1086           GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
1087               "<muc-stream> is only valid in a MUC context" };
1088 
1089           gabble_bytestream_iface_close (bytestream, &e);
1090         }
1091       else
1092         {
1093           gabble_muc_factory_handle_si_stream_request (priv->conn->muc_factory,
1094               bytestream, room_handle, stream_id, msg);
1095         }
1096     }
1097   else
1098     {
1099       GError e = { WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
1100           "Invalid tube SI request: expected <tube>, <stream> or "
1101           "<muc-stream>" };
1102 
1103       /* Invalid tube SI request */
1104       STANZA_DEBUG (msg, e.message);
1105       gabble_bytestream_iface_close (bytestream, &e);
1106     }
1107 }
1108 
1109 /**
1110  * bytestream_factory_iq_si_cb:
1111  *
1112  * Called by Wocky when we get an incoming <iq>. This handler is concerned
1113  * with Stream Initiation requests (XEP-0095).
1114  *
1115  */
1116 static gboolean
bytestream_factory_iq_si_cb(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1117 bytestream_factory_iq_si_cb (
1118     WockyPorter *porter,
1119     WockyStanza *msg,
1120     gpointer user_data)
1121 {
1122   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1123   GabbleBytestreamFactoryPrivate *priv =
1124     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1125   TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
1126       (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_CONTACT);
1127   TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
1128       (TpBaseConnection *) priv->conn, TP_HANDLE_TYPE_ROOM);
1129   WockyNode *si;
1130   TpHandle peer_handle = 0, room_handle;
1131   GabbleBytestreamIface *bytestream = NULL;
1132   GSList *l;
1133   const gchar *profile, *from, *stream_id, *stream_init_id, *mime_type;
1134   GSList *stream_methods = NULL;
1135   gboolean multiple;
1136   gchar *peer_resource = NULL;
1137   gchar *self_jid = NULL;
1138 
1139   si = wocky_node_get_child_ns (
1140     wocky_stanza_get_top_node (msg), "si", NS_SI);
1141   g_return_val_if_fail (si != NULL, FALSE);
1142 
1143   /* after this point, the message is for us, so in all cases we either handle
1144    * it or send an error reply */
1145 
1146   if (!streaminit_parse_request (msg, si, &profile, &from, &stream_id,
1147         &stream_init_id, &mime_type, &stream_methods, &multiple))
1148     {
1149       wocky_porter_send_iq_error (porter, msg,
1150           WOCKY_XMPP_ERROR_BAD_REQUEST, "failed to parse SI request");
1151       goto out;
1152     }
1153 
1154   DEBUG ("received a SI request");
1155 
1156   room_handle = gabble_get_room_handle_from_jid (room_repo, from);
1157 
1158   if (room_handle == 0)
1159     {
1160       /* jid is not a muc jid so we need contact's resource */
1161 
1162       if (!wocky_decode_jid (from, NULL, NULL, &peer_resource))
1163         {
1164           DEBUG ("Got an SI IQ response from a bad JID. Ignoring.");
1165           goto out;
1166         }
1167 
1168       if (!peer_resource)
1169         {
1170           DEBUG ("Got an SI IQ response from a JID without a resource."
1171               "Ignoring.");
1172           goto out;
1173         }
1174 
1175       peer_handle = tp_handle_ensure (contact_repo, from, NULL, NULL);
1176 
1177       /* we are not in a muc so our own jid is the one in the 'to' attribute */
1178       self_jid = g_strdup (wocky_node_get_attribute (
1179         wocky_stanza_get_top_node (msg), "to"));
1180     }
1181   else
1182     {
1183       /* we are in a muc so need to get our muc jid */
1184       GabbleMucChannel *muc;
1185 
1186       peer_handle = tp_handle_ensure (contact_repo, from,
1187           GUINT_TO_POINTER (GABBLE_JID_ROOM_MEMBER), NULL);
1188 
1189       muc = gabble_muc_factory_find_text_channel (priv->conn->muc_factory,
1190           room_handle);
1191 
1192       if (muc == NULL)
1193         {
1194           DEBUG ("Got an IQ from a muc in which we are not. Ignoring.");
1195           goto out;
1196         }
1197 
1198       g_object_get (muc, "self-jid", &self_jid, NULL);
1199     }
1200 
1201   if (peer_handle == 0)
1202     {
1203       wocky_porter_send_iq_error (porter, msg,
1204           WOCKY_XMPP_ERROR_JID_MALFORMED, NULL);
1205       goto out;
1206     }
1207 
1208   if (multiple)
1209     {
1210       DEBUG ("Receiver supports multi bytestreams");
1211 
1212       bytestream = (GabbleBytestreamIface *)
1213           gabble_bytestream_factory_create_multiple (self, peer_handle,
1214             stream_id, stream_init_id, peer_resource, self_jid,
1215             GABBLE_BYTESTREAM_STATE_LOCAL_PENDING);
1216     }
1217 
1218   /* check stream method */
1219   for (l = stream_methods; l != NULL; l = l->next)
1220     {
1221       if (multiple)
1222         {
1223           if (stream_method_supported (l->data))
1224             {
1225               DEBUG ("add %s to multi-bytestream methods",
1226                   (const gchar *) l->data);
1227 
1228               gabble_bytestream_multiple_add_stream_method (
1229                   GABBLE_BYTESTREAM_MULTIPLE (bytestream), l->data);
1230             }
1231           else
1232             {
1233               DEBUG ("skip unsupported stream method: %s",
1234                   (const gchar *) l->data);
1235             }
1236         }
1237       else
1238         {
1239           /* We create the stream according the stream method chosen.
1240            * User has to accept it */
1241           DEBUG ("Receiver doesn't support multi bytestreams. He chose %s",
1242               (const gchar *) l->data);
1243 
1244           bytestream = gabble_bytestream_factory_create_from_method (self,
1245               l->data, peer_handle, stream_id, stream_init_id, peer_resource,
1246               self_jid, GABBLE_BYTESTREAM_STATE_LOCAL_PENDING);
1247           if (bytestream != NULL)
1248             break;
1249         }
1250     }
1251 
1252   if (bytestream == NULL)
1253     {
1254       GError error = { WOCKY_SI_ERROR, WOCKY_SI_ERROR_NO_VALID_STREAMS, "" };
1255 
1256       DEBUG ("SI request doesn't contain any supported stream methods.");
1257       wocky_porter_send_iq_gerror (porter, msg, &error);
1258       goto out;
1259     }
1260 
1261   if (multiple)
1262     {
1263       /* Is there at least one stream method? */
1264       if (!gabble_bytestream_multiple_has_stream_method (
1265             GABBLE_BYTESTREAM_MULTIPLE (bytestream)))
1266         {
1267           GError e = { WOCKY_SI_ERROR, WOCKY_SI_ERROR_NO_VALID_STREAMS, "" };
1268           DEBUG ("No valid stream method in the multi bytestream. Closing");
1269 
1270           gabble_bytestream_iface_close (bytestream, &e);
1271           goto out;
1272         }
1273     }
1274 
1275   /* Now that we have a bytestream, it's responsible for declining the IQ
1276    * if needed. */
1277 
1278   /* We inform the right factory we received a SI request */
1279   if (!tp_strdiff (profile, NS_TUBES))
1280     {
1281       si_tube_received (self, msg, si, bytestream, peer_handle, room_handle,
1282           stream_id);
1283     }
1284 #ifdef ENABLE_FILE_TRANSFER
1285   else if (!tp_strdiff (profile, NS_FILE_TRANSFER))
1286     {
1287       gabble_ft_manager_handle_si_request (priv->conn->ft_manager, bytestream,
1288           peer_handle, stream_id, msg);
1289     }
1290 #endif
1291   else
1292     {
1293       GError e = { WOCKY_SI_ERROR, WOCKY_SI_ERROR_BAD_PROFILE, "" };
1294       DEBUG ("SI profile unsupported: %s", profile);
1295 
1296       gabble_bytestream_iface_close (bytestream, &e);
1297     }
1298 
1299 out:
1300   g_slist_free (stream_methods);
1301   g_free (peer_resource);
1302   g_free (self_jid);
1303 
1304   return TRUE;
1305 }
1306 
1307 static gboolean
handle_ibb_open_iq(GabbleBytestreamFactory * self,WockyStanza * msg)1308 handle_ibb_open_iq (GabbleBytestreamFactory *self,
1309                     WockyStanza *msg)
1310 {
1311   GabbleBytestreamFactoryPrivate *priv =
1312     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1313   WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
1314   GabbleBytestreamIBB *bytestream;
1315   WockyNode *open_node;
1316   ConstBytestreamIdentifier bsid = { NULL, NULL };
1317   const gchar *tmp;
1318   guint state;
1319   WockyStanzaSubType sub_type;
1320 
1321   wocky_stanza_get_type_info (msg, NULL, &sub_type);
1322   if (sub_type != WOCKY_STANZA_SUB_TYPE_SET)
1323     return FALSE;
1324 
1325   open_node = wocky_node_get_child_ns (
1326       wocky_stanza_get_top_node (msg), "open", NS_IBB);
1327   if (open_node == NULL)
1328     return FALSE;
1329 
1330   bsid.jid = wocky_node_get_attribute (
1331       wocky_stanza_get_top_node (msg), "from");
1332   if (bsid.jid == NULL)
1333     {
1334       DEBUG ("got a message without a from field");
1335       wocky_porter_send_iq_error (porter, msg,
1336           WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1337       return TRUE;
1338     }
1339 
1340   bsid.stream = wocky_node_get_attribute (open_node, "sid");
1341   if (bsid.stream == NULL)
1342     {
1343       DEBUG ("IBB open stanza doesn't contain stream id");
1344       wocky_porter_send_iq_error (porter, msg,
1345           WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1346       return TRUE;
1347     }
1348 
1349   bytestream = g_hash_table_lookup (priv->ibb_bytestreams, &bsid);
1350   if (bytestream == NULL)
1351     {
1352       /* We don't accept streams not previously announced using SI */
1353       DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1354       wocky_porter_send_iq_error (porter, msg,
1355           WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1356       return TRUE;
1357     }
1358 
1359   g_object_get (bytestream, "state", &state, NULL);
1360 
1361   if (state != GABBLE_BYTESTREAM_STATE_ACCEPTED)
1362     {
1363       /* We don't accept streams not previously accepted using SI */
1364       DEBUG ("unaccepted stream: <%s> from <%s>", bsid.stream, bsid.jid);
1365       wocky_porter_send_iq_error (porter, msg,
1366           WOCKY_XMPP_ERROR_BAD_REQUEST, NULL);
1367       return TRUE;
1368     }
1369 
1370   tmp = wocky_node_get_attribute (open_node, "block-size");
1371   if (tmp != NULL)
1372     {
1373       guint block_size = strtoul (tmp, NULL, 10);
1374 
1375       if (block_size > 0)
1376         g_object_set (bytestream, "block-size", block_size, NULL);
1377     }
1378 
1379   g_object_set (bytestream, "state", GABBLE_BYTESTREAM_STATE_OPEN,
1380       NULL);
1381 
1382   wocky_porter_acknowledge_iq (porter, msg, NULL);
1383 
1384   return TRUE;
1385 }
1386 
1387 static gboolean
handle_ibb_close_iq(GabbleBytestreamFactory * self,WockyStanza * msg)1388 handle_ibb_close_iq (GabbleBytestreamFactory *self,
1389                      WockyStanza *msg)
1390 {
1391   GabbleBytestreamFactoryPrivate *priv =
1392     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1393   WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
1394   ConstBytestreamIdentifier bsid = { NULL, NULL };
1395   GabbleBytestreamIBB *bytestream;
1396   WockyNode *close_node;
1397   WockyStanzaSubType sub_type;
1398 
1399   wocky_stanza_get_type_info (msg, NULL, &sub_type);
1400   if (sub_type != WOCKY_STANZA_SUB_TYPE_SET)
1401     return FALSE;
1402 
1403   close_node = wocky_node_get_child_ns (
1404       wocky_stanza_get_top_node (msg), "close", NS_IBB);
1405   if (close_node == NULL)
1406     return FALSE;
1407 
1408   bsid.jid = wocky_node_get_attribute (wocky_stanza_get_top_node (msg),
1409       "from");
1410   if (bsid.jid == NULL)
1411     {
1412       DEBUG ("got a message without a from field");
1413       wocky_porter_send_iq_error (porter, msg,
1414           WOCKY_XMPP_ERROR_BAD_REQUEST, "IBB <close> has no 'from' attribute");
1415       return TRUE;
1416     }
1417 
1418   bsid.stream = wocky_node_get_attribute (close_node, "sid");
1419   if (bsid.stream == NULL)
1420     {
1421       DEBUG ("IBB close stanza doesn't contain stream id");
1422       wocky_porter_send_iq_error (porter, msg,
1423           WOCKY_XMPP_ERROR_BAD_REQUEST, "IBB <close> has no stream ID");
1424       return TRUE;
1425     }
1426 
1427   bytestream = g_hash_table_lookup (priv->ibb_bytestreams, &bsid);
1428   if (bytestream == NULL)
1429     {
1430       DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1431       wocky_porter_send_iq_error (porter, msg,
1432           WOCKY_XMPP_ERROR_ITEM_NOT_FOUND, NULL);
1433     }
1434   else
1435     {
1436       gabble_bytestream_ibb_close_received (bytestream, msg);
1437     }
1438 
1439   return TRUE;
1440 }
1441 
1442 /* IBB can be transported over either IQs or messages, so msg can either be
1443  * an <iq> or a <message>. If it's an <iq> we need to reply to it.
1444  *
1445  * Return TRUE if we take responsibility for this message. */
1446 static gboolean
handle_ibb_data(GabbleBytestreamFactory * self,WockyStanza * msg,gboolean is_iq)1447 handle_ibb_data (GabbleBytestreamFactory *self,
1448                  WockyStanza *msg,
1449                  gboolean is_iq)
1450 {
1451   GabbleBytestreamFactoryPrivate *priv =
1452     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1453   WockyPorter *porter = wocky_session_get_porter (priv->conn->session);
1454   GabbleBytestreamIBB *bytestream = NULL;
1455   WockyNode *data;
1456   ConstBytestreamIdentifier bsid = { NULL, NULL };
1457   WockyStanzaSubType sub_type;
1458 
1459   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1460 
1461   wocky_stanza_get_type_info (msg, NULL, &sub_type);
1462   if (is_iq && sub_type != WOCKY_STANZA_SUB_TYPE_SET)
1463     return FALSE;
1464 
1465   data = wocky_node_get_child_ns (
1466       wocky_stanza_get_top_node (msg), "data", NS_IBB);
1467   if (data == NULL)
1468     return FALSE;
1469 
1470   bsid.jid = wocky_node_get_attribute (wocky_stanza_get_top_node (msg),
1471     "from");
1472   if (bsid.jid == NULL)
1473     {
1474       DEBUG ("got a message without a from field");
1475       if (is_iq)
1476         wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1477             "IBB <close> has no 'from' attribute");
1478       return TRUE;
1479     }
1480 
1481   bsid.stream = wocky_node_get_attribute (data, "sid");
1482   if (bsid.stream == NULL)
1483     {
1484       DEBUG ("got a IBB message data without a stream id field");
1485       if (is_iq)
1486         wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1487             "IBB <data> needs a stream ID");
1488       return TRUE;
1489     }
1490 
1491   bytestream = g_hash_table_lookup (priv->ibb_bytestreams, &bsid);
1492 
1493   if (bytestream == NULL)
1494     {
1495       DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1496       if (is_iq)
1497         wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1498             "IBB <data> has unknown stream ID");
1499 
1500       return TRUE;
1501     }
1502 
1503   gabble_bytestream_ibb_receive (bytestream, msg, is_iq);
1504 
1505   return TRUE;
1506 }
1507 
1508 static gboolean
handle_muc_data(GabbleBytestreamFactory * self,WockyStanza * msg)1509 handle_muc_data (GabbleBytestreamFactory *self,
1510                  WockyStanza *msg)
1511 {
1512   GabbleBytestreamFactoryPrivate *priv =
1513     GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1514   GabbleBytestreamMuc *bytestream = NULL;
1515   WockyNode *data;
1516   ConstBytestreamIdentifier bsid = { NULL, NULL };
1517   gchar *room_name;
1518   const gchar *from;
1519 
1520   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1521 
1522   data = wocky_node_get_child_ns (
1523       wocky_stanza_get_top_node (msg), "data", NS_MUC_BYTESTREAM);
1524   if (data == NULL)
1525     return FALSE;
1526 
1527   from = wocky_node_get_attribute (
1528       wocky_stanza_get_top_node (msg), "from");
1529   if (from == NULL)
1530     {
1531       DEBUG ("got a message without a from field");
1532       return TRUE;
1533     }
1534 
1535   bsid.stream = wocky_node_get_attribute (data, "sid");
1536   if (bsid.stream == NULL)
1537     {
1538       DEBUG ("got a pseudo IBB muc message data without a stream id field");
1539       return TRUE;
1540     }
1541 
1542   room_name = gabble_remove_resource (from);
1543   bsid.jid = room_name;
1544   bytestream = g_hash_table_lookup (priv->muc_bytestreams, &bsid);
1545 
1546   if (bytestream == NULL)
1547     {
1548       DEBUG ("unknown muc stream: <%s> from <%s>", bsid.stream, bsid.jid);
1549       g_free (room_name);
1550       return TRUE;
1551     }
1552   g_assert (GABBLE_IS_BYTESTREAM_MUC (bytestream));
1553 
1554   gabble_bytestream_muc_receive (bytestream, msg);
1555 
1556   g_free (room_name);
1557   return TRUE;
1558 }
1559 
1560 /**
1561  * bytestream_factory_iq_ibb_cb:
1562  *
1563  * Called by Wocky when we get an incoming <iq>.
1564  * This handler is concerned with IBB iq's.
1565  *
1566  */
1567 static gboolean
bytestream_factory_iq_ibb_cb(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1568 bytestream_factory_iq_ibb_cb (
1569     WockyPorter *porter,
1570     WockyStanza *msg,
1571     gpointer user_data)
1572 {
1573   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1574 
1575   if (handle_ibb_open_iq (self, msg))
1576     return TRUE;
1577 
1578   if (handle_ibb_close_iq (self, msg))
1579     return TRUE;
1580 
1581   if (handle_ibb_data (self, msg, TRUE))
1582     return TRUE;
1583 
1584   return FALSE;
1585 }
1586 
1587 /**
1588  * bytestream_factory_msg_data_cb
1589  *
1590  * Called by Wocky when we get an incoming <message>.
1591  * This handler handles IBB data and pseudo IBB Muc data.
1592  */
1593 static gboolean
bytestream_factory_msg_data_cb(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1594 bytestream_factory_msg_data_cb (
1595     WockyPorter *porter,
1596     WockyStanza *msg,
1597     gpointer user_data)
1598 {
1599   GabbleBytestreamFactory *self = user_data;
1600 
1601   if (handle_ibb_data (self, msg, FALSE))
1602     return TRUE;
1603 
1604   if (handle_muc_data (self, msg))
1605     return TRUE;
1606 
1607   return FALSE;
1608 }
1609 
1610 static gboolean
handle_socks5_query_iq(WockyPorter * porter,WockyStanza * msg,gpointer user_data)1611 handle_socks5_query_iq (
1612     WockyPorter *porter,
1613     WockyStanza *msg,
1614     gpointer user_data)
1615 {
1616   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1617   GabbleBytestreamFactoryPrivate *priv = self->priv;
1618   GabbleBytestreamSocks5 *bytestream;
1619   WockyNode *query_node, *child_node;
1620   ConstBytestreamIdentifier bsid = { NULL, NULL };
1621   const gchar *tmp;
1622   WockyNodeIter i;
1623 
1624   query_node = wocky_node_get_child_ns (
1625       wocky_stanza_get_top_node (msg), "query", NS_BYTESTREAMS);
1626   g_return_val_if_fail (query_node != NULL, FALSE);
1627 
1628   bsid.jid = wocky_node_get_attribute (
1629       wocky_stanza_get_top_node (msg), "from");
1630   if (bsid.jid == NULL)
1631     {
1632       DEBUG ("got a message without a from field");
1633       wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1634           "SOCKS5 <query> has no 'from' attribute");
1635       return TRUE;
1636     }
1637 
1638   bsid.stream = wocky_node_get_attribute (query_node, "sid");
1639   if (bsid.stream == NULL)
1640     {
1641       DEBUG ("SOCKS5 query stanza doesn't contain stream id");
1642       wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1643           "SOCKS5 <query> has no stream ID");
1644       return TRUE;
1645     }
1646 
1647   bytestream = g_hash_table_lookup (priv->socks5_bytestreams, &bsid);
1648   if (bytestream == NULL)
1649     {
1650       /* We don't accept streams not previously announced using SI */
1651       DEBUG ("unknown stream: <%s> from <%s>", bsid.stream, bsid.jid);
1652       wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_ITEM_NOT_FOUND,
1653           "SOCKS5 <query> has an unknown stream ID");
1654       return TRUE;
1655     }
1656 
1657   tmp = wocky_node_get_attribute (query_node, "mode");
1658   /* If this attribute is missing, the default value of "tcp" MUST be assumed */
1659   if (tmp != NULL && tp_strdiff (tmp, "tcp"))
1660     {
1661       DEBUG ("non-TCP SOCKS5 bytestreams are not supported");
1662       wocky_porter_send_iq_error (porter, msg, WOCKY_XMPP_ERROR_BAD_REQUEST,
1663           "SOCKS5 non-TCP bytestreams are not supported");
1664       return TRUE;
1665     }
1666 
1667   wocky_node_iter_init (&i, query_node, "streamhost", NULL);
1668   while (wocky_node_iter_next (&i, &child_node))
1669     {
1670       gabble_bytestream_socks5_add_streamhost (bytestream, child_node);
1671     }
1672 
1673   gabble_bytestream_socks5_connect_to_streamhost (bytestream, msg);
1674 
1675   return TRUE;
1676 }
1677 
1678 GabbleBytestreamFactory *
gabble_bytestream_factory_new(GabbleConnection * conn)1679 gabble_bytestream_factory_new (GabbleConnection *conn)
1680 {
1681   GabbleBytestreamFactory *factory;
1682 
1683   g_return_val_if_fail (GABBLE_IS_CONNECTION (conn), NULL);
1684 
1685   factory = GABBLE_BYTESTREAM_FACTORY (
1686       g_object_new (GABBLE_TYPE_BYTESTREAM_FACTORY,
1687         "connection", conn,
1688         NULL));
1689 
1690   return factory;
1691 }
1692 
1693 static void
bytestream_state_changed_cb(GabbleBytestreamIface * bytestream,GabbleBytestreamState state,gpointer user_data)1694 bytestream_state_changed_cb (GabbleBytestreamIface *bytestream,
1695                              GabbleBytestreamState state,
1696                              gpointer user_data)
1697 {
1698   GabbleBytestreamFactory *self = GABBLE_BYTESTREAM_FACTORY (user_data);
1699   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
1700       self);
1701 
1702   if (priv->dispose_has_run)
1703     return;
1704 
1705   if (state == GABBLE_BYTESTREAM_STATE_CLOSED)
1706     {
1707       remove_bytestream (self, bytestream);
1708     }
1709 }
1710 
1711 gchar *
gabble_bytestream_factory_generate_stream_id(void)1712 gabble_bytestream_factory_generate_stream_id (void)
1713 {
1714   gchar *stream_id;
1715 
1716   stream_id = g_strdup_printf ("%lu-%u", (unsigned long) time (NULL),
1717       g_random_int ());
1718 
1719   return stream_id;
1720 }
1721 
1722 GabbleBytestreamIface *
gabble_bytestream_factory_create_from_method(GabbleBytestreamFactory * self,const gchar * stream_method,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,const gchar * self_jid,GabbleBytestreamState state)1723 gabble_bytestream_factory_create_from_method (GabbleBytestreamFactory *self,
1724                                               const gchar *stream_method,
1725                                               TpHandle peer_handle,
1726                                               const gchar *stream_id,
1727                                               const gchar *stream_init_id,
1728                                               const gchar *peer_resource,
1729                                               const gchar *self_jid,
1730                                               GabbleBytestreamState state)
1731 {
1732   GabbleBytestreamIface *bytestream = NULL;
1733 
1734   if (!tp_strdiff (stream_method, NS_IBB))
1735     {
1736       bytestream = GABBLE_BYTESTREAM_IFACE (
1737           gabble_bytestream_factory_create_ibb (self, peer_handle,
1738             stream_id, stream_init_id, peer_resource, state));
1739     }
1740   else if (!tp_strdiff (stream_method, NS_BYTESTREAMS))
1741     {
1742       bytestream = GABBLE_BYTESTREAM_IFACE (
1743           gabble_bytestream_factory_create_socks5 (self, peer_handle,
1744             stream_id, stream_init_id, peer_resource, self_jid, state));
1745     }
1746 
1747   return bytestream;
1748 }
1749 
1750 static GabbleBytestreamIBB *
gabble_bytestream_factory_create_ibb(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,GabbleBytestreamState state)1751 gabble_bytestream_factory_create_ibb (GabbleBytestreamFactory *self,
1752                                       TpHandle peer_handle,
1753                                       const gchar *stream_id,
1754                                       const gchar *stream_init_id,
1755                                       const gchar *peer_resource,
1756                                       GabbleBytestreamState state)
1757 {
1758   GabbleBytestreamFactoryPrivate *priv;
1759   GabbleBytestreamIBB *ibb;
1760   BytestreamIdentifier *id;
1761 
1762   g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1763   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1764 
1765   ibb = g_object_new (GABBLE_TYPE_BYTESTREAM_IBB,
1766       "connection", priv->conn,
1767       "peer-handle", peer_handle,
1768       "stream-id", stream_id,
1769       "state", state,
1770       "stream-init-id", stream_init_id,
1771       "peer-resource", peer_resource,
1772       NULL);
1773 
1774   gabble_signal_connect_weak (ibb, "state-changed",
1775       G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1776 
1777   id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (ibb));
1778   DEBUG ("add IBB bytestream <%s> from <%s>", id->stream, id->jid);
1779   g_hash_table_insert (priv->ibb_bytestreams, id, ibb);
1780 
1781   return ibb;
1782 }
1783 
1784 GabbleBytestreamMuc *
gabble_bytestream_factory_create_muc(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,GabbleBytestreamState state)1785 gabble_bytestream_factory_create_muc (GabbleBytestreamFactory *self,
1786                                       TpHandle peer_handle,
1787                                       const gchar *stream_id,
1788                                       GabbleBytestreamState state)
1789 {
1790   GabbleBytestreamFactoryPrivate *priv;
1791   GabbleBytestreamMuc *bytestream;
1792   BytestreamIdentifier *id;
1793 
1794   g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1795   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1796 
1797   bytestream = g_object_new (GABBLE_TYPE_BYTESTREAM_MUC,
1798       "connection", priv->conn,
1799       "peer-handle", peer_handle,
1800       "stream-id", stream_id,
1801       "state", state,
1802       NULL);
1803 
1804   gabble_signal_connect_weak (bytestream, "state-changed",
1805       G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1806 
1807   id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (bytestream));
1808   DEBUG ("add muc bytestream <%s> from <%s>", id->stream, id->jid);
1809   g_hash_table_insert (priv->muc_bytestreams, id, bytestream);
1810 
1811   return bytestream;
1812 }
1813 
1814 static GabbleBytestreamSocks5 *
gabble_bytestream_factory_create_socks5(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,const gchar * self_jid,GabbleBytestreamState state)1815 gabble_bytestream_factory_create_socks5 (GabbleBytestreamFactory *self,
1816                                          TpHandle peer_handle,
1817                                          const gchar *stream_id,
1818                                          const gchar *stream_init_id,
1819                                          const gchar *peer_resource,
1820                                          const gchar *self_jid,
1821                                          GabbleBytestreamState state)
1822 {
1823   GabbleBytestreamFactoryPrivate *priv;
1824   GabbleBytestreamSocks5 *socks5;
1825   BytestreamIdentifier *id;
1826 
1827   g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1828   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1829 
1830   socks5 = g_object_new (GABBLE_TYPE_BYTESTREAM_SOCKS5,
1831       "connection", priv->conn,
1832       "peer-handle", peer_handle,
1833       "stream-id", stream_id,
1834       "state", state,
1835       "stream-init-id", stream_init_id,
1836       "peer-resource", peer_resource,
1837       "self-jid", self_jid,
1838       NULL);
1839 
1840   gabble_signal_connect_weak (socks5, "state-changed",
1841       G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1842 
1843   id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (socks5));
1844   DEBUG ("add SOCKS5 bytestream <%s> from <%s>", id->stream, id->jid);
1845   g_hash_table_insert (priv->socks5_bytestreams, id, socks5);
1846 
1847   return socks5;
1848 }
1849 
1850 static GabbleBytestreamMultiple *
gabble_bytestream_factory_create_multiple(GabbleBytestreamFactory * self,TpHandle peer_handle,const gchar * stream_id,const gchar * stream_init_id,const gchar * peer_resource,const gchar * self_jid,GabbleBytestreamState state)1851 gabble_bytestream_factory_create_multiple (GabbleBytestreamFactory *self,
1852                                            TpHandle peer_handle,
1853                                            const gchar *stream_id,
1854                                            const gchar *stream_init_id,
1855                                            const gchar *peer_resource,
1856                                            const gchar *self_jid,
1857                                            GabbleBytestreamState state)
1858 {
1859   GabbleBytestreamFactoryPrivate *priv;
1860   GabbleBytestreamMultiple *multiple;
1861   BytestreamIdentifier *id;
1862 
1863   g_return_val_if_fail (GABBLE_IS_BYTESTREAM_FACTORY (self), NULL);
1864   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
1865 
1866   multiple = g_object_new (GABBLE_TYPE_BYTESTREAM_MULTIPLE,
1867       "connection", priv->conn,
1868       "peer-handle", peer_handle,
1869       "stream-id", stream_id,
1870       "state", state,
1871       "stream-init-id", stream_init_id,
1872       "peer-resource", peer_resource,
1873       "factory", self,
1874       "self-jid", self_jid,
1875       NULL);
1876 
1877   gabble_signal_connect_weak (multiple, "state-changed",
1878       G_CALLBACK (bytestream_state_changed_cb), G_OBJECT (self));
1879 
1880   id = bytestream_id_new (GABBLE_BYTESTREAM_IFACE (multiple));
1881   DEBUG ("add multi bytestream <%s> from <%s>", id->stream, id->jid);
1882   g_hash_table_insert (priv->multiple_bytestreams, id, multiple);
1883 
1884   return multiple;
1885 }
1886 
1887 static GabbleBytestreamIface *
streaminit_get_multiple_bytestream(GabbleBytestreamFactory * self,WockyStanza * reply_msg,WockyNode * si,const gchar * stream_id,TpHandle peer_handle,const gchar * peer_resource,const gchar * self_jid)1888 streaminit_get_multiple_bytestream (GabbleBytestreamFactory *self,
1889                                     WockyStanza *reply_msg,
1890                                     WockyNode *si,
1891                                     const gchar *stream_id,
1892                                     TpHandle peer_handle,
1893                                     const gchar *peer_resource,
1894                                     const gchar *self_jid)
1895 {
1896   /* If the other client supports si-multiple we have directly a list of
1897    * supported methods inside <value/> tags */
1898   WockyNode *si_multi;
1899   const gchar *stream_method;
1900   GabbleBytestreamMultiple *bytestream = NULL;
1901   WockyNode *value;
1902   WockyNodeIter i;
1903 
1904   si_multi = wocky_node_get_child_ns (si, "si-multiple",
1905       NS_SI_MULTIPLE);
1906   if (si_multi == NULL)
1907     return NULL;
1908 
1909   bytestream = gabble_bytestream_factory_create_multiple (self, peer_handle,
1910       stream_id, NULL, peer_resource, self_jid,
1911       GABBLE_BYTESTREAM_STATE_INITIATING);
1912 
1913   wocky_node_iter_init (&i, si_multi, "value", NULL);
1914   while (wocky_node_iter_next (&i, &value))
1915     {
1916       stream_method = value->content;
1917       if (!stream_method_supported (stream_method))
1918         {
1919           DEBUG ("got a si-multiple reply with an unsupported "
1920               "stream method: %s", stream_method);
1921           continue;
1922         }
1923 
1924       gabble_bytestream_multiple_add_stream_method (bytestream, stream_method);
1925     }
1926 
1927   return GABBLE_BYTESTREAM_IFACE (bytestream);
1928 }
1929 
1930 static GabbleBytestreamIface *
streaminit_get_bytestream(GabbleBytestreamFactory * self,WockyStanza * reply_msg,WockyNode * si,const gchar * stream_id,TpHandle peer_handle,const gchar * peer_resource,const gchar * self_jid)1931 streaminit_get_bytestream (GabbleBytestreamFactory *self,
1932                            WockyStanza *reply_msg,
1933                            WockyNode *si,
1934                            const gchar *stream_id,
1935                            TpHandle peer_handle,
1936                            const gchar *peer_resource,
1937                            const gchar *self_jid)
1938 {
1939   WockyNode *feature, *x, *value, *field;
1940   GabbleBytestreamIface *bytestream = NULL;
1941   const gchar *stream_method;
1942   WockyNodeIter i;
1943 
1944   feature = wocky_node_get_child_ns (si, "feature",
1945       NS_FEATURENEG);
1946   if (feature == NULL)
1947     {
1948       STANZA_DEBUG (reply_msg, "got a SI reply without a feature field");
1949       return NULL;
1950     }
1951 
1952   x = wocky_node_get_child_ns (feature, "x", NS_X_DATA);
1953   if (x == NULL)
1954     {
1955       STANZA_DEBUG (reply_msg, "got a SI reply without a x field");
1956       return NULL;
1957     }
1958 
1959   wocky_node_iter_init (&i, x, NULL, NULL);
1960   while (wocky_node_iter_next (&i, &field))
1961     {
1962       if (tp_strdiff (wocky_node_get_attribute (field, "var"),
1963             "stream-method"))
1964         /* some future field, ignore it */
1965         continue;
1966 
1967       value = wocky_node_get_child (field, "value");
1968       if (value == NULL)
1969         {
1970           STANZA_DEBUG (reply_msg, "SI reply's stream-method field "
1971               "doesn't contain stream-method value");
1972           return NULL;
1973         }
1974 
1975       stream_method = value->content;
1976       bytestream = gabble_bytestream_factory_create_from_method (self,
1977           stream_method, peer_handle, stream_id, NULL, peer_resource, self_jid,
1978           GABBLE_BYTESTREAM_STATE_INITIATING);
1979 
1980       /* no need to parse the rest of the fields, we've found the one we
1981        * wanted */
1982       break;
1983     }
1984 
1985   return bytestream;
1986 }
1987 
1988 struct _streaminit_reply_cb_data
1989 {
1990   GabbleBytestreamFactory *self;
1991   gchar *stream_id;
1992   GabbleBytestreamFactoryNegotiateReplyFunc func;
1993   TpWeakRef *weak_object;
1994 };
1995 
1996 /* Called when we receive the reply of a SI request */
1997 static void
streaminit_reply_cb(GObject * source,GAsyncResult * result,gpointer user_data)1998 streaminit_reply_cb (
1999     GObject *source,
2000     GAsyncResult *result,
2001     gpointer user_data)
2002 {
2003   GabbleConnection *conn = GABBLE_CONNECTION (source);
2004   struct _streaminit_reply_cb_data *data = user_data;
2005   GabbleBytestreamFactory *self = data->self;
2006   GabbleBytestreamFactoryPrivate *priv = self->priv;
2007   GabbleBytestreamIface *bytestream = NULL;
2008   gchar *peer_resource = NULL;
2009   WockyNode *si;
2010   const gchar *from;
2011   TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
2012       (TpBaseConnection *) conn, TP_HANDLE_TYPE_CONTACT);
2013   TpHandleRepoIface *room_repo = tp_base_connection_get_handles (
2014       (TpBaseConnection *) conn, TP_HANDLE_TYPE_ROOM);
2015   TpHandle peer_handle = 0;
2016   TpHandle room_handle;
2017   gboolean success = FALSE;
2018   gchar *self_jid = NULL;
2019   GObject *object = tp_weak_ref_dup_object (data->weak_object);
2020   WockyStanza *reply_msg = NULL;
2021 
2022   if (object == NULL)
2023     {
2024       DEBUG ("Object which requested the bytestream was disposed. Ignoring");
2025       goto END;
2026     }
2027 
2028   if (!conn_util_send_iq_finish (conn, result, &reply_msg, NULL))
2029     {
2030       DEBUG ("stream %s declined", data->stream_id);
2031       goto END;
2032     }
2033 
2034   /* stream accepted */
2035 
2036   from = wocky_node_get_attribute (
2037       wocky_stanza_get_top_node (reply_msg), "from");
2038   if (from == NULL)
2039     {
2040       STANZA_DEBUG (reply_msg, "got a message without a from field");
2041       goto END;
2042     }
2043 
2044   peer_handle = tp_handle_ensure (contact_repo, from, NULL, NULL);
2045   room_handle = gabble_get_room_handle_from_jid (room_repo, from);
2046 
2047   if (room_handle == 0)
2048     {
2049       /* jid is not a muc jid so we need contact's resource */
2050 
2051       if (!wocky_decode_jid (from, NULL, NULL, &peer_resource))
2052         {
2053           DEBUG ("Got an SI request with a bad JID");
2054           goto END;
2055         }
2056 
2057       if (peer_resource == NULL)
2058         {
2059           DEBUG ("Got an SI request from a JID without a resource; ignoring");
2060           goto END;
2061         }
2062 
2063       /* we are not in a muc so our own jid is the one in the 'to' attribute */
2064       self_jid = g_strdup (wocky_node_get_attribute (
2065           wocky_stanza_get_top_node (reply_msg), "to"));
2066     }
2067   else
2068     {
2069       /* we are in a muc so need to get our muc jid */
2070       GabbleMucChannel *muc;
2071 
2072       muc = gabble_muc_factory_find_text_channel (priv->conn->muc_factory,
2073           room_handle);
2074 
2075       if (muc == NULL)
2076         {
2077           DEBUG ("Got an IQ from a muc in which we are not. Ignoring");
2078           goto END;
2079         }
2080 
2081       g_object_get (muc, "self-jid", &self_jid, NULL);
2082     }
2083 
2084   si = wocky_node_get_child_ns (
2085       wocky_stanza_get_top_node (reply_msg), "si", NS_SI);
2086   if (si == NULL)
2087     {
2088       STANZA_DEBUG (reply_msg, "got a SI reply without a si field");
2089       goto END;
2090     }
2091 
2092   /* Try to build a multiple bytestream with fallback methods */
2093   bytestream = streaminit_get_multiple_bytestream (self, reply_msg, si,
2094       data->stream_id, peer_handle, peer_resource, self_jid);
2095   /* FIXME: check if there is at least one stream method */
2096 
2097   if (bytestream == NULL)
2098     /* The other client doesn't suppport si-multiple, use the normal XEP-095
2099      * method */
2100     bytestream = streaminit_get_bytestream (self, reply_msg, si,
2101         data->stream_id, peer_handle, peer_resource, self_jid);
2102 
2103   if (bytestream == NULL)
2104     goto END;
2105 
2106   DEBUG ("stream %s accepted", data->stream_id);
2107 
2108   /* Let's start the initiation of the stream */
2109   if (gabble_bytestream_iface_initiate (bytestream))
2110     {
2111       /* FIXME: we should really only "succeed" when our <open> succeeds.
2112        * It only really matters from the point of view of the data->func */
2113       success = TRUE;
2114     }
2115 
2116 END:
2117   if (!success && bytestream != NULL)
2118     {
2119       remove_bytestream (self, bytestream);
2120       bytestream = NULL;
2121     }
2122 
2123   /* user callback */
2124   if (object != NULL)
2125     {
2126       data->func (bytestream, reply_msg,
2127           object, tp_weak_ref_get_user_data (data->weak_object));
2128       g_clear_object (&object);
2129     }
2130 
2131   if (peer_resource != NULL)
2132     g_free (peer_resource);
2133 
2134   g_clear_object (&reply_msg);
2135   g_clear_object (&data->self);
2136   g_free (self_jid);
2137   g_free (data->stream_id);
2138   tp_weak_ref_destroy (data->weak_object);
2139   g_slice_free (struct _streaminit_reply_cb_data, data);
2140 }
2141 
2142 /*
2143  * gabble_bytestream_factory_negotiate_stream:
2144  *
2145  * @msg: the SI negotiation IQ (created using
2146  * gabble_bytestream_factory_make_stream_init_iq)
2147  * @stream_id: the stream identifier
2148  * @func: the callback to call when we receive the answser of the request
2149  * @user_data: user data to pass to the callback
2150  * @object: the handler will follow the lifetime of this object,
2151  * which means that if the object is destroyed the callback will not be invoked.
2152  *
2153  * Send a Stream Initiation (XEP-0095) request.
2154  */
2155 void
gabble_bytestream_factory_negotiate_stream(GabbleBytestreamFactory * self,WockyStanza * msg,const gchar * stream_id,GabbleBytestreamFactoryNegotiateReplyFunc func,gpointer user_data,GObject * object)2156 gabble_bytestream_factory_negotiate_stream (GabbleBytestreamFactory *self,
2157                                             WockyStanza *msg,
2158                                             const gchar *stream_id,
2159                                             GabbleBytestreamFactoryNegotiateReplyFunc func,
2160                                             gpointer user_data,
2161                                             GObject *object)
2162 {
2163   GabbleBytestreamFactoryPrivate *priv;
2164   struct _streaminit_reply_cb_data *data;
2165 
2166   g_assert (GABBLE_IS_BYTESTREAM_FACTORY (self));
2167   g_assert (stream_id != NULL);
2168   g_assert (func != NULL);
2169   g_assert (object != NULL);
2170 
2171   priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (self);
2172 
2173   data = g_slice_new (struct _streaminit_reply_cb_data);
2174   data->self = g_object_ref (self);
2175   data->stream_id = g_strdup (stream_id);
2176   data->func = func;
2177   data->weak_object = tp_weak_ref_new (object, user_data, NULL);
2178 
2179   conn_util_send_iq_async (priv->conn, msg, NULL,
2180       streaminit_reply_cb, data);
2181 }
2182 
2183 /*
2184  * gabble_bytestream_factory_make_accept_iq
2185  *
2186  * @full_jid: the full jid of the stream initiator
2187  * @stream_init_id: the id of the SI request
2188  * @stream_method: the stream method chosen (one of them proposed
2189  * in the SI request)
2190  *
2191  * Create an IQ stanza accepting a stream in response to
2192  * a SI request (XEP-0095).
2193  *
2194  */
2195 WockyStanza *
gabble_bytestream_factory_make_accept_iq(const gchar * full_jid,const gchar * stream_init_id,const gchar * stream_method)2196 gabble_bytestream_factory_make_accept_iq (const gchar *full_jid,
2197                                           const gchar *stream_init_id,
2198                                           const gchar *stream_method)
2199 {
2200   return wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_RESULT,
2201       NULL, full_jid,
2202       '@', "id", stream_init_id,
2203       '(', "si",
2204         ':', NS_SI,
2205         '(', "feature",
2206           ':', NS_FEATURENEG,
2207           '(', "x",
2208             ':', NS_X_DATA,
2209             '@', "type", "submit",
2210             '(', "field",
2211               '@', "var", "stream-method",
2212               '(', "value", '$', stream_method, ')',
2213             ')',
2214           ')',
2215         ')',
2216       ')', NULL);
2217 }
2218 
2219 /*
2220  * gabble_bytestream_factory_make_multi_accept_iq
2221  *
2222  * @full_jid: the full jid of the stream initiator
2223  * @stream_init_id: the id of the SI request
2224  * @stream_methods: a list of the accepted string methods
2225  *
2226  * Create an IQ stanza accepting a stream in response to
2227  * a si-multiple SI request.
2228  *
2229  */
2230 WockyStanza *
gabble_bytestream_factory_make_multi_accept_iq(const gchar * full_jid,const gchar * stream_init_id,GList * stream_methods)2231 gabble_bytestream_factory_make_multi_accept_iq (const gchar *full_jid,
2232                                                 const gchar *stream_init_id,
2233                                                 GList *stream_methods)
2234 {
2235   WockyStanza *msg;
2236   WockyNode *multi_node;
2237   GList *l;
2238 
2239   msg = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ, WOCKY_STANZA_SUB_TYPE_RESULT,
2240       NULL, full_jid,
2241       '@', "id", stream_init_id,
2242       '(', "si",
2243         ':', NS_SI,
2244         '(', "si-multiple",
2245           ':', NS_SI_MULTIPLE,
2246           '*', &multi_node,
2247         ')',
2248       ')', NULL);
2249 
2250   for (l = stream_methods; l != NULL; l = l->next)
2251     {
2252       wocky_node_add_child_with_content (multi_node, "value", l->data);
2253     }
2254 
2255   return msg;
2256 }
2257 
2258 GSList *
gabble_bytestream_factory_get_socks5_proxies(GabbleBytestreamFactory * self)2259 gabble_bytestream_factory_get_socks5_proxies (GabbleBytestreamFactory *self)
2260 {
2261   GabbleBytestreamFactoryPrivate *priv = GABBLE_BYTESTREAM_FACTORY_GET_PRIVATE (
2262       self);
2263 
2264   return g_slist_concat (g_slist_copy (priv->socks5_proxies),
2265       g_slist_copy (priv->socks5_fallback_proxies));
2266 }
2267