4
* purple - Jabber Protocol Plugin
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
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.
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.
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
43
jingle_get_type(const gchar *type)
48
if (!strcmp(type, JINGLE_TRANSPORT_RAWUDP))
49
return JINGLE_TYPE_RAWUDP;
50
else if (!strcmp(type, JINGLE_TRANSPORT_ICEUDP))
51
return JINGLE_TYPE_ICEUDP;
53
else if (!strcmp(type, JINGLE_TRANSPORT_SOCKS))
54
return JINGLE_TYPE_SOCKS;
55
else if (!strcmp(type, JINGLE_TRANSPORT_IBB))
56
return JINGLE_TYPE_IBB;
59
else if (!strcmp(type, JINGLE_APP_RTP))
60
return JINGLE_TYPE_RTP;
63
else if (!strcmp(type, JINGLE_APP_FT))
64
return JINGLE_TYPE_FT;
65
else if (!strcmp(type, JINGLE_APP_XML))
66
return JINGLE_TYPE_XML;
73
jingle_handle_unknown_type(JingleSession *session, xmlnode *jingle)
79
jingle_handle_content_accept(JingleSession *session, xmlnode *jingle)
81
xmlnode *content = xmlnode_get_child(jingle, "content");
82
jabber_iq_send(jingle_session_create_ack(session, jingle));
84
for (; content; content = xmlnode_get_next_twin(content)) {
85
const gchar *name = xmlnode_get_attrib(content, "name");
86
const gchar *creator = xmlnode_get_attrib(content, "creator");
87
jingle_session_accept_content(session, name, creator);
93
jingle_handle_content_add(JingleSession *session, xmlnode *jingle)
95
xmlnode *content = xmlnode_get_child(jingle, "content");
96
jabber_iq_send(jingle_session_create_ack(session, jingle));
98
for (; content; content = xmlnode_get_next_twin(content)) {
99
JingleContent *pending_content =
100
jingle_content_parse(content);
101
if (pending_content == NULL) {
102
purple_debug_error("jingle",
103
"Error parsing \"content-add\" content.\n");
104
jabber_iq_send(jingle_session_terminate_packet(session,
105
"unsupported-applications"));
107
jingle_session_add_pending_content(session,
112
/* XXX: signal here */
116
jingle_handle_content_modify(JingleSession *session, xmlnode *jingle)
118
xmlnode *content = xmlnode_get_child(jingle, "content");
119
jabber_iq_send(jingle_session_create_ack(session, jingle));
121
for (; content; content = xmlnode_get_next_twin(content)) {
122
const gchar *name = xmlnode_get_attrib(content, "name");
123
const gchar *creator = xmlnode_get_attrib(content, "creator");
124
JingleContent *local_content = jingle_session_find_content(session, name, creator);
126
if (local_content != NULL) {
127
const gchar *senders = xmlnode_get_attrib(content, "senders");
128
gchar *local_senders = jingle_content_get_senders(local_content);
129
if (!purple_strequal(senders, local_senders))
130
jingle_content_modify(local_content, senders);
131
g_free(local_senders);
133
purple_debug_error("jingle", "content_modify: unknown content\n");
134
jabber_iq_send(jingle_session_terminate_packet(session,
135
"unknown-applications"));
141
jingle_handle_content_reject(JingleSession *session, xmlnode *jingle)
143
xmlnode *content = xmlnode_get_child(jingle, "content");
144
jabber_iq_send(jingle_session_create_ack(session, jingle));
146
for (; content; content = xmlnode_get_next_twin(content)) {
147
const gchar *name = xmlnode_get_attrib(content, "name");
148
const gchar *creator = xmlnode_get_attrib(content, "creator");
149
jingle_session_remove_pending_content(session, name, creator);
155
jingle_handle_content_remove(JingleSession *session, xmlnode *jingle)
157
xmlnode *content = xmlnode_get_child(jingle, "content");
159
jabber_iq_send(jingle_session_create_ack(session, jingle));
161
for (; content; content = xmlnode_get_next_twin(content)) {
162
const gchar *name = xmlnode_get_attrib(content, "name");
163
const gchar *creator = xmlnode_get_attrib(content, "creator");
164
jingle_session_remove_content(session, name, creator);
169
jingle_handle_description_info(JingleSession *session, xmlnode *jingle)
171
xmlnode *content = xmlnode_get_child(jingle, "content");
173
jabber_iq_send(jingle_session_create_ack(session, jingle));
175
jingle_session_accept_session(session);
177
for (; content; content = xmlnode_get_next_twin(content)) {
178
const gchar *name = xmlnode_get_attrib(content, "name");
179
const gchar *creator = xmlnode_get_attrib(content, "creator");
180
JingleContent *parsed_content =
181
jingle_session_find_content(session, name, creator);
182
if (parsed_content == NULL) {
183
purple_debug_error("jingle", "Error parsing content\n");
184
jabber_iq_send(jingle_session_terminate_packet(session,
185
"unsupported-applications"));
187
jingle_content_handle_action(parsed_content, content,
188
JINGLE_DESCRIPTION_INFO);
194
jingle_handle_security_info(JingleSession *session, xmlnode *jingle)
196
jabber_iq_send(jingle_session_create_ack(session, jingle));
200
jingle_handle_session_accept(JingleSession *session, xmlnode *jingle)
202
xmlnode *content = xmlnode_get_child(jingle, "content");
204
jabber_iq_send(jingle_session_create_ack(session, jingle));
206
jingle_session_accept_session(session);
208
for (; content; content = xmlnode_get_next_twin(content)) {
209
const gchar *name = xmlnode_get_attrib(content, "name");
210
const gchar *creator = xmlnode_get_attrib(content, "creator");
211
JingleContent *parsed_content =
212
jingle_session_find_content(session, name, creator);
213
if (parsed_content == NULL) {
214
purple_debug_error("jingle", "Error parsing content\n");
215
jabber_iq_send(jingle_session_terminate_packet(session,
216
"unsupported-applications"));
218
jingle_content_handle_action(parsed_content, content,
219
JINGLE_SESSION_ACCEPT);
225
jingle_handle_session_info(JingleSession *session, xmlnode *jingle)
227
jabber_iq_send(jingle_session_create_ack(session, jingle));
228
/* XXX: call signal */
232
jingle_handle_session_initiate(JingleSession *session, xmlnode *jingle)
234
xmlnode *content = xmlnode_get_child(jingle, "content");
236
for (; content; content = xmlnode_get_next_twin(content)) {
237
JingleContent *parsed_content = jingle_content_parse(content);
238
if (parsed_content == NULL) {
239
purple_debug_error("jingle", "Error parsing content\n");
240
jabber_iq_send(jingle_session_terminate_packet(session,
241
"unsupported-applications"));
243
jingle_session_add_content(session, parsed_content);
244
jingle_content_handle_action(parsed_content, content,
245
JINGLE_SESSION_INITIATE);
249
jabber_iq_send(jingle_session_create_ack(session, jingle));
253
jingle_handle_session_terminate(JingleSession *session, xmlnode *jingle)
255
jabber_iq_send(jingle_session_create_ack(session, jingle));
257
jingle_session_handle_action(session, jingle,
258
JINGLE_SESSION_TERMINATE);
259
/* display reason? */
260
g_object_unref(session);
264
jingle_handle_transport_accept(JingleSession *session, xmlnode *jingle)
266
xmlnode *content = xmlnode_get_child(jingle, "content");
268
jabber_iq_send(jingle_session_create_ack(session, jingle));
270
for (; content; content = xmlnode_get_next_twin(content)) {
271
const gchar *name = xmlnode_get_attrib(content, "name");
272
const gchar *creator = xmlnode_get_attrib(content, "creator");
273
JingleContent *content = jingle_session_find_content(session, name, creator);
274
jingle_content_accept_transport(content);
279
jingle_handle_transport_info(JingleSession *session, xmlnode *jingle)
281
xmlnode *content = xmlnode_get_child(jingle, "content");
283
jabber_iq_send(jingle_session_create_ack(session, jingle));
285
for (; content; content = xmlnode_get_next_twin(content)) {
286
const gchar *name = xmlnode_get_attrib(content, "name");
287
const gchar *creator = xmlnode_get_attrib(content, "creator");
288
JingleContent *parsed_content =
289
jingle_session_find_content(session, name, creator);
290
if (parsed_content == NULL) {
291
purple_debug_error("jingle", "Error parsing content\n");
292
jabber_iq_send(jingle_session_terminate_packet(session,
293
"unsupported-applications"));
295
jingle_content_handle_action(parsed_content, content,
296
JINGLE_TRANSPORT_INFO);
302
jingle_handle_transport_reject(JingleSession *session, xmlnode *jingle)
304
xmlnode *content = xmlnode_get_child(jingle, "content");
306
jabber_iq_send(jingle_session_create_ack(session, jingle));
308
for (; content; content = xmlnode_get_next_twin(content)) {
309
const gchar *name = xmlnode_get_attrib(content, "name");
310
const gchar *creator = xmlnode_get_attrib(content, "creator");
311
JingleContent *content = jingle_session_find_content(session, name, creator);
312
jingle_content_remove_pending_transport(content);
317
jingle_handle_transport_replace(JingleSession *session, xmlnode *jingle)
319
xmlnode *content = xmlnode_get_child(jingle, "content");
321
jabber_iq_send(jingle_session_create_ack(session, jingle));
323
for (; content; content = xmlnode_get_next_twin(content)) {
324
const gchar *name = xmlnode_get_attrib(content, "name");
325
const gchar *creator = xmlnode_get_attrib(content, "creator");
326
xmlnode *xmltransport = xmlnode_get_child(content, "transport");
327
JingleTransport *transport = jingle_transport_parse(xmltransport);
328
JingleContent *content = jingle_session_find_content(session, name, creator);
330
jingle_content_set_pending_transport(content, transport);
336
void (*handler)(JingleSession*, xmlnode*);
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},
359
jingle_get_action_name(JingleActionType action)
361
return jingle_actions[action].name;
365
jingle_get_action_type(const gchar *action)
367
static const int num_actions =
368
sizeof(jingle_actions)/sizeof(JingleAction);
369
/* Start at 1 to skip the unknown-action type */
371
for (; i < num_actions; ++i) {
372
if (!strcmp(action, jingle_actions[i].name))
375
return JINGLE_UNKNOWN_TYPE;
379
jingle_parse(JabberStream *js, const char *from, JabberIqType type,
380
const char *id, xmlnode *jingle)
384
JingleActionType action_type;
385
JingleSession *session;
387
if (type != JABBER_IQ_SET) {
388
/* TODO: send iq error here */
392
if (!(action = xmlnode_get_attrib(jingle, "action"))) {
393
/* TODO: send iq error here */
397
action_type = jingle_get_action_type(action);
399
purple_debug_info("jabber", "got Jingle package action = %s\n",
402
if (!(sid = xmlnode_get_attrib(jingle, "sid"))) {
403
/* send iq error here */
407
if (!(session = jingle_session_find_by_sid(js, sid))
408
&& strcmp(action, "session-initiate")) {
409
purple_debug_error("jingle", "jabber_jingle_session_parse couldn't find session\n");
410
/* send iq error here */
414
if (action_type == JINGLE_SESSION_INITIATE) {
416
/* This should only happen if you start a session with yourself */
417
purple_debug_error("jingle", "Jingle session with "
418
"id={%s} already exists\n", sid);
422
char *own_jid = g_strdup_printf("%s@%s/%s", js->user->node,
423
js->user->domain, js->user->resource);
424
session = jingle_session_create(js, sid, own_jid, from, FALSE);
429
jingle_actions[action_type].handler(session, jingle);
433
jingle_terminate_sessions_gh(gpointer key, gpointer value, gpointer user_data)
435
g_object_unref(value);
439
jingle_terminate_sessions(JabberStream *js)
442
g_hash_table_foreach(js->sessions,
443
jingle_terminate_sessions_gh, NULL);
448
jingle_create_relay_info(const gchar *ip, guint port, const gchar *username,
449
const gchar *password, const gchar *relay_type, GValueArray *relay_info)
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,
459
purple_debug_info("jabber", "created gst_structure %" GST_PTR_FORMAT "\n",
462
memset(&value, 0, sizeof(GValue));
463
g_value_init(&value, GST_TYPE_STRUCTURE);
464
gst_value_set_structure(&value, turn_setup);
465
relay_info = g_value_array_append(relay_info, &value);
466
gst_structure_free(turn_setup);
472
jingle_get_params(JabberStream *js, const gchar *relay_ip, guint relay_udp,
473
guint relay_tcp, guint relay_ssltcp, const gchar *relay_username,
474
const gchar *relay_password, guint *num)
476
/* don't set a STUN server if one is set globally in prefs, in that case
477
this will be handled in media.c */
478
gboolean has_account_stun = js->stun_ip && !purple_network_get_stun_ip();
479
guint num_params = has_account_stun ?
480
(relay_ip ? 3 : 2) : (relay_ip ? 1 : 0);
481
GParameter *params = NULL;
484
if (num_params > 0) {
485
params = g_new0(GParameter, num_params);
487
if (has_account_stun) {
488
purple_debug_info("jabber",
489
"setting param stun-ip for stream using Google auto-config: %s\n",
491
params[next_index].name = "stun-ip";
492
g_value_init(¶ms[next_index].value, G_TYPE_STRING);
493
g_value_set_string(¶ms[next_index].value, js->stun_ip);
494
purple_debug_info("jabber",
495
"setting param stun-port for stream using Google auto-config: %d\n",
498
params[next_index].name = "stun-port";
499
g_value_init(¶ms[next_index].value, G_TYPE_UINT);
500
g_value_set_uint(¶ms[next_index].value, js->stun_port);
505
GValueArray *relay_info = g_value_array_new(0);
509
jingle_create_relay_info(relay_ip, relay_udp, relay_username,
510
relay_password, "udp", relay_info);
514
jingle_create_relay_info(relay_ip, relay_tcp, relay_username,
515
relay_password, "tcp", relay_info);
519
jingle_create_relay_info(relay_ip, relay_ssltcp, relay_username,
520
relay_password, "tls", relay_info);
522
params[next_index].name = "relay-info";
523
g_value_init(¶ms[next_index].value, G_TYPE_VALUE_ARRAY);
524
g_value_set_boxed(¶ms[next_index].value, relay_info);
525
g_value_array_free(relay_info);