/src/pidgin/libpurple/protocols/jabber/jingle/jingle.c
Line | Count | Source |
1 | | /* |
2 | | * @file jingle.c |
3 | | * |
4 | | * purple - Jabber Protocol Plugin |
5 | | * |
6 | | * Purple is the legal property of its developers, whose names are too numerous |
7 | | * to list here. Please refer to the COPYRIGHT file distributed with this |
8 | | * source distribution. |
9 | | * |
10 | | * This program is free software; you can redistribute it and/or modify |
11 | | * it under the terms of the GNU General Public License as published by |
12 | | * the Free Software Foundation; either version 2 of the License, or |
13 | | * (at your option) any later version. |
14 | | * |
15 | | * This program is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU General Public License |
21 | | * along with this program; if not, write to the Free Software |
22 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA |
23 | | * |
24 | | */ |
25 | | |
26 | | #include "internal.h" |
27 | | #include "network.h" |
28 | | |
29 | | #include "content.h" |
30 | | #include "debug.h" |
31 | | #include "jingle.h" |
32 | | #include "session.h" |
33 | | #include "iceudp.h" |
34 | | #include "rawudp.h" |
35 | | #include "rtp.h" |
36 | | |
37 | | #include <string.h> |
38 | | #ifdef USE_VV |
39 | | #include <gst/gst.h> |
40 | | #endif |
41 | | |
42 | | GType |
43 | | jingle_get_type(const gchar *type) |
44 | 0 | { |
45 | 0 | if (type == NULL) |
46 | 0 | return G_TYPE_NONE; |
47 | | |
48 | 0 | if (purple_strequal(type, JINGLE_TRANSPORT_RAWUDP)) |
49 | 0 | return JINGLE_TYPE_RAWUDP; |
50 | 0 | else if (purple_strequal(type, JINGLE_TRANSPORT_ICEUDP)) |
51 | 0 | return JINGLE_TYPE_ICEUDP; |
52 | | #if 0 |
53 | | else if (purple_strequal(type, JINGLE_TRANSPORT_SOCKS)) |
54 | | return JINGLE_TYPE_SOCKS; |
55 | | else if (purple_strequal(type, JINGLE_TRANSPORT_IBB)) |
56 | | return JINGLE_TYPE_IBB; |
57 | | #endif |
58 | | #ifdef USE_VV |
59 | | else if (purple_strequal(type, JINGLE_APP_RTP)) |
60 | | return JINGLE_TYPE_RTP; |
61 | | #endif |
62 | | #if 0 |
63 | | else if (purple_strequal(type, JINGLE_APP_FT)) |
64 | | return JINGLE_TYPE_FT; |
65 | | else if (purple_strequal(type, JINGLE_APP_XML)) |
66 | | return JINGLE_TYPE_XML; |
67 | | #endif |
68 | 0 | else |
69 | 0 | return G_TYPE_NONE; |
70 | 0 | } |
71 | | |
72 | | static void |
73 | | jingle_handle_unknown_type(JingleSession *session, xmlnode *jingle) |
74 | 0 | { |
75 | | /* Send error */ |
76 | 0 | } |
77 | | |
78 | | static void |
79 | | jingle_handle_content_accept(JingleSession *session, xmlnode *jingle) |
80 | 0 | { |
81 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
82 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
83 | |
|
84 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
85 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
86 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
87 | 0 | jingle_session_accept_content(session, name, creator); |
88 | | /* signal here */ |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | static void |
93 | | jingle_handle_content_add(JingleSession *session, xmlnode *jingle) |
94 | 0 | { |
95 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
96 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
97 | |
|
98 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
99 | 0 | JingleContent *pending_content = |
100 | 0 | jingle_content_parse(content); |
101 | 0 | if (pending_content == NULL) { |
102 | 0 | purple_debug_error("jingle", |
103 | 0 | "Error parsing \"content-add\" content.\n"); |
104 | 0 | jabber_iq_send(jingle_session_terminate_packet(session, |
105 | 0 | "unsupported-applications")); |
106 | 0 | } else { |
107 | 0 | jingle_session_add_pending_content(session, |
108 | 0 | pending_content); |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | /* XXX: signal here */ |
113 | 0 | } |
114 | | |
115 | | static void |
116 | | jingle_handle_content_modify(JingleSession *session, xmlnode *jingle) |
117 | 0 | { |
118 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
119 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
120 | |
|
121 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
122 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
123 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
124 | 0 | JingleContent *local_content = jingle_session_find_content(session, name, creator); |
125 | |
|
126 | 0 | if (local_content != NULL) { |
127 | 0 | const gchar *senders = xmlnode_get_attrib(content, "senders"); |
128 | 0 | gchar *local_senders = jingle_content_get_senders(local_content); |
129 | 0 | if (!purple_strequal(senders, local_senders)) |
130 | 0 | jingle_content_modify(local_content, senders); |
131 | 0 | g_free(local_senders); |
132 | 0 | } else { |
133 | 0 | purple_debug_error("jingle", "content_modify: unknown content\n"); |
134 | 0 | jabber_iq_send(jingle_session_terminate_packet(session, |
135 | 0 | "unknown-applications")); |
136 | 0 | } |
137 | 0 | } |
138 | 0 | } |
139 | | |
140 | | static void |
141 | | jingle_handle_content_reject(JingleSession *session, xmlnode *jingle) |
142 | 0 | { |
143 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
144 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
145 | |
|
146 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
147 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
148 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
149 | 0 | jingle_session_remove_pending_content(session, name, creator); |
150 | | /* signal here */ |
151 | 0 | } |
152 | 0 | } |
153 | | |
154 | | static void |
155 | | jingle_handle_content_remove(JingleSession *session, xmlnode *jingle) |
156 | 0 | { |
157 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
158 | |
|
159 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
160 | |
|
161 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
162 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
163 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
164 | 0 | jingle_session_remove_content(session, name, creator); |
165 | 0 | } |
166 | 0 | } |
167 | | |
168 | | static void |
169 | | jingle_handle_description_info(JingleSession *session, xmlnode *jingle) |
170 | 0 | { |
171 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
172 | |
|
173 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
174 | |
|
175 | 0 | jingle_session_accept_session(session); |
176 | |
|
177 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
178 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
179 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
180 | 0 | JingleContent *parsed_content = |
181 | 0 | jingle_session_find_content(session, name, creator); |
182 | 0 | if (parsed_content == NULL) { |
183 | 0 | purple_debug_error("jingle", "Error parsing content\n"); |
184 | 0 | jabber_iq_send(jingle_session_terminate_packet(session, |
185 | 0 | "unsupported-applications")); |
186 | 0 | } else { |
187 | 0 | jingle_content_handle_action(parsed_content, content, |
188 | 0 | JINGLE_DESCRIPTION_INFO); |
189 | 0 | } |
190 | 0 | } |
191 | 0 | } |
192 | | |
193 | | static void |
194 | | jingle_handle_security_info(JingleSession *session, xmlnode *jingle) |
195 | 0 | { |
196 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
197 | 0 | } |
198 | | |
199 | | static void |
200 | | jingle_handle_session_accept(JingleSession *session, xmlnode *jingle) |
201 | 0 | { |
202 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
203 | |
|
204 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
205 | |
|
206 | 0 | jingle_session_accept_session(session); |
207 | |
|
208 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
209 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
210 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
211 | 0 | JingleContent *parsed_content = |
212 | 0 | jingle_session_find_content(session, name, creator); |
213 | 0 | if (parsed_content == NULL) { |
214 | 0 | purple_debug_error("jingle", "Error parsing content\n"); |
215 | 0 | jabber_iq_send(jingle_session_terminate_packet(session, |
216 | 0 | "unsupported-applications")); |
217 | 0 | } else { |
218 | 0 | jingle_content_handle_action(parsed_content, content, |
219 | 0 | JINGLE_SESSION_ACCEPT); |
220 | 0 | } |
221 | 0 | } |
222 | 0 | } |
223 | | |
224 | | static void |
225 | | jingle_handle_session_info(JingleSession *session, xmlnode *jingle) |
226 | 0 | { |
227 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
228 | | /* XXX: call signal */ |
229 | 0 | } |
230 | | |
231 | | static void |
232 | | jingle_handle_session_initiate(JingleSession *session, xmlnode *jingle) |
233 | 0 | { |
234 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
235 | |
|
236 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
237 | 0 | JingleContent *parsed_content = jingle_content_parse(content); |
238 | 0 | if (parsed_content == NULL) { |
239 | 0 | purple_debug_error("jingle", "Error parsing content\n"); |
240 | 0 | jabber_iq_send(jingle_session_terminate_packet(session, |
241 | 0 | "unsupported-applications")); |
242 | 0 | } else { |
243 | 0 | jingle_session_add_content(session, parsed_content); |
244 | 0 | jingle_content_handle_action(parsed_content, content, |
245 | 0 | JINGLE_SESSION_INITIATE); |
246 | 0 | } |
247 | 0 | } |
248 | |
|
249 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
250 | 0 | } |
251 | | |
252 | | static void |
253 | | jingle_handle_session_terminate(JingleSession *session, xmlnode *jingle) |
254 | 0 | { |
255 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
256 | |
|
257 | 0 | jingle_session_handle_action(session, jingle, |
258 | 0 | JINGLE_SESSION_TERMINATE); |
259 | | /* display reason? */ |
260 | 0 | g_object_unref(session); |
261 | 0 | } |
262 | | |
263 | | static void |
264 | | jingle_handle_transport_accept(JingleSession *session, xmlnode *jingle) |
265 | 0 | { |
266 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
267 | |
|
268 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
269 | |
|
270 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
271 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
272 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
273 | 0 | JingleContent *content = jingle_session_find_content(session, name, creator); |
274 | 0 | jingle_content_accept_transport(content); |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | | static void |
279 | | jingle_handle_transport_info(JingleSession *session, xmlnode *jingle) |
280 | 0 | { |
281 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
282 | |
|
283 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
284 | |
|
285 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
286 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
287 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
288 | 0 | JingleContent *parsed_content = |
289 | 0 | jingle_session_find_content(session, name, creator); |
290 | 0 | if (parsed_content == NULL) { |
291 | 0 | purple_debug_error("jingle", "Error parsing content\n"); |
292 | 0 | jabber_iq_send(jingle_session_terminate_packet(session, |
293 | 0 | "unsupported-applications")); |
294 | 0 | } else { |
295 | 0 | jingle_content_handle_action(parsed_content, content, |
296 | 0 | JINGLE_TRANSPORT_INFO); |
297 | 0 | } |
298 | 0 | } |
299 | 0 | } |
300 | | |
301 | | static void |
302 | | jingle_handle_transport_reject(JingleSession *session, xmlnode *jingle) |
303 | 0 | { |
304 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
305 | |
|
306 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
307 | |
|
308 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
309 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
310 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
311 | 0 | JingleContent *content = jingle_session_find_content(session, name, creator); |
312 | 0 | jingle_content_remove_pending_transport(content); |
313 | 0 | } |
314 | 0 | } |
315 | | |
316 | | static void |
317 | | jingle_handle_transport_replace(JingleSession *session, xmlnode *jingle) |
318 | 0 | { |
319 | 0 | xmlnode *content = xmlnode_get_child(jingle, "content"); |
320 | |
|
321 | 0 | jabber_iq_send(jingle_session_create_ack(session, jingle)); |
322 | |
|
323 | 0 | for (; content; content = xmlnode_get_next_twin(content)) { |
324 | 0 | const gchar *name = xmlnode_get_attrib(content, "name"); |
325 | 0 | const gchar *creator = xmlnode_get_attrib(content, "creator"); |
326 | 0 | xmlnode *xmltransport = xmlnode_get_child(content, "transport"); |
327 | 0 | JingleTransport *transport = jingle_transport_parse(xmltransport); |
328 | 0 | JingleContent *content = jingle_session_find_content(session, name, creator); |
329 | |
|
330 | 0 | jingle_content_set_pending_transport(content, transport); |
331 | 0 | } |
332 | 0 | } |
333 | | |
334 | | typedef struct { |
335 | | const char *name; |
336 | | void (*handler)(JingleSession*, xmlnode*); |
337 | | } JingleAction; |
338 | | |
339 | | static const JingleAction jingle_actions[] = { |
340 | | {"unknown-type", jingle_handle_unknown_type}, |
341 | | {"content-accept", jingle_handle_content_accept}, |
342 | | {"content-add", jingle_handle_content_add}, |
343 | | {"content-modify", jingle_handle_content_modify}, |
344 | | {"content-reject", jingle_handle_content_reject}, |
345 | | {"content-remove", jingle_handle_content_remove}, |
346 | | {"description-info", jingle_handle_description_info}, |
347 | | {"security-info", jingle_handle_security_info}, |
348 | | {"session-accept", jingle_handle_session_accept}, |
349 | | {"session-info", jingle_handle_session_info}, |
350 | | {"session-initiate", jingle_handle_session_initiate}, |
351 | | {"session-terminate", jingle_handle_session_terminate}, |
352 | | {"transport-accept", jingle_handle_transport_accept}, |
353 | | {"transport-info", jingle_handle_transport_info}, |
354 | | {"transport-reject", jingle_handle_transport_reject}, |
355 | | {"transport-replace", jingle_handle_transport_replace}, |
356 | | }; |
357 | | |
358 | | const gchar * |
359 | | jingle_get_action_name(JingleActionType action) |
360 | 0 | { |
361 | 0 | return jingle_actions[action].name; |
362 | 0 | } |
363 | | |
364 | | JingleActionType |
365 | | jingle_get_action_type(const gchar *action) |
366 | 0 | { |
367 | 0 | static const int num_actions = |
368 | 0 | sizeof(jingle_actions)/sizeof(JingleAction); |
369 | | /* Start at 1 to skip the unknown-action type */ |
370 | 0 | int i = 1; |
371 | 0 | for (; i < num_actions; ++i) { |
372 | 0 | if (purple_strequal(action, jingle_actions[i].name)) |
373 | 0 | return i; |
374 | 0 | } |
375 | 0 | return JINGLE_UNKNOWN_TYPE; |
376 | 0 | } |
377 | | |
378 | | void |
379 | | jingle_parse(JabberStream *js, const char *from, JabberIqType type, |
380 | | const char *id, xmlnode *jingle) |
381 | 0 | { |
382 | 0 | const gchar *action; |
383 | 0 | const gchar *sid; |
384 | 0 | JingleActionType action_type; |
385 | 0 | JingleSession *session; |
386 | |
|
387 | 0 | if (type != JABBER_IQ_SET) { |
388 | | /* TODO: send iq error here */ |
389 | 0 | return; |
390 | 0 | } |
391 | | |
392 | 0 | if (!(action = xmlnode_get_attrib(jingle, "action"))) { |
393 | | /* TODO: send iq error here */ |
394 | 0 | return; |
395 | 0 | } |
396 | | |
397 | 0 | action_type = jingle_get_action_type(action); |
398 | |
|
399 | 0 | purple_debug_info("jabber", "got Jingle package action = %s\n", |
400 | 0 | action); |
401 | |
|
402 | 0 | if (!(sid = xmlnode_get_attrib(jingle, "sid"))) { |
403 | | /* send iq error here */ |
404 | 0 | return; |
405 | 0 | } |
406 | | |
407 | 0 | if (!(session = jingle_session_find_by_sid(js, sid)) |
408 | 0 | && !purple_strequal(action, "session-initiate")) { |
409 | 0 | purple_debug_error("jingle", "jabber_jingle_session_parse couldn't find session\n"); |
410 | | /* send iq error here */ |
411 | 0 | return; |
412 | 0 | } |
413 | | |
414 | 0 | if (action_type == JINGLE_SESSION_INITIATE) { |
415 | 0 | if (session) { |
416 | | /* This should only happen if you start a session with yourself */ |
417 | 0 | purple_debug_error("jingle", "Jingle session with " |
418 | 0 | "id={%s} already exists\n", sid); |
419 | | /* send iq error */ |
420 | 0 | return; |
421 | 0 | } else { |
422 | 0 | char *own_jid = g_strdup_printf("%s@%s/%s", js->user->node, |
423 | 0 | js->user->domain, js->user->resource); |
424 | 0 | session = jingle_session_create(js, sid, own_jid, from, FALSE); |
425 | 0 | g_free(own_jid); |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | 0 | jingle_actions[action_type].handler(session, jingle); |
430 | 0 | } |
431 | | |
432 | | static void |
433 | | jingle_terminate_sessions_gh(gpointer key, gpointer value, gpointer user_data) |
434 | 0 | { |
435 | 0 | g_object_unref(value); |
436 | 0 | } |
437 | | |
438 | | void |
439 | | jingle_terminate_sessions(JabberStream *js) |
440 | 0 | { |
441 | 0 | if (js->sessions) |
442 | 0 | g_hash_table_foreach(js->sessions, |
443 | | jingle_terminate_sessions_gh, NULL); |
444 | 0 | } |
445 | | |
446 | | #ifdef USE_VV |
447 | | static GValueArray * |
448 | | jingle_create_relay_info(const gchar *ip, guint port, const gchar *username, |
449 | | const gchar *password, const gchar *relay_type, GValueArray *relay_info) |
450 | | { |
451 | | GValue value; |
452 | | GstStructure *turn_setup = gst_structure_new("relay-info", |
453 | | "ip", G_TYPE_STRING, ip, |
454 | | "port", G_TYPE_UINT, port, |
455 | | "username", G_TYPE_STRING, username, |
456 | | "password", G_TYPE_STRING, password, |
457 | | "relay-type", G_TYPE_STRING, relay_type, |
458 | | NULL); |
459 | | purple_debug_info("jabber", "created gst_structure %p\n", |
460 | | turn_setup); |
461 | | if (turn_setup) { |
462 | | memset(&value, 0, sizeof(GValue)); |
463 | | g_value_init(&value, GST_TYPE_STRUCTURE); |
464 | | gst_value_set_structure(&value, turn_setup); |
465 | | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
466 | | relay_info = g_value_array_append(relay_info, &value); |
467 | | G_GNUC_END_IGNORE_DEPRECATIONS |
468 | | gst_structure_free(turn_setup); |
469 | | } |
470 | | return relay_info; |
471 | | } |
472 | | |
473 | | GParameter * |
474 | | jingle_get_params(JabberStream *js, const gchar *relay_ip, guint relay_udp, |
475 | | guint relay_tcp, guint relay_ssltcp, const gchar *relay_username, |
476 | | const gchar *relay_password, guint *num) |
477 | | { |
478 | | /* don't set a STUN server if one is set globally in prefs, in that case |
479 | | this will be handled in media.c */ |
480 | | gboolean has_account_stun = js->stun_ip && !purple_network_get_stun_ip(); |
481 | | guint num_params = has_account_stun ? |
482 | | (relay_ip ? 3 : 2) : (relay_ip ? 1 : 0); |
483 | | GParameter *params = NULL; |
484 | | int next_index = 0; |
485 | | |
486 | | if (num_params > 0) { |
487 | | params = g_new0(GParameter, num_params); |
488 | | |
489 | | if (has_account_stun) { |
490 | | purple_debug_info("jabber", |
491 | | "setting param stun-ip for stream using Google auto-config: %s\n", |
492 | | js->stun_ip); |
493 | | params[next_index].name = "stun-ip"; |
494 | | g_value_init(¶ms[next_index].value, G_TYPE_STRING); |
495 | | g_value_set_string(¶ms[next_index].value, js->stun_ip); |
496 | | purple_debug_info("jabber", |
497 | | "setting param stun-port for stream using Google auto-config: %d\n", |
498 | | js->stun_port); |
499 | | next_index++; |
500 | | params[next_index].name = "stun-port"; |
501 | | g_value_init(¶ms[next_index].value, G_TYPE_UINT); |
502 | | g_value_set_uint(¶ms[next_index].value, js->stun_port); |
503 | | next_index++; |
504 | | } |
505 | | |
506 | | if (relay_ip) { |
507 | | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
508 | | GValueArray *relay_info = g_value_array_new(0); |
509 | | G_GNUC_END_IGNORE_DEPRECATIONS |
510 | | |
511 | | if (relay_udp) { |
512 | | relay_info = |
513 | | jingle_create_relay_info(relay_ip, relay_udp, relay_username, |
514 | | relay_password, "udp", relay_info); |
515 | | } |
516 | | if (relay_tcp) { |
517 | | relay_info = |
518 | | jingle_create_relay_info(relay_ip, relay_tcp, relay_username, |
519 | | relay_password, "tcp", relay_info); |
520 | | } |
521 | | if (relay_ssltcp) { |
522 | | relay_info = |
523 | | jingle_create_relay_info(relay_ip, relay_ssltcp, relay_username, |
524 | | relay_password, "tls", relay_info); |
525 | | } |
526 | | params[next_index].name = "relay-info"; |
527 | | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
528 | | g_value_init(¶ms[next_index].value, G_TYPE_VALUE_ARRAY); |
529 | | g_value_set_boxed(¶ms[next_index].value, relay_info); |
530 | | g_value_array_free(relay_info); |
531 | | G_GNUC_END_IGNORE_DEPRECATIONS |
532 | | } |
533 | | } |
534 | | |
535 | | *num = num_params; |
536 | | return params; |
537 | | } |
538 | | #endif |
539 | | |