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
26 #include "glibcompat.h"
46 gboolean is_initiator
;
49 GList
*pending_contents
;
50 } JingleSessionPrivate
;
61 PROP_PENDING_CONTENTS
,
65 static GParamSpec
*properties
[PROP_LAST
];
67 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
72 G_ADD_PRIVATE_DYNAMIC(JingleSession
)
75 /******************************************************************************
77 *****************************************************************************/
78 static gboolean
find_by_jid_ghr(gpointer key
,
79 gpointer value
, gpointer user_data
)
81 JingleSession
*session
= (JingleSession
*)value
;
82 const gchar
*jid
= user_data
;
83 gboolean use_bare
= strchr(jid
, '/') == NULL
;
84 gchar
*remote_jid
= jingle_session_get_remote_jid(session
);
85 gchar
*cmp_jid
= use_bare
? jabber_get_bare_jid(remote_jid
)
86 : g_strdup(remote_jid
);
88 if (purple_strequal(jid
, cmp_jid
)) {
97 static PurpleXmlNode
*
98 jingle_add_jingle_packet(JingleSession
*session
,
99 JabberIq
*iq
, JingleActionType action
)
101 PurpleXmlNode
*jingle
= iq
?
102 purple_xmlnode_new_child(iq
->node
, "jingle") :
103 purple_xmlnode_new("jingle");
104 gchar
*local_jid
= jingle_session_get_local_jid(session
);
105 gchar
*remote_jid
= jingle_session_get_remote_jid(session
);
106 gchar
*sid
= jingle_session_get_sid(session
);
108 purple_xmlnode_set_namespace(jingle
, JINGLE
);
109 purple_xmlnode_set_attrib(jingle
, "action", jingle_get_action_name(action
));
111 if (jingle_session_is_initiator(session
)) {
112 purple_xmlnode_set_attrib(jingle
, "initiator", local_jid
);
113 purple_xmlnode_set_attrib(jingle
, "responder", remote_jid
);
115 purple_xmlnode_set_attrib(jingle
, "initiator", remote_jid
);
116 purple_xmlnode_set_attrib(jingle
, "responder", local_jid
);
119 purple_xmlnode_set_attrib(jingle
, "sid", sid
);
129 jingle_create_iq(JingleSession
*session
)
131 JabberStream
*js
= jingle_session_get_js(session
);
132 JabberIq
*result
= jabber_iq_new(js
, JABBER_IQ_SET
);
133 gchar
*from
= jingle_session_get_local_jid(session
);
134 gchar
*to
= jingle_session_get_remote_jid(session
);
136 purple_xmlnode_set_attrib(result
->node
, "from", from
);
137 purple_xmlnode_set_attrib(result
->node
, "to", to
);
144 /******************************************************************************
145 * GObject Implementation
146 *****************************************************************************/
148 jingle_session_set_property (GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
150 JingleSession
*session
= JINGLE_SESSION(object
);
151 JingleSessionPrivate
*priv
= jingle_session_get_instance_private(session
);
156 priv
->sid
= g_value_dup_string(value
);
159 priv
->js
= g_value_get_pointer(value
);
161 case PROP_REMOTE_JID
:
162 g_free(priv
->remote_jid
);
163 priv
->remote_jid
= g_value_dup_string(value
);
166 g_free(priv
->local_jid
);
167 priv
->local_jid
= g_value_dup_string(value
);
169 case PROP_IS_INITIATOR
:
170 priv
->is_initiator
= g_value_get_boolean(value
);
173 priv
->state
= g_value_get_boolean(value
);
176 priv
->contents
= g_value_get_pointer(value
);
178 case PROP_PENDING_CONTENTS
:
179 priv
->pending_contents
= g_value_get_pointer(value
);
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
188 jingle_session_get_property (GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
190 JingleSession
*session
= JINGLE_SESSION(object
);
191 JingleSessionPrivate
*priv
= jingle_session_get_instance_private(session
);
195 g_value_set_string(value
, priv
->sid
);
198 g_value_set_pointer(value
, priv
->js
);
200 case PROP_REMOTE_JID
:
201 g_value_set_string(value
, priv
->remote_jid
);
204 g_value_set_string(value
, priv
->local_jid
);
206 case PROP_IS_INITIATOR
:
207 g_value_set_boolean(value
, priv
->is_initiator
);
210 g_value_set_boolean(value
, priv
->state
);
213 g_value_set_pointer(value
, priv
->contents
);
215 case PROP_PENDING_CONTENTS
:
216 g_value_set_pointer(value
, priv
->pending_contents
);
219 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
225 jingle_session_init (JingleSession
*session
)
230 jingle_session_finalize (GObject
*session
)
232 JingleSessionPrivate
*priv
= jingle_session_get_instance_private(JINGLE_SESSION(session
));
233 purple_debug_info("jingle","jingle_session_finalize\n");
235 g_hash_table_remove(priv
->js
->sessions
, priv
->sid
);
238 g_free(priv
->remote_jid
);
239 g_free(priv
->local_jid
);
241 g_list_free_full(priv
->contents
, g_object_unref
);
242 g_list_free_full(priv
->pending_contents
, g_object_unref
);
244 G_OBJECT_CLASS(jingle_session_parent_class
)->finalize(session
);
248 jingle_session_class_finalize (JingleSessionClass
*klass
)
253 jingle_session_class_init (JingleSessionClass
*klass
)
255 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
257 obj_class
->finalize
= jingle_session_finalize
;
258 obj_class
->set_property
= jingle_session_set_property
;
259 obj_class
->get_property
= jingle_session_get_property
;
261 properties
[PROP_SID
] = g_param_spec_string("sid",
263 "The unique session ID of the Jingle Session.",
265 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
267 properties
[PROP_JS
] = g_param_spec_pointer("js",
269 "The Jabber stream associated with this session.",
270 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
272 properties
[PROP_REMOTE_JID
] = g_param_spec_string("remote-jid",
274 "The JID of the remote participant.",
276 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
278 properties
[PROP_LOCAL_JID
] = g_param_spec_string("local-jid",
280 "The JID of the local participant.",
282 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
284 properties
[PROP_IS_INITIATOR
] = g_param_spec_boolean("is-initiator",
286 "Whether or not the local JID is the initiator of the session.",
288 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
290 properties
[PROP_STATE
] = g_param_spec_boolean("state",
292 "The state of the session (PENDING=FALSE, ACTIVE=TRUE).",
294 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
296 properties
[PROP_CONTENTS
] = g_param_spec_pointer("contents",
298 "The active contents contained within this session",
299 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
301 properties
[PROP_PENDING_CONTENTS
] = g_param_spec_pointer("pending-contents",
303 "The pending contents contained within this session",
304 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
306 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
309 /******************************************************************************
311 *****************************************************************************/
313 jingle_session_register(PurplePlugin
*plugin
) {
314 jingle_session_register_type(G_TYPE_MODULE(plugin
));
318 jingle_session_create(JabberStream
*js
, const gchar
*sid
,
319 const gchar
*local_jid
, const gchar
*remote_jid
,
320 gboolean is_initiator
)
322 JingleSession
*session
= g_object_new(jingle_session_get_type(),
325 "local-jid", local_jid
,
326 "remote-jid", remote_jid
,
327 "is_initiator", is_initiator
,
330 /* insert it into the hash table */
332 purple_debug_info("jingle",
333 "Creating hash table for sessions\n");
334 js
->sessions
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
336 purple_debug_info("jingle",
337 "inserting session with key: %s into table\n", sid
);
338 g_hash_table_insert(js
->sessions
, g_strdup(sid
), session
);
344 jingle_session_get_js(JingleSession
*session
)
347 g_object_get(session
, "js", &js
, NULL
);
352 jingle_session_get_sid(JingleSession
*session
)
355 g_object_get(session
, "sid", &sid
, NULL
);
360 jingle_session_get_local_jid(JingleSession
*session
)
363 g_object_get(session
, "local-jid", &local_jid
, NULL
);
368 jingle_session_get_remote_jid(JingleSession
*session
)
371 g_object_get(session
, "remote-jid", &remote_jid
, NULL
);
376 jingle_session_is_initiator(JingleSession
*session
)
378 gboolean is_initiator
;
379 g_object_get(session
, "is-initiator", &is_initiator
, NULL
);
384 jingle_session_get_state(JingleSession
*session
)
387 g_object_get(session
, "state", &state
, NULL
);
392 jingle_session_get_contents(JingleSession
*session
)
395 g_object_get(session
, "contents", &contents
, NULL
);
400 jingle_session_get_pending_contents(JingleSession
*session
)
402 GList
*pending_contents
;
403 g_object_get(session
, "pending-contents", &pending_contents
, NULL
);
404 return pending_contents
;
408 jingle_session_find_by_sid(JabberStream
*js
, const gchar
*sid
)
410 JingleSession
*session
= NULL
;
413 session
= g_hash_table_lookup(js
->sessions
, sid
);
415 purple_debug_info("jingle", "find_by_id %s\n", sid
);
416 purple_debug_info("jingle", "lookup: %p\n", session
);
422 jingle_session_find_by_jid(JabberStream
*js
, const gchar
*jid
)
424 return js
->sessions
!= NULL
?
425 g_hash_table_find(js
->sessions
,
426 find_by_jid_ghr
, (gpointer
)jid
) : NULL
;
430 jingle_session_create_ack(JingleSession
*session
, const PurpleXmlNode
*jingle
)
432 JabberIq
*result
= jabber_iq_new(
433 jingle_session_get_js(session
),
435 PurpleXmlNode
*packet
= purple_xmlnode_get_parent(jingle
);
436 jabber_iq_set_id(result
, purple_xmlnode_get_attrib(packet
, "id"));
437 purple_xmlnode_set_attrib(result
->node
, "from", purple_xmlnode_get_attrib(packet
, "to"));
438 purple_xmlnode_set_attrib(result
->node
, "to", purple_xmlnode_get_attrib(packet
, "from"));
443 jingle_session_to_xml(JingleSession
*session
, PurpleXmlNode
*jingle
, JingleActionType action
)
445 if (action
!= JINGLE_SESSION_INFO
&& action
!= JINGLE_SESSION_TERMINATE
) {
447 if (action
== JINGLE_CONTENT_ACCEPT
448 || action
== JINGLE_CONTENT_ADD
449 || action
== JINGLE_CONTENT_REMOVE
)
450 iter
= jingle_session_get_pending_contents(session
);
452 iter
= jingle_session_get_contents(session
);
454 for (; iter
; iter
= g_list_next(iter
)) {
455 jingle_content_to_xml(iter
->data
, jingle
, action
);
462 jingle_session_to_packet(JingleSession
*session
, JingleActionType action
)
464 JabberIq
*iq
= jingle_create_iq(session
);
465 PurpleXmlNode
*jingle
= jingle_add_jingle_packet(session
, iq
, action
);
466 jingle_session_to_xml(session
, jingle
, action
);
470 void jingle_session_handle_action(JingleSession
*session
, PurpleXmlNode
*jingle
, JingleActionType action
)
473 if (action
== JINGLE_CONTENT_ADD
|| action
== JINGLE_CONTENT_REMOVE
)
474 iter
= jingle_session_get_pending_contents(session
);
476 iter
= jingle_session_get_contents(session
);
478 for (; iter
; iter
= g_list_next(iter
)) {
479 jingle_content_handle_action(iter
->data
, jingle
, action
);
484 jingle_session_find_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
486 JingleSessionPrivate
*priv
= NULL
;
489 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
494 priv
= jingle_session_get_instance_private(session
);
496 iter
= priv
->contents
;
497 for (; iter
; iter
= g_list_next(iter
)) {
498 JingleContent
*content
= iter
->data
;
499 gchar
*cname
= jingle_content_get_name(content
);
500 gboolean result
= purple_strequal(name
, cname
);
503 if (creator
!= NULL
) {
504 gchar
*ccreator
= jingle_content_get_creator(content
);
505 result
= (result
&& purple_strequal(creator
, ccreator
));
516 jingle_session_find_pending_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
518 JingleSessionPrivate
*priv
= NULL
;
521 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
526 priv
= jingle_session_get_instance_private(session
);
528 iter
= priv
->pending_contents
;
529 for (; iter
; iter
= g_list_next(iter
)) {
530 JingleContent
*content
= iter
->data
;
531 gchar
*cname
= jingle_content_get_name(content
);
532 gboolean result
= purple_strequal(name
, cname
);
535 if (creator
!= NULL
) {
536 gchar
*ccreator
= jingle_content_get_creator(content
);
537 result
= (result
&& purple_strequal(creator
, ccreator
));
548 jingle_session_add_content(JingleSession
*session
, JingleContent
* content
)
550 JingleSessionPrivate
*priv
= NULL
;
552 g_return_if_fail(JINGLE_IS_SESSION(session
));
554 priv
= jingle_session_get_instance_private(session
);
556 priv
->contents
= g_list_append(priv
->contents
, content
);
557 jingle_content_set_session(content
, session
);
559 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_CONTENTS
]);
563 jingle_session_remove_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
565 JingleSessionPrivate
*priv
= NULL
;
566 JingleContent
*content
= NULL
;
568 g_return_if_fail(JINGLE_IS_SESSION(session
));
570 priv
= jingle_session_get_instance_private(session
);
571 content
= jingle_session_find_content(session
, name
, creator
);
574 priv
->contents
= g_list_remove(priv
->contents
, content
);
575 g_object_unref(content
);
577 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_CONTENTS
]);
582 jingle_session_add_pending_content(JingleSession
*session
, JingleContent
* content
)
584 JingleSessionPrivate
*priv
= NULL
;
586 g_return_if_fail(JINGLE_IS_SESSION(session
));
588 priv
= jingle_session_get_instance_private(session
);
590 priv
->pending_contents
= g_list_append(priv
->pending_contents
, content
);
591 jingle_content_set_session(content
, session
);
593 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_PENDING_CONTENTS
]);
597 jingle_session_remove_pending_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
599 JingleSessionPrivate
*priv
= NULL
;
600 JingleContent
*content
= NULL
;
602 g_return_if_fail(JINGLE_IS_SESSION(session
));
604 priv
= jingle_session_get_instance_private(session
);
605 content
= jingle_session_find_pending_content(session
, name
, creator
);
608 priv
->pending_contents
= g_list_remove(priv
->pending_contents
, content
);
609 g_object_unref(content
);
611 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_PENDING_CONTENTS
]);
616 jingle_session_accept_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
618 JingleContent
*content
= NULL
;
620 g_return_if_fail(JINGLE_IS_SESSION(session
));
622 content
= jingle_session_find_pending_content(session
, name
, creator
);
624 g_object_ref(content
);
625 jingle_session_remove_pending_content(session
, name
, creator
);
626 jingle_session_add_content(session
, content
);
631 jingle_session_accept_session(JingleSession
*session
)
633 JingleSessionPrivate
*priv
= NULL
;
635 g_return_if_fail(JINGLE_IS_SESSION(session
));
637 priv
= jingle_session_get_instance_private(session
);
641 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_STATE
]);
645 jingle_session_terminate_packet(JingleSession
*session
, const gchar
*reason
)
649 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
651 iq
= jingle_session_to_packet(session
, JINGLE_SESSION_TERMINATE
);
653 if (reason
!= NULL
) {
654 PurpleXmlNode
*reason_node
;
655 PurpleXmlNode
*jingle
= purple_xmlnode_get_child(iq
->node
, "jingle");
656 reason_node
= purple_xmlnode_new_child(jingle
, "reason");
657 purple_xmlnode_new_child(reason_node
, reason
);
664 jingle_session_redirect_packet(JingleSession
*session
, const gchar
*sid
)
667 PurpleXmlNode
*alt_session
;
669 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
671 iq
= jingle_session_terminate_packet(session
, "alternative-session");
676 alt_session
= purple_xmlnode_get_child(iq
->node
,
677 "jingle/reason/alternative-session");
679 if (alt_session
!= NULL
) {
680 PurpleXmlNode
*sid_node
= purple_xmlnode_new_child(alt_session
, "sid");
681 purple_xmlnode_insert_data(sid_node
, sid
, -1);