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
34 struct _JingleSessionPrivate
40 gboolean is_initiator
;
43 GList
*pending_contents
;
46 #define JINGLE_SESSION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), JINGLE_TYPE_SESSION, JingleSessionPrivate))
48 static void jingle_session_class_init (JingleSessionClass
*klass
);
49 static void jingle_session_init (JingleSession
*session
);
50 static void jingle_session_finalize (GObject
*object
);
51 static void jingle_session_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
);
52 static void jingle_session_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
);
54 static GObjectClass
*parent_class
= NULL
;
65 PROP_PENDING_CONTENTS
,
69 jingle_session_get_type()
71 static GType type
= 0;
74 static const GTypeInfo info
= {
75 sizeof(JingleSessionClass
),
78 (GClassInitFunc
) jingle_session_class_init
,
81 sizeof(JingleSession
),
83 (GInstanceInitFunc
) jingle_session_init
,
86 type
= g_type_register_static(G_TYPE_OBJECT
, "JingleSession", &info
, 0);
92 jingle_session_class_init (JingleSessionClass
*klass
)
94 GObjectClass
*gobject_class
= (GObjectClass
*)klass
;
95 parent_class
= g_type_class_peek_parent(klass
);
97 gobject_class
->finalize
= jingle_session_finalize
;
98 gobject_class
->set_property
= jingle_session_set_property
;
99 gobject_class
->get_property
= jingle_session_get_property
;
101 g_object_class_install_property(gobject_class
, PROP_SID
,
102 g_param_spec_string("sid",
104 "The unique session ID of the Jingle Session.",
106 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
108 g_object_class_install_property(gobject_class
, PROP_JS
,
109 g_param_spec_pointer("js",
111 "The Jabber stream associated with this session.",
112 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
114 g_object_class_install_property(gobject_class
, PROP_REMOTE_JID
,
115 g_param_spec_string("remote-jid",
117 "The JID of the remote participant.",
119 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
121 g_object_class_install_property(gobject_class
, PROP_LOCAL_JID
,
122 g_param_spec_string("local-jid",
124 "The JID of the local participant.",
126 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
128 g_object_class_install_property(gobject_class
, PROP_IS_INITIATOR
,
129 g_param_spec_boolean("is-initiator",
131 "Whether or not the local JID is the initiator of the session.",
133 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
));
135 g_object_class_install_property(gobject_class
, PROP_STATE
,
136 g_param_spec_boolean("state",
138 "The state of the session (PENDING=FALSE, ACTIVE=TRUE).",
142 g_object_class_install_property(gobject_class
, PROP_CONTENTS
,
143 g_param_spec_pointer("contents",
145 "The active contents contained within this session",
148 g_object_class_install_property(gobject_class
, PROP_PENDING_CONTENTS
,
149 g_param_spec_pointer("pending-contents",
151 "The pending contents contained within this session",
154 g_type_class_add_private(klass
, sizeof(JingleSessionPrivate
));
158 jingle_session_init (JingleSession
*session
)
160 session
->priv
= JINGLE_SESSION_GET_PRIVATE(session
);
161 memset(session
->priv
, 0, sizeof(*session
->priv
));
165 jingle_session_finalize (GObject
*session
)
167 JingleSessionPrivate
*priv
= JINGLE_SESSION_GET_PRIVATE(session
);
168 purple_debug_info("jingle","jingle_session_finalize\n");
170 g_hash_table_remove(priv
->js
->sessions
, priv
->sid
);
173 g_free(priv
->remote_jid
);
174 g_free(priv
->local_jid
);
176 for (; priv
->contents
; priv
->contents
=
177 g_list_delete_link(priv
->contents
, priv
->contents
)) {
178 g_object_unref(priv
->contents
->data
);
180 for (; priv
->pending_contents
; priv
->pending_contents
=
181 g_list_delete_link(priv
->pending_contents
, priv
->pending_contents
)) {
182 g_object_unref(priv
->pending_contents
->data
);
185 parent_class
->finalize(session
);
189 jingle_session_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
191 JingleSession
*session
;
193 g_return_if_fail(object
!= NULL
);
194 g_return_if_fail(JINGLE_IS_SESSION(object
));
196 session
= JINGLE_SESSION(object
);
200 g_free(session
->priv
->sid
);
201 session
->priv
->sid
= g_value_dup_string(value
);
204 session
->priv
->js
= g_value_get_pointer(value
);
206 case PROP_REMOTE_JID
:
207 g_free(session
->priv
->remote_jid
);
208 session
->priv
->remote_jid
= g_value_dup_string(value
);
211 g_free(session
->priv
->local_jid
);
212 session
->priv
->local_jid
= g_value_dup_string(value
);
214 case PROP_IS_INITIATOR
:
215 session
->priv
->is_initiator
= g_value_get_boolean(value
);
218 session
->priv
->state
= g_value_get_boolean(value
);
221 session
->priv
->contents
= g_value_get_pointer(value
);
223 case PROP_PENDING_CONTENTS
:
224 session
->priv
->pending_contents
= g_value_get_pointer(value
);
227 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
233 jingle_session_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
235 JingleSession
*session
;
237 g_return_if_fail(object
!= NULL
);
238 g_return_if_fail(JINGLE_IS_SESSION(object
));
240 session
= JINGLE_SESSION(object
);
244 g_value_set_string(value
, session
->priv
->sid
);
247 g_value_set_pointer(value
, session
->priv
->js
);
249 case PROP_REMOTE_JID
:
250 g_value_set_string(value
, session
->priv
->remote_jid
);
253 g_value_set_string(value
, session
->priv
->local_jid
);
255 case PROP_IS_INITIATOR
:
256 g_value_set_boolean(value
, session
->priv
->is_initiator
);
259 g_value_set_boolean(value
, session
->priv
->state
);
262 g_value_set_pointer(value
, session
->priv
->contents
);
264 case PROP_PENDING_CONTENTS
:
265 g_value_set_pointer(value
, session
->priv
->pending_contents
);
268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
275 jingle_session_create(JabberStream
*js
, const gchar
*sid
,
276 const gchar
*local_jid
, const gchar
*remote_jid
,
277 gboolean is_initiator
)
279 JingleSession
*session
= g_object_new(jingle_session_get_type(),
282 "local-jid", local_jid
,
283 "remote-jid", remote_jid
,
284 "is_initiator", is_initiator
,
287 /* insert it into the hash table */
289 purple_debug_info("jingle",
290 "Creating hash table for sessions\n");
291 js
->sessions
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
293 purple_debug_info("jingle",
294 "inserting session with key: %s into table\n", sid
);
295 g_hash_table_insert(js
->sessions
, g_strdup(sid
), session
);
301 jingle_session_get_js(JingleSession
*session
)
304 g_object_get(session
, "js", &js
, NULL
);
309 jingle_session_get_sid(JingleSession
*session
)
312 g_object_get(session
, "sid", &sid
, NULL
);
317 jingle_session_get_local_jid(JingleSession
*session
)
320 g_object_get(session
, "local-jid", &local_jid
, NULL
);
325 jingle_session_get_remote_jid(JingleSession
*session
)
328 g_object_get(session
, "remote-jid", &remote_jid
, NULL
);
333 jingle_session_is_initiator(JingleSession
*session
)
335 gboolean is_initiator
;
336 g_object_get(session
, "is-initiator", &is_initiator
, NULL
);
341 jingle_session_get_state(JingleSession
*session
)
344 g_object_get(session
, "state", &state
, NULL
);
349 jingle_session_get_contents(JingleSession
*session
)
352 g_object_get(session
, "contents", &contents
, NULL
);
357 jingle_session_get_pending_contents(JingleSession
*session
)
359 GList
*pending_contents
;
360 g_object_get(session
, "pending-contents", &pending_contents
, NULL
);
361 return pending_contents
;
365 jingle_session_find_by_sid(JabberStream
*js
, const gchar
*sid
)
367 JingleSession
*session
= NULL
;
370 session
= g_hash_table_lookup(js
->sessions
, sid
);
372 purple_debug_info("jingle", "find_by_id %s\n", sid
);
373 purple_debug_info("jingle", "lookup: %p\n", session
);
378 static gboolean
find_by_jid_ghr(gpointer key
,
379 gpointer value
, gpointer user_data
)
381 JingleSession
*session
= (JingleSession
*)value
;
382 const gchar
*jid
= user_data
;
383 gboolean use_bare
= strchr(jid
, '/') == NULL
;
384 gchar
*remote_jid
= jingle_session_get_remote_jid(session
);
385 gchar
*cmp_jid
= use_bare
? jabber_get_bare_jid(remote_jid
)
386 : g_strdup(remote_jid
);
388 if (g_str_equal(jid
, cmp_jid
)) {
398 jingle_session_find_by_jid(JabberStream
*js
, const gchar
*jid
)
400 return js
->sessions
!= NULL
?
401 g_hash_table_find(js
->sessions
,
402 find_by_jid_ghr
, (gpointer
)jid
) : NULL
;
406 jingle_add_jingle_packet(JingleSession
*session
,
407 JabberIq
*iq
, JingleActionType action
)
409 xmlnode
*jingle
= iq
?
410 xmlnode_new_child(iq
->node
, "jingle") :
411 xmlnode_new("jingle");
412 gchar
*local_jid
= jingle_session_get_local_jid(session
);
413 gchar
*remote_jid
= jingle_session_get_remote_jid(session
);
414 gchar
*sid
= jingle_session_get_sid(session
);
416 xmlnode_set_namespace(jingle
, JINGLE
);
417 xmlnode_set_attrib(jingle
, "action", jingle_get_action_name(action
));
419 if (jingle_session_is_initiator(session
)) {
420 xmlnode_set_attrib(jingle
, "initiator", local_jid
);
421 xmlnode_set_attrib(jingle
, "responder", remote_jid
);
423 xmlnode_set_attrib(jingle
, "initiator", remote_jid
);
424 xmlnode_set_attrib(jingle
, "responder", local_jid
);
427 xmlnode_set_attrib(jingle
, "sid", sid
);
437 jingle_session_create_ack(JingleSession
*session
, const xmlnode
*jingle
)
439 JabberIq
*result
= jabber_iq_new(
440 jingle_session_get_js(session
),
442 xmlnode
*packet
= xmlnode_get_parent(jingle
);
443 jabber_iq_set_id(result
, xmlnode_get_attrib(packet
, "id"));
444 xmlnode_set_attrib(result
->node
, "from", xmlnode_get_attrib(packet
, "to"));
445 xmlnode_set_attrib(result
->node
, "to", xmlnode_get_attrib(packet
, "from"));
450 jingle_create_iq(JingleSession
*session
)
452 JabberStream
*js
= jingle_session_get_js(session
);
453 JabberIq
*result
= jabber_iq_new(js
, JABBER_IQ_SET
);
454 gchar
*from
= jingle_session_get_local_jid(session
);
455 gchar
*to
= jingle_session_get_remote_jid(session
);
457 xmlnode_set_attrib(result
->node
, "from", from
);
458 xmlnode_set_attrib(result
->node
, "to", to
);
466 jingle_session_to_xml(JingleSession
*session
, xmlnode
*jingle
, JingleActionType action
)
468 if (action
!= JINGLE_SESSION_INFO
&& action
!= JINGLE_SESSION_TERMINATE
) {
470 if (action
== JINGLE_CONTENT_ACCEPT
471 || action
== JINGLE_CONTENT_ADD
472 || action
== JINGLE_CONTENT_REMOVE
)
473 iter
= jingle_session_get_pending_contents(session
);
475 iter
= jingle_session_get_contents(session
);
477 for (; iter
; iter
= g_list_next(iter
)) {
478 jingle_content_to_xml(iter
->data
, jingle
, action
);
485 jingle_session_to_packet(JingleSession
*session
, JingleActionType action
)
487 JabberIq
*iq
= jingle_create_iq(session
);
488 xmlnode
*jingle
= jingle_add_jingle_packet(session
, iq
, action
);
489 jingle_session_to_xml(session
, jingle
, action
);
493 void jingle_session_handle_action(JingleSession
*session
, xmlnode
*jingle
, JingleActionType action
)
496 if (action
== JINGLE_CONTENT_ADD
|| action
== JINGLE_CONTENT_REMOVE
)
497 iter
= jingle_session_get_pending_contents(session
);
499 iter
= jingle_session_get_contents(session
);
501 for (; iter
; iter
= g_list_next(iter
)) {
502 jingle_content_handle_action(iter
->data
, jingle
, action
);
507 jingle_session_find_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
514 iter
= session
->priv
->contents
;
515 for (; iter
; iter
= g_list_next(iter
)) {
516 JingleContent
*content
= iter
->data
;
517 gchar
*cname
= jingle_content_get_name(content
);
518 gboolean result
= g_str_equal(name
, cname
);
521 if (creator
!= NULL
) {
522 gchar
*ccreator
= jingle_content_get_creator(content
);
523 result
= (result
&& !strcmp(creator
, ccreator
));
534 jingle_session_find_pending_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
541 iter
= session
->priv
->pending_contents
;
542 for (; iter
; iter
= g_list_next(iter
)) {
543 JingleContent
*content
= iter
->data
;
544 gchar
*cname
= jingle_content_get_name(content
);
545 gboolean result
= g_str_equal(name
, cname
);
548 if (creator
!= NULL
) {
549 gchar
*ccreator
= jingle_content_get_creator(content
);
550 result
= (result
&& !strcmp(creator
, ccreator
));
561 jingle_session_add_content(JingleSession
*session
, JingleContent
* content
)
563 session
->priv
->contents
=
564 g_list_append(session
->priv
->contents
, content
);
565 jingle_content_set_session(content
, session
);
569 jingle_session_remove_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
571 JingleContent
*content
=
572 jingle_session_find_content(session
, name
, creator
);
575 session
->priv
->contents
=
576 g_list_remove(session
->priv
->contents
, content
);
577 g_object_unref(content
);
582 jingle_session_add_pending_content(JingleSession
*session
, JingleContent
* content
)
584 session
->priv
->pending_contents
=
585 g_list_append(session
->priv
->pending_contents
, content
);
586 jingle_content_set_session(content
, session
);
590 jingle_session_remove_pending_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
592 JingleContent
*content
= jingle_session_find_pending_content(session
, name
, creator
);
595 session
->priv
->pending_contents
=
596 g_list_remove(session
->priv
->pending_contents
, content
);
597 g_object_unref(content
);
602 jingle_session_accept_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
604 JingleContent
*content
= jingle_session_find_pending_content(session
, name
, creator
);
607 g_object_ref(content
);
608 jingle_session_remove_pending_content(session
, name
, creator
);
609 jingle_session_add_content(session
, content
);
614 jingle_session_accept_session(JingleSession
*session
)
616 session
->priv
->state
= TRUE
;
620 jingle_session_terminate_packet(JingleSession
*session
, const gchar
*reason
)
622 JabberIq
*iq
= jingle_session_to_packet(session
,
623 JINGLE_SESSION_TERMINATE
);
624 xmlnode
*jingle
= xmlnode_get_child(iq
->node
, "jingle");
626 if (reason
!= NULL
) {
627 xmlnode
*reason_node
;
628 reason_node
= xmlnode_new_child(jingle
, "reason");
629 xmlnode_new_child(reason_node
, reason
);
635 jingle_session_redirect_packet(JingleSession
*session
, const gchar
*sid
)
637 JabberIq
*iq
= jingle_session_terminate_packet(session
,
638 "alternative-session");
639 xmlnode
*alt_session
;
644 alt_session
= xmlnode_get_child(iq
->node
,
645 "jingle/reason/alternative-session");
647 if (alt_session
!= NULL
) {
648 xmlnode
*sid_node
= xmlnode_new_child(alt_session
, "sid");
649 xmlnode_insert_data(sid_node
, sid
, -1);