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 for (; priv
->contents
; priv
->contents
=
242 g_list_delete_link(priv
->contents
, priv
->contents
)) {
243 g_object_unref(priv
->contents
->data
);
245 for (; priv
->pending_contents
; priv
->pending_contents
=
246 g_list_delete_link(priv
->pending_contents
, priv
->pending_contents
)) {
247 g_object_unref(priv
->pending_contents
->data
);
250 G_OBJECT_CLASS(jingle_session_parent_class
)->finalize(session
);
254 jingle_session_class_finalize (JingleSessionClass
*klass
)
259 jingle_session_class_init (JingleSessionClass
*klass
)
261 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
263 obj_class
->finalize
= jingle_session_finalize
;
264 obj_class
->set_property
= jingle_session_set_property
;
265 obj_class
->get_property
= jingle_session_get_property
;
267 properties
[PROP_SID
] = g_param_spec_string("sid",
269 "The unique session ID of the Jingle Session.",
271 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
273 properties
[PROP_JS
] = g_param_spec_pointer("js",
275 "The Jabber stream associated with this session.",
276 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
278 properties
[PROP_REMOTE_JID
] = g_param_spec_string("remote-jid",
280 "The JID of the remote participant.",
282 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
284 properties
[PROP_LOCAL_JID
] = g_param_spec_string("local-jid",
286 "The JID of the local participant.",
288 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
290 properties
[PROP_IS_INITIATOR
] = g_param_spec_boolean("is-initiator",
292 "Whether or not the local JID is the initiator of the session.",
294 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
296 properties
[PROP_STATE
] = g_param_spec_boolean("state",
298 "The state of the session (PENDING=FALSE, ACTIVE=TRUE).",
300 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
302 properties
[PROP_CONTENTS
] = g_param_spec_pointer("contents",
304 "The active contents contained within this session",
305 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
307 properties
[PROP_PENDING_CONTENTS
] = g_param_spec_pointer("pending-contents",
309 "The pending contents contained within this session",
310 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
312 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
315 /******************************************************************************
317 *****************************************************************************/
319 jingle_session_register(PurplePlugin
*plugin
) {
320 jingle_session_register_type(G_TYPE_MODULE(plugin
));
324 jingle_session_create(JabberStream
*js
, const gchar
*sid
,
325 const gchar
*local_jid
, const gchar
*remote_jid
,
326 gboolean is_initiator
)
328 JingleSession
*session
= g_object_new(jingle_session_get_type(),
331 "local-jid", local_jid
,
332 "remote-jid", remote_jid
,
333 "is_initiator", is_initiator
,
336 /* insert it into the hash table */
338 purple_debug_info("jingle",
339 "Creating hash table for sessions\n");
340 js
->sessions
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
342 purple_debug_info("jingle",
343 "inserting session with key: %s into table\n", sid
);
344 g_hash_table_insert(js
->sessions
, g_strdup(sid
), session
);
350 jingle_session_get_js(JingleSession
*session
)
353 g_object_get(session
, "js", &js
, NULL
);
358 jingle_session_get_sid(JingleSession
*session
)
361 g_object_get(session
, "sid", &sid
, NULL
);
366 jingle_session_get_local_jid(JingleSession
*session
)
369 g_object_get(session
, "local-jid", &local_jid
, NULL
);
374 jingle_session_get_remote_jid(JingleSession
*session
)
377 g_object_get(session
, "remote-jid", &remote_jid
, NULL
);
382 jingle_session_is_initiator(JingleSession
*session
)
384 gboolean is_initiator
;
385 g_object_get(session
, "is-initiator", &is_initiator
, NULL
);
390 jingle_session_get_state(JingleSession
*session
)
393 g_object_get(session
, "state", &state
, NULL
);
398 jingle_session_get_contents(JingleSession
*session
)
401 g_object_get(session
, "contents", &contents
, NULL
);
406 jingle_session_get_pending_contents(JingleSession
*session
)
408 GList
*pending_contents
;
409 g_object_get(session
, "pending-contents", &pending_contents
, NULL
);
410 return pending_contents
;
414 jingle_session_find_by_sid(JabberStream
*js
, const gchar
*sid
)
416 JingleSession
*session
= NULL
;
419 session
= g_hash_table_lookup(js
->sessions
, sid
);
421 purple_debug_info("jingle", "find_by_id %s\n", sid
);
422 purple_debug_info("jingle", "lookup: %p\n", session
);
428 jingle_session_find_by_jid(JabberStream
*js
, const gchar
*jid
)
430 return js
->sessions
!= NULL
?
431 g_hash_table_find(js
->sessions
,
432 find_by_jid_ghr
, (gpointer
)jid
) : NULL
;
436 jingle_session_create_ack(JingleSession
*session
, const PurpleXmlNode
*jingle
)
438 JabberIq
*result
= jabber_iq_new(
439 jingle_session_get_js(session
),
441 PurpleXmlNode
*packet
= purple_xmlnode_get_parent(jingle
);
442 jabber_iq_set_id(result
, purple_xmlnode_get_attrib(packet
, "id"));
443 purple_xmlnode_set_attrib(result
->node
, "from", purple_xmlnode_get_attrib(packet
, "to"));
444 purple_xmlnode_set_attrib(result
->node
, "to", purple_xmlnode_get_attrib(packet
, "from"));
449 jingle_session_to_xml(JingleSession
*session
, PurpleXmlNode
*jingle
, JingleActionType action
)
451 if (action
!= JINGLE_SESSION_INFO
&& action
!= JINGLE_SESSION_TERMINATE
) {
453 if (action
== JINGLE_CONTENT_ACCEPT
454 || action
== JINGLE_CONTENT_ADD
455 || action
== JINGLE_CONTENT_REMOVE
)
456 iter
= jingle_session_get_pending_contents(session
);
458 iter
= jingle_session_get_contents(session
);
460 for (; iter
; iter
= g_list_next(iter
)) {
461 jingle_content_to_xml(iter
->data
, jingle
, action
);
468 jingle_session_to_packet(JingleSession
*session
, JingleActionType action
)
470 JabberIq
*iq
= jingle_create_iq(session
);
471 PurpleXmlNode
*jingle
= jingle_add_jingle_packet(session
, iq
, action
);
472 jingle_session_to_xml(session
, jingle
, action
);
476 void jingle_session_handle_action(JingleSession
*session
, PurpleXmlNode
*jingle
, JingleActionType action
)
479 if (action
== JINGLE_CONTENT_ADD
|| action
== JINGLE_CONTENT_REMOVE
)
480 iter
= jingle_session_get_pending_contents(session
);
482 iter
= jingle_session_get_contents(session
);
484 for (; iter
; iter
= g_list_next(iter
)) {
485 jingle_content_handle_action(iter
->data
, jingle
, action
);
490 jingle_session_find_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
492 JingleSessionPrivate
*priv
= NULL
;
495 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
500 priv
= jingle_session_get_instance_private(session
);
502 iter
= priv
->contents
;
503 for (; iter
; iter
= g_list_next(iter
)) {
504 JingleContent
*content
= iter
->data
;
505 gchar
*cname
= jingle_content_get_name(content
);
506 gboolean result
= purple_strequal(name
, cname
);
509 if (creator
!= NULL
) {
510 gchar
*ccreator
= jingle_content_get_creator(content
);
511 result
= (result
&& purple_strequal(creator
, ccreator
));
522 jingle_session_find_pending_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
524 JingleSessionPrivate
*priv
= NULL
;
527 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
532 priv
= jingle_session_get_instance_private(session
);
534 iter
= priv
->pending_contents
;
535 for (; iter
; iter
= g_list_next(iter
)) {
536 JingleContent
*content
= iter
->data
;
537 gchar
*cname
= jingle_content_get_name(content
);
538 gboolean result
= purple_strequal(name
, cname
);
541 if (creator
!= NULL
) {
542 gchar
*ccreator
= jingle_content_get_creator(content
);
543 result
= (result
&& purple_strequal(creator
, ccreator
));
554 jingle_session_add_content(JingleSession
*session
, JingleContent
* content
)
556 JingleSessionPrivate
*priv
= NULL
;
558 g_return_if_fail(JINGLE_IS_SESSION(session
));
560 priv
= jingle_session_get_instance_private(session
);
562 priv
->contents
= g_list_append(priv
->contents
, content
);
563 jingle_content_set_session(content
, session
);
565 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_CONTENTS
]);
569 jingle_session_remove_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
571 JingleSessionPrivate
*priv
= NULL
;
572 JingleContent
*content
= NULL
;
574 g_return_if_fail(JINGLE_IS_SESSION(session
));
576 priv
= jingle_session_get_instance_private(session
);
577 content
= jingle_session_find_content(session
, name
, creator
);
580 priv
->contents
= g_list_remove(priv
->contents
, content
);
581 g_object_unref(content
);
583 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_CONTENTS
]);
588 jingle_session_add_pending_content(JingleSession
*session
, JingleContent
* content
)
590 JingleSessionPrivate
*priv
= NULL
;
592 g_return_if_fail(JINGLE_IS_SESSION(session
));
594 priv
= jingle_session_get_instance_private(session
);
596 priv
->pending_contents
= g_list_append(priv
->pending_contents
, content
);
597 jingle_content_set_session(content
, session
);
599 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_PENDING_CONTENTS
]);
603 jingle_session_remove_pending_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
605 JingleSessionPrivate
*priv
= NULL
;
606 JingleContent
*content
= NULL
;
608 g_return_if_fail(JINGLE_IS_SESSION(session
));
610 priv
= jingle_session_get_instance_private(session
);
611 content
= jingle_session_find_pending_content(session
, name
, creator
);
614 priv
->pending_contents
= g_list_remove(priv
->pending_contents
, content
);
615 g_object_unref(content
);
617 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_PENDING_CONTENTS
]);
622 jingle_session_accept_content(JingleSession
*session
, const gchar
*name
, const gchar
*creator
)
624 JingleContent
*content
= NULL
;
626 g_return_if_fail(JINGLE_IS_SESSION(session
));
628 content
= jingle_session_find_pending_content(session
, name
, creator
);
630 g_object_ref(content
);
631 jingle_session_remove_pending_content(session
, name
, creator
);
632 jingle_session_add_content(session
, content
);
637 jingle_session_accept_session(JingleSession
*session
)
639 JingleSessionPrivate
*priv
= NULL
;
641 g_return_if_fail(JINGLE_IS_SESSION(session
));
643 priv
= jingle_session_get_instance_private(session
);
647 g_object_notify_by_pspec(G_OBJECT(session
), properties
[PROP_STATE
]);
651 jingle_session_terminate_packet(JingleSession
*session
, const gchar
*reason
)
655 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
657 iq
= jingle_session_to_packet(session
, JINGLE_SESSION_TERMINATE
);
659 if (reason
!= NULL
) {
660 PurpleXmlNode
*reason_node
;
661 PurpleXmlNode
*jingle
= purple_xmlnode_get_child(iq
->node
, "jingle");
662 reason_node
= purple_xmlnode_new_child(jingle
, "reason");
663 purple_xmlnode_new_child(reason_node
, reason
);
670 jingle_session_redirect_packet(JingleSession
*session
, const gchar
*sid
)
673 PurpleXmlNode
*alt_session
;
675 g_return_val_if_fail(JINGLE_IS_SESSION(session
), NULL
);
677 iq
= jingle_session_terminate_packet(session
, "alternative-session");
682 alt_session
= purple_xmlnode_get_child(iq
->node
,
683 "jingle/reason/alternative-session");
685 if (alt_session
!= NULL
) {
686 PurpleXmlNode
*sid_node
= purple_xmlnode_new_child(alt_session
, "sid");
687 purple_xmlnode_insert_data(sid_node
, sid
, -1);