summaryrefslogtreecommitdiff
path: root/src/jingle-session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jingle-session.c')
-rw-r--r--src/jingle-session.c244
1 files changed, 116 insertions, 128 deletions
diff --git a/src/jingle-session.c b/src/jingle-session.c
index 97e81aaa3..b4701fccc 100644
--- a/src/jingle-session.c
+++ b/src/jingle-session.c
@@ -26,6 +26,7 @@
#include <loudmouth/loudmouth.h>
#include <telepathy-glib/handle-repo-dynamic.h>
+#include <wocky/wocky-utils.h>
#define DEBUG_FLAG GABBLE_DEBUG_MEDIA
@@ -34,6 +35,7 @@
#include "conn-presence.h"
#include "debug.h"
#include "gabble-signals-marshal.h"
+#include "gabble-enumtypes.h"
#include "jingle-content.h"
#include "jingle-factory.h"
/* FIXME: the RTP-specific bits of this file should be separated from the
@@ -52,6 +54,7 @@ enum
NEW_CONTENT,
REMOTE_STATE_CHANGED,
TERMINATED,
+ CONTENT_REJECTED,
LAST_SIGNAL
};
@@ -479,12 +482,45 @@ gabble_jingle_session_class_init (GabbleJingleSessionClass *cls)
G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST,
0, NULL, NULL, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ signals[CONTENT_REJECTED] = g_signal_new ("content-rejected",
+ G_TYPE_FROM_CLASS (cls), G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL, gabble_marshal_VOID__OBJECT_UINT_STRING,
+ G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_UINT, G_TYPE_STRING);
}
typedef void (*HandlerFunc)(GabbleJingleSession *sess,
- LmMessageNode *node, GError **error);
+ LmMessageNode *node, GError **error);
typedef void (*ContentHandlerFunc)(GabbleJingleSession *sess,
- GabbleJingleContent *c, LmMessageNode *content_node, GError **error);
+ GabbleJingleContent *c, LmMessageNode *content_node, gpointer user_data,
+ GError **error);
+
+static gboolean
+extract_reason (WockyNode *node, JingleReason *reason, gchar **message)
+{
+ JingleReason _reason = JINGLE_REASON_UNKNOWN;
+ WockyNode *child;
+ WockyNodeIter iter;
+
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ if (message != NULL)
+ *message = g_strdup (wocky_node_get_content_from_child (node, "text"));
+
+ wocky_node_iter_init (&iter, node, NULL, NULL);
+
+ while (wocky_node_iter_next (&iter, &child))
+ {
+ if (wocky_enum_from_nick (
+ jingle_reason_get_type (), child->name, (gint *) &_reason))
+ {
+ if (reason != NULL)
+ *reason = _reason;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
static JingleAction
parse_action (const gchar *txt)
@@ -592,9 +628,7 @@ action_is_allowed (JingleAction action, JingleState state)
static void gabble_jingle_session_send_rtp_info (GabbleJingleSession *sess,
const gchar *name);
static void set_state (GabbleJingleSession *sess,
- JingleState state,
- TpChannelGroupChangeReason termination_reason,
- const gchar *text);
+ JingleState state, JingleReason termination_reason, const gchar *text);
static GabbleJingleContent *_get_any_content (GabbleJingleSession *session);
static gboolean
@@ -682,6 +716,7 @@ _foreach_content (GabbleJingleSession *sess,
LmMessageNode *node,
gboolean fail_if_missing,
ContentHandlerFunc func,
+ gpointer user_data,
GError **error)
{
GabbleJingleContent *c;
@@ -700,7 +735,7 @@ _foreach_content (GabbleJingleSession *sess,
fail_if_missing, &c, error))
return;
- func (sess, c, content_node, error);
+ func (sess, c, content_node, user_data, error);
if (*error != NULL)
return;
}
@@ -829,7 +864,7 @@ create_content (GabbleJingleSession *sess, GType content_type,
static void
_each_content_add (GabbleJingleSession *sess, GabbleJingleContent *c,
- LmMessageNode *content_node, GError **error)
+ LmMessageNode *content_node, gpointer user_data, GError **error)
{
GabbleJingleSessionPrivate *priv = sess->priv;
const gchar *name = lm_message_node_get_attribute (content_node, "name");
@@ -873,7 +908,7 @@ _each_content_add (GabbleJingleSession *sess, GabbleJingleContent *c,
static void
_each_content_remove (GabbleJingleSession *sess, GabbleJingleContent *c,
- LmMessageNode *content_node, GError **error)
+ LmMessageNode *content_node, gpointer user_data, GError **error)
{
g_assert (c != NULL);
@@ -881,8 +916,20 @@ _each_content_remove (GabbleJingleSession *sess, GabbleJingleContent *c,
}
static void
+_each_content_rejected (GabbleJingleSession *sess, GabbleJingleContent *c,
+ LmMessageNode *content_node, gpointer user_data, GError **error)
+{
+ JingleReason reason = GPOINTER_TO_UINT (user_data);
+ g_assert (c != NULL);
+
+ g_signal_emit (sess, signals[CONTENT_REJECTED], 0, c, reason, "");
+
+ gabble_jingle_content_remove (c, FALSE);
+}
+
+static void
_each_content_modify (GabbleJingleSession *sess, GabbleJingleContent *c,
- LmMessageNode *content_node, GError **error)
+ LmMessageNode *content_node, gpointer user_data, GError **error)
{
g_assert (c != NULL);
@@ -894,19 +941,19 @@ _each_content_modify (GabbleJingleSession *sess, GabbleJingleContent *c,
static void
_each_content_replace (GabbleJingleSession *sess, GabbleJingleContent *c,
- LmMessageNode *content_node, GError **error)
+ LmMessageNode *content_node, gpointer user_data, GError **error)
{
- _each_content_remove (sess, c, content_node, error);
+ _each_content_remove (sess, c, content_node, NULL, error);
if (*error != NULL)
return;
- _each_content_add (sess, c, content_node, error);
+ _each_content_add (sess, c, content_node, NULL, error);
}
static void
_each_content_accept (GabbleJingleSession *sess, GabbleJingleContent *c,
- LmMessageNode *content_node ,GError **error)
+ LmMessageNode *content_node, gpointer user_data, GError **error)
{
GabbleJingleSessionPrivate *priv = sess->priv;
JingleContentState state;
@@ -929,7 +976,7 @@ _each_content_accept (GabbleJingleSession *sess, GabbleJingleContent *c,
static void
_each_description_info (GabbleJingleSession *sess, GabbleJingleContent *c,
- LmMessageNode *content_node, GError **error)
+ LmMessageNode *content_node, gpointer user_data, GError **error)
{
gabble_jingle_content_parse_description_info (c, content_node, error);
}
@@ -945,8 +992,7 @@ on_session_initiate (GabbleJingleSession *sess, LmMessageNode *node,
{
/* We ignore initiate from us, and terminate the session immediately
* afterwards */
- gabble_jingle_session_terminate (sess,
- TP_CHANNEL_GROUP_CHANGE_REASON_BUSY, NULL, NULL);
+ gabble_jingle_session_terminate (sess, JINGLE_REASON_BUSY, NULL, NULL);
return;
}
@@ -976,17 +1022,17 @@ on_session_initiate (GabbleJingleSession *sess, LmMessageNode *node,
}
else
{
- _each_content_add (sess, NULL, node, error);
+ _each_content_add (sess, NULL, node, NULL, error);
}
}
else if (priv->dialect == JINGLE_DIALECT_GTALK4)
{
/* in this case we implicitly have just one content */
- _each_content_add (sess, NULL, node, error);
+ _each_content_add (sess, NULL, node, NULL, error);
}
else
{
- _foreach_content (sess, node, FALSE, _each_content_add, error);
+ _foreach_content (sess, node, FALSE, _each_content_add, NULL, error);
}
if (*error == NULL)
@@ -995,7 +1041,8 @@ on_session_initiate (GabbleJingleSession *sess, LmMessageNode *node,
* disposition; resolve this as soon as the proper procedure is defined
* in XEP-0166. */
- set_state (sess, JINGLE_STATE_PENDING_INITIATED, 0, NULL);
+ set_state (sess, JINGLE_STATE_PENDING_INITIATED, JINGLE_REASON_UNKNOWN,
+ NULL);
gabble_jingle_session_send_rtp_info (sess, "ringing");
}
@@ -1005,45 +1052,54 @@ static void
on_content_add (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- _foreach_content (sess, node, FALSE, _each_content_add, error);
+ _foreach_content (sess, node, FALSE, _each_content_add, NULL, error);
}
static void
on_content_modify (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- _foreach_content (sess, node, TRUE, _each_content_modify, error);
+ _foreach_content (sess, node, TRUE, _each_content_modify, NULL, error);
}
static void
on_content_remove (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- _foreach_content (sess, node, TRUE, _each_content_remove, error);
+ _foreach_content (sess, node, TRUE, _each_content_remove, NULL, error);
}
static void
on_content_replace (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- _foreach_content (sess, node, TRUE, _each_content_replace, error);
+ _foreach_content (sess, node, TRUE, _each_content_replace, NULL, error);
}
static void
on_content_reject (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- /* FIXME: reject is different from remove - remove is for
- * acknowledged contents, reject is for pending; but the result
- * is the same. */
- _foreach_content (sess, node, TRUE, _each_content_remove, error);
+ LmMessageNode *n = lm_message_node_get_child (node, "reason");
+ JingleReason reason = JINGLE_REASON_UNKNOWN;
+
+ DEBUG (" ");
+
+ if (n != NULL)
+ extract_reason (n, &reason, NULL);
+
+ if (reason == JINGLE_REASON_UNKNOWN)
+ reason = JINGLE_REASON_GENERAL_ERROR;
+
+ _foreach_content (sess, node, TRUE, _each_content_rejected,
+ GUINT_TO_POINTER (reason), error);
}
static void
on_content_accept (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- _foreach_content (sess, node, TRUE, _each_content_accept, error);
+ _foreach_content (sess, node, TRUE, _each_content_accept, NULL, error);
}
static void
@@ -1066,19 +1122,19 @@ on_session_accept (GabbleJingleSession *sess, LmMessageNode *node,
GList *l;
for (l = cs; l != NULL; l = l->next)
- _each_content_accept (sess, l->data, node, error);
+ _each_content_accept (sess, l->data, node, NULL, error);
g_list_free (cs);
}
else
{
- _foreach_content (sess, node, TRUE, _each_content_accept, error);
+ _foreach_content (sess, node, TRUE, _each_content_accept, NULL, error);
}
if (*error != NULL)
return;
- set_state (sess, JINGLE_STATE_ACTIVE, 0, NULL);
+ set_state (sess, JINGLE_STATE_ACTIVE, JINGLE_REASON_UNKNOWN, NULL);
if (priv->dialect != JINGLE_DIALECT_V032)
{
@@ -1259,76 +1315,24 @@ on_session_info (GabbleJingleSession *sess,
"no recognized session-info payloads");
}
-typedef struct {
- const gchar *element;
- TpChannelGroupChangeReason reason;
-} ReasonMapping;
-
-/* Taken from the schema in XEP 0166 */
-ReasonMapping reasons[] = {
- { "alternative-session", TP_CHANNEL_GROUP_CHANGE_REASON_NONE },
- { "busy", TP_CHANNEL_GROUP_CHANGE_REASON_BUSY },
- { "cancel", TP_CHANNEL_GROUP_CHANGE_REASON_NONE },
- { "connectivity-error", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "decline", TP_CHANNEL_GROUP_CHANGE_REASON_NONE },
- { "expired", TP_CHANNEL_GROUP_CHANGE_REASON_NONE },
- { "failed-application", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "failed-transport", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "general-error", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "gone", TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE },
- { "incompatible-parameters", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "media-error", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "security-error", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "success", TP_CHANNEL_GROUP_CHANGE_REASON_NONE },
- { "timeout", TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER },
- { "unsupported-applications", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { "unsupported-transports", TP_CHANNEL_GROUP_CHANGE_REASON_ERROR },
- { NULL, }
-};
-
static void
on_session_terminate (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- TpChannelGroupChangeReason reason = TP_CHANNEL_GROUP_CHANGE_REASON_NONE;
- const gchar *text = NULL;
+ gchar *text = NULL;
LmMessageNode *n = lm_message_node_get_child (node, "reason");
- ReasonMapping *m = NULL;
- NodeIter i;
+ JingleReason jingle_reason = JINGLE_REASON_UNKNOWN;
- /* If the session-terminate stanza has a <reason> child, then iterate across
- * its children, looking for a child whose name we recognise as a
- * machine-readable reason for the call ending (looked up from the table
- * above), and a <text> node containing a human-readable message.
- */
if (n != NULL)
- for (i = node_iter (n); i; i = node_iter_next (i))
- {
- const gchar *name;
+ extract_reason (n, &jingle_reason, &text);
- n = node_iter_data (i);
-
- name = lm_message_node_get_name (n);
+ DEBUG ("remote end terminated the session with reason %s and text '%s'",
+ gabble_jingle_session_get_reason_name (jingle_reason),
+ (text != NULL ? text : "(none)"));
- if (!tp_strdiff (name, "text"))
- {
- text = lm_message_node_get_value (n);
- continue;
- }
+ set_state (sess, JINGLE_STATE_ENDED, jingle_reason, text);
- for (m = reasons; m->element != NULL; m++)
- if (!tp_strdiff (m->element, name))
- {
- reason = m->reason;
- break;
- }
- }
-
- DEBUG ("remote end terminated the session with reason %s (%u) "
- "and text '%s'",
- (m != NULL && m->element != NULL ? m->element : "(none)"), reason,
- (text != NULL ? text : "(none)"));
- set_state (sess, JINGLE_STATE_ENDED, reason, text);
+ g_free (text);
}
static void
@@ -1409,7 +1413,7 @@ static void
on_description_info (GabbleJingleSession *sess, LmMessageNode *node,
GError **error)
{
- _foreach_content (sess, node, TRUE, _each_description_info, error);
+ _foreach_content (sess, node, TRUE, _each_description_info, NULL, error);
}
static void
@@ -1816,7 +1820,7 @@ _on_initiate_reply (GObject *sess_as_obj,
}
else
{
- set_state (sess, JINGLE_STATE_ENDED, TP_CHANNEL_GROUP_CHANGE_REASON_NONE,
+ set_state (sess, JINGLE_STATE_ENDED, JINGLE_REASON_UNKNOWN,
NULL);
}
}
@@ -1835,7 +1839,7 @@ _on_accept_reply (GObject *sess_as_obj,
}
else
{
- set_state (sess, JINGLE_STATE_ENDED, TP_CHANNEL_GROUP_CHANGE_REASON_NONE,
+ set_state (sess, JINGLE_STATE_ENDED, JINGLE_REASON_UNKNOWN,
NULL);
}
}
@@ -1966,14 +1970,14 @@ try_session_initiate_or_accept (GabbleJingleSession *sess)
* @sess: a jingle session
* @state: the new state for the session
* @termination_reason: if @state is JINGLE_STATE_ENDED, the reason the session
- * ended. Otherwise, must be 0.
+ * ended. Otherwise, must be JINGLE_REASON_UNKNOWN.
* @text: if @state is JINGLE_STATE_ENDED, the human-readable reason the session
* ended.
*/
static void
set_state (GabbleJingleSession *sess,
JingleState state,
- TpChannelGroupChangeReason termination_reason,
+ JingleReason termination_reason,
const gchar *text)
{
GabbleJingleSessionPrivate *priv = sess->priv;
@@ -1985,7 +1989,7 @@ set_state (GabbleJingleSession *sess,
}
if (state != JINGLE_STATE_ENDED)
- g_assert (termination_reason == 0);
+ g_assert (termination_reason == JINGLE_REASON_UNKNOWN);
DEBUG ("Setting state of JingleSession: %p (priv = %p) from %u to %u", sess, priv, priv->state, state);
@@ -2013,33 +2017,20 @@ gabble_jingle_session_accept (GabbleJingleSession *sess)
try_session_initiate_or_accept (sess);
}
-static const gchar *
-_get_jingle_reason (GabbleJingleSession *sess,
- TpChannelGroupChangeReason reason)
+const gchar *
+gabble_jingle_session_get_reason_name (JingleReason reason)
{
- switch (reason)
- {
- case TP_CHANNEL_GROUP_CHANGE_REASON_NONE:
- if (sess->priv->state == JINGLE_STATE_ACTIVE)
- return "success";
- else
- return "cancel";
- case TP_CHANNEL_GROUP_CHANGE_REASON_OFFLINE:
- return "gone";
- case TP_CHANNEL_GROUP_CHANGE_REASON_BUSY:
- return "busy";
- case TP_CHANNEL_GROUP_CHANGE_REASON_ERROR:
- return "general-error";
- case TP_CHANNEL_GROUP_CHANGE_REASON_NO_ANSWER:
- return "timeout";
- default:
- return NULL;
- }
+ GEnumClass *klass = g_type_class_ref (jingle_reason_get_type ());
+ GEnumValue *enum_value = g_enum_get_value (klass, (gint) reason);
+
+ g_return_val_if_fail (enum_value != NULL, NULL);
+
+ return enum_value->value_nick;
}
gboolean
gabble_jingle_session_terminate (GabbleJingleSession *sess,
- TpChannelGroupChangeReason reason,
+ JingleReason reason,
const gchar *text,
GError **error)
{
@@ -2052,14 +2043,11 @@ gabble_jingle_session_terminate (GabbleJingleSession *sess,
return TRUE;
}
- reason_elt = _get_jingle_reason (sess, reason);
+ if (reason == JINGLE_REASON_UNKNOWN)
+ reason = (priv->state == JINGLE_STATE_ACTIVE) ?
+ JINGLE_REASON_SUCCESS : JINGLE_REASON_CANCEL;
- if (reason_elt == NULL)
- {
- g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
- "%u doesn't make sense as a reason to end a call", reason);
- return FALSE;
- }
+ reason_elt = gabble_jingle_session_get_reason_name (reason);
if (priv->state != JINGLE_STATE_PENDING_CREATED)
{
@@ -2139,7 +2127,7 @@ content_removed_cb (GabbleJingleContent *c, gpointer user_data)
if (count_active_contents (sess) == 0)
{
gabble_jingle_session_terminate (sess,
- TP_CHANNEL_GROUP_CHANGE_REASON_NONE, NULL, NULL);
+ JINGLE_REASON_UNKNOWN, NULL, NULL);
}
else
{