[Telepathy-commits] [telepathy-sofiasip/master] Implemented media Channel properties InitiatorID, InitiatorHandle, Requested

Mikhail Zabaluev mikhail.zabaluev at nokia.com
Wed Oct 15 08:50:02 PDT 2008


The "creator" GObject property of TpsipMediaChannel backing InitiatorHandle
is also used to clarify the internal logic.
---
 src/media-factory.c     |   34 +++++---
 src/media-factory.h     |   13 +--
 src/sip-connection.c    |    7 +-
 src/sip-media-channel.c |  221 ++++++++++++++++++++++++++++++-----------------
 src/sip-media-channel.h |    5 +-
 5 files changed, 176 insertions(+), 104 deletions(-)

diff --git a/src/media-factory.c b/src/media-factory.c
index 488cce6..ca01b3a 100644
--- a/src/media-factory.c
+++ b/src/media-factory.c
@@ -270,6 +270,7 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
                                  gpointer request,
                                  TpHandleType handle_type,
                                  TpHandle handle,
+                                 TpHandle creator,
                                  GError **error)
 {
   TpsipMediaFactoryPrivate *priv;
@@ -279,6 +280,7 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
   const gchar *nat_traversal = "none";
 
   g_assert (TPSIP_IS_MEDIA_FACTORY (fac));
+  g_assert (creator != 0);
 
   priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
   conn = (TpBaseConnection *)priv->conn;
@@ -296,6 +298,7 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
   chan = g_object_new (TPSIP_TYPE_MEDIA_CHANNEL,
                        "connection", priv->conn,
                        "object-path", object_path,
+                       "creator", creator,
                        "nat-traversal", nat_traversal,
                        NULL);
 
@@ -308,10 +311,13 @@ tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
         g_object_set ((GObject *) chan, "stun-port", priv->stun_port, NULL);
     }
 
-  if (handle_type == TP_HANDLE_TYPE_CONTACT)
+  if (handle_type == TP_HANDLE_TYPE_CONTACT && handle != creator)
     {
       GArray *contacts;
       gboolean added;
+
+      g_assert (creator == conn->self_handle);
+
       contacts = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), 1);
       g_array_append_val (contacts, handle);
       added = tp_group_mixin_add_members (G_OBJECT (chan),
@@ -338,16 +344,18 @@ err:
 
 static TpChannelFactoryRequestStatus
 tpsip_media_factory_request (TpChannelFactoryIface *iface,
-                          const gchar *chan_type,
-                          TpHandleType handle_type,
-                          TpHandle handle,
-                          gpointer request,
-                          TpChannelIface **ret,
-                          GError **error_ret)
+                             const gchar *chan_type,
+                             TpHandleType handle_type,
+                             TpHandle handle,
+                             gpointer request,
+                             TpChannelIface **ret,
+                             GError **error_ret)
 {
   TpsipMediaFactory *fac = TPSIP_MEDIA_FACTORY (iface);
+  TpsipMediaFactoryPrivate *priv;
   TpChannelIface *chan;
   TpChannelFactoryRequestStatus status = TP_CHANNEL_FACTORY_REQUEST_STATUS_ERROR;
+  TpBaseConnection *base_conn;
   GError *error = NULL;
 
   if (strcmp (chan_type, TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA))
@@ -355,11 +363,15 @@ tpsip_media_factory_request (TpChannelFactoryIface *iface,
       return TP_CHANNEL_FACTORY_REQUEST_STATUS_NOT_IMPLEMENTED;
     }
 
+  priv = TPSIP_MEDIA_FACTORY_GET_PRIVATE (fac);
+  base_conn = (TpBaseConnection *)priv->conn;
+
   chan = (TpChannelIface *) tpsip_media_factory_new_channel (fac,
-                                                           request,
-                                                           handle_type,
-                                                           handle,
-                                                           &error);
+                                                             request,
+                                                             handle_type,
+                                                             handle,
+                                                             base_conn->self_handle,
+                                                             &error);
   if (chan != NULL)
     {
       *ret = chan;
diff --git a/src/media-factory.h b/src/media-factory.h
index 95e0005..b670659 100644
--- a/src/media-factory.h
+++ b/src/media-factory.h
@@ -54,15 +54,12 @@ GType tpsip_media_factory_get_type(void);
 #define TPSIP_MEDIA_FACTORY_GET_CLASS(obj) \
   (G_TYPE_INSTANCE_GET_CLASS ((obj), TPSIP_TYPE_MEDIA_FACTORY, TpsipMediaFactoryClass))
 
-/***********************************************************************
- * Functions for managing media session IDs (sids) 
- ***********************************************************************/
-
 TpsipMediaChannel *tpsip_media_factory_new_channel (TpsipMediaFactory *fac,
-                                                gpointer request,
-                                                TpHandleType handle_type,
-                                                TpHandle handle,
-                                                GError **error);
+                                                    gpointer request,
+                                                    TpHandleType handle_type,
+                                                    TpHandle handle,
+                                                    TpHandle creator,
+                                                    GError **error);
 
 G_END_DECLS
 
diff --git a/src/sip-connection.c b/src/sip-connection.c
index e95d0a2..e8afb6a 100644
--- a/src/sip-connection.c
+++ b/src/sip-connection.c
@@ -808,12 +808,13 @@ tpsip_connection_nua_i_invite_cb (TpsipConnection   *self,
   channel = tpsip_media_factory_new_channel (
                 TPSIP_MEDIA_FACTORY (priv->media_factory),
                 NULL,
-                TP_HANDLE_TYPE_NONE,
-                0,
+                TP_HANDLE_TYPE_CONTACT,
+                handle,
+                handle,
                 &error);
   if (channel)
     {
-      tpsip_media_channel_receive_invite (channel, ev->nua_handle, handle);
+      tpsip_media_channel_receive_invite (channel, ev->nua_handle);
     }
   else
     {
diff --git a/src/sip-media-channel.c b/src/sip-media-channel.c
index 523d243..b03a7da 100644
--- a/src/sip-media-channel.c
+++ b/src/sip-media-channel.c
@@ -94,6 +94,9 @@ enum
   PROP_HANDLE_TYPE,
   PROP_HANDLE,
   PROP_TARGET_ID,
+  PROP_CREATOR,
+  PROP_CREATOR_ID,
+  PROP_REQUESTED,
   PROP_INTERFACES,
   /* Telepathy properties (see below too) */
   PROP_NAT_TRAVERSAL,
@@ -123,12 +126,14 @@ typedef struct _TpsipMediaChannelPrivate TpsipMediaChannelPrivate;
 
 struct _TpsipMediaChannelPrivate
 {
-  gboolean dispose_has_run;
-  gboolean closed;
   TpsipConnection *conn;
   TpsipMediaSession *session;
   gchar *object_path;
+  TpHandle creator;
   GHashTable *call_states;
+
+  gboolean closed;
+  gboolean dispose_has_run;
 };
 
 #define TPSIP_MEDIA_CHANNEL_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), TPSIP_TYPE_MEDIA_CHANNEL, TpsipMediaChannelPrivate))
@@ -161,6 +166,7 @@ tpsip_media_channel_constructed (GObject *obj)
       G_OBJECT_CLASS (tpsip_media_channel_parent_class);
   DBusGConnection *bus;
   TpHandleRepoIface *contact_repo;
+  TpIntSet *set;
 
   if (parent_object_class->constructed != NULL)
     parent_object_class->constructed (obj);
@@ -180,6 +186,18 @@ tpsip_media_channel_constructed (GObject *obj)
                        contact_repo,
                        conn->self_handle);
 
+  /* automatically add creator to channel, but also ref them again (because
+   * priv->creator is the InitiatorHandle) */
+  g_assert (priv->creator != 0);
+  tp_handle_ref (contact_repo, priv->creator);
+
+  set = tp_intset_new ();
+  tp_intset_add (set, priv->creator);
+
+  tp_group_mixin_change_members (obj, "", set, NULL, NULL, NULL, 0, 0);
+
+  tp_intset_destroy (set);
+
   /* Allow member adding; also, we implement the 0.17.6 properties */
   tp_group_mixin_change_flags (obj,
       TP_CHANNEL_GROUP_FLAG_CAN_ADD | TP_CHANNEL_GROUP_FLAG_PROPERTIES, 0);
@@ -219,11 +237,14 @@ static void
 tpsip_media_channel_class_init (TpsipMediaChannelClass *klass)
 {
   static const TpDBusPropertiesMixinPropImpl channel_props[] = {
+      { "ChannelType", "channel-type", NULL },
+      { "Interfaces", "interfaces", NULL },
       { "TargetHandleType", "handle-type", NULL },
       { "TargetHandle", "handle", NULL },
       { "TargetID", "target-id", NULL },
-      { "ChannelType", "channel-type", NULL },
-      { "Interfaces", "interfaces", NULL },
+      { "InitiatorHandle", "creator", NULL },
+      { "InitiatorID", "creator-id", NULL },
+      { "Requested", "requested", NULL },
       { NULL }
   };
   static const TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
@@ -290,6 +311,24 @@ tpsip_media_channel_class_init (TpsipMediaChannelClass *klass)
       G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
   g_object_class_install_property (object_class, PROP_TARGET_ID, param_spec);
 
+  param_spec = g_param_spec_uint ("creator", "Channel creator",
+      "The TpHandle representing the contact who created the channel.",
+      0, G_MAXUINT32, 0,
+      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_CREATOR, param_spec);
+
+  param_spec = g_param_spec_string ("creator-id", "Creator URI",
+      "The URI obtained by inspecting the creator handle.",
+      NULL,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_CREATOR_ID, param_spec);
+
+  param_spec = g_param_spec_boolean ("requested", "Requested?",
+      "True if this channel was requested by the local user",
+      FALSE,
+      G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+  g_object_class_install_property (object_class, PROP_REQUESTED, param_spec);
+
   tp_properties_mixin_class_init (object_class,
       G_STRUCT_OFFSET (TpsipMediaChannelClass, properties_class),
       media_channel_property_signatures, NUM_TP_PROPS, NULL);
@@ -317,6 +356,7 @@ tpsip_media_channel_get_property (GObject    *object,
 {
   TpsipMediaChannel *chan = TPSIP_MEDIA_CHANNEL (object);
   TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (chan);
+  TpBaseConnection *base_conn = TP_BASE_CONNECTION (priv->conn);
 
   switch (property_id) {
     case PROP_CONNECTION:
@@ -337,6 +377,20 @@ tpsip_media_channel_get_property (GObject    *object,
     case PROP_TARGET_ID:
       g_value_set_static_string (value, "");
       break;
+    case PROP_CREATOR:
+      g_value_set_uint (value, priv->creator);
+      break;
+    case PROP_CREATOR_ID:
+        {
+          TpHandleRepoIface *repo = tp_base_connection_get_handles (
+              base_conn, TP_HANDLE_TYPE_CONTACT);
+
+          g_value_set_string (value, tp_handle_inspect (repo, priv->creator));
+        }
+      break;
+    case PROP_REQUESTED:
+      g_value_set_boolean (value, (priv->creator == base_conn->self_handle));
+      break;
     case PROP_INTERFACES:
       g_value_set_static_boxed (value, tpsip_media_channel_interfaces);
       break;
@@ -390,6 +444,9 @@ tpsip_media_channel_set_property (GObject     *object,
       g_free (priv->object_path);
       priv->object_path = g_value_dup_string (value);
       break;
+    case PROP_CREATOR:
+      priv->creator = g_value_get_uint (value);
+      break;
     default:
       /* some properties live in the mixin */
       {
@@ -417,6 +474,7 @@ tpsip_media_channel_dispose (GObject *object)
 {
   TpsipMediaChannel *self = TPSIP_MEDIA_CHANNEL (object);
   TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self);
+  TpHandleRepoIface *contact_handles;
 
   if (priv->dispose_has_run)
     return;
@@ -430,8 +488,13 @@ tpsip_media_channel_dispose (GObject *object)
   if (!priv->closed)
     tpsip_media_channel_close (self);
 
-  if (priv->conn)
-    g_object_unref (priv->conn);
+  contact_handles = tp_base_connection_get_handles (
+      TP_BASE_CONNECTION (priv->conn), TP_HANDLE_TYPE_CONTACT);
+
+  tp_handle_unref (contact_handles, priv->creator);
+  priv->creator = 0;
+
+  g_object_unref (priv->conn);
 
   if (G_OBJECT_CLASS (tpsip_media_channel_parent_class)->dispose)
     G_OBJECT_CLASS (tpsip_media_channel_parent_class)->dispose (object);
@@ -787,60 +850,50 @@ tpsip_media_channel_request_streams (TpSvcChannelTypeStreamedMedia *iface,
 
 /**
  * Handle an incoming INVITE, normally called just after the channel
- * has been created.
+ * has been created with initiator handle of the sender.
  */
 void
 tpsip_media_channel_receive_invite (TpsipMediaChannel *self, 
-                                  nua_handle_t *nh,
-                                  TpHandle handle)
+                                    nua_handle_t *nh)
 {
   TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self);
   TpBaseConnection *conn = TP_BASE_CONNECTION (priv->conn);
-  GObject *obj = G_OBJECT (self);
   TpHandleRepoIface *contact_repo;
-  TpIntSet *member_set, *pending_set;
- 
+  TpIntSet *pending_set;
+
+  g_assert (priv->creator != conn->self_handle);
+
   contact_repo = tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT);
 
   if (priv->session == NULL)
     {
       /* note: start the local stream-engine; once the local 
        *       media are ready, reply with nua_respond() */
-      priv_create_session (self, nh, handle);
+      priv_create_session (self, nh, priv->creator);
       g_assert (priv->session != NULL);
       tpsip_media_session_receive_invite (priv->session);
     }
   else
+    /* FIXME: This shall really be an assertion */
     g_warning ("session already exists");
 
-  /* XXX: should be attached more data than just the handle? 
-   * - yes, we need to be able to access all the <op,handle> pairs */
-
-  DEBUG("adding handle %d (%s)", 
-        handle,
-        tp_handle_inspect (contact_repo, handle));
-
-  /* add the peer to channel members and self_handle to local pending */
-
-  member_set = tp_intset_new ();
-  tp_intset_add (member_set, handle);
+  /* add self_handle to local pending */
 
   pending_set = tp_intset_new ();
   tp_intset_add (pending_set, conn->self_handle);
 
-  tp_group_mixin_change_members (obj, "INVITE received",
-                                 member_set,    /* add */
+  tp_group_mixin_change_members ((GObject *) self, "INVITE received",
+                                 NULL,          /* add */
                                  NULL,          /* remove */
                                  pending_set,   /* local pending */
                                  NULL,          /* remote pending */
-                                 handle,        /* actor */
+                                 priv->creator, /* actor */
                                  TP_CHANNEL_GROUP_CHANGE_REASON_INVITED);
 
-  tp_intset_destroy (member_set);
   tp_intset_destroy (pending_set);
 
   /* No adding more members to the incoming call, removing is OK */
-  tp_group_mixin_change_flags (obj,
+  tp_group_mixin_change_flags ((GObject *) self,
                                TP_CHANNEL_GROUP_FLAG_CAN_REMOVE,
                                TP_CHANNEL_GROUP_FLAG_CAN_ADD);
 }
@@ -1102,10 +1155,10 @@ static void priv_session_state_changed_cb (TpsipMediaSession *session,
                                            guint state,
 					   TpsipMediaChannel *channel)
 {
+  TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (channel);
   TpGroupMixin *mixin = TP_GROUP_MIXIN (channel);
   TpHandle peer;
   TpIntSet *set = NULL;
-  TpIntSet *rset;
 
   DEBUG("enter");
 
@@ -1115,21 +1168,19 @@ static void priv_session_state_changed_cb (TpsipMediaSession *session,
     {
     case TPSIP_MEDIA_SESSION_STATE_INVITE_SENT:
       set = tp_intset_new ();
-      rset = tp_intset_new ();
 
-      /* add the peer to remote pending, make sure the self handle is
-       * in the member list */
-      tp_intset_add (set, mixin->self_handle);
-      tp_intset_add (rset, peer);
+      g_assert (priv->creator == mixin->self_handle);
+
+      /* add the peer to remote pending */
+      tp_intset_add (set, peer);
       tp_group_mixin_change_members ((GObject *)channel,
                                      "INVITE sent",
-                                     set,     /* add */
+                                     NULL,    /* add */
                                      NULL,    /* remove */
                                      NULL,    /* local pending */
-                                     rset,    /* remote pending */
+                                     set,     /* remote pending */
                                      mixin->self_handle,        /* actor */
                                      TP_CHANNEL_GROUP_CHANGE_REASON_INVITED);
-      tp_intset_destroy (rset);
 
       /* update flags: allow adding, removal and rescinding */
       tp_group_mixin_change_flags ((GObject *)channel,
@@ -1140,23 +1191,26 @@ static void priv_session_state_changed_cb (TpsipMediaSession *session,
 
       break;
     case TPSIP_MEDIA_SESSION_STATE_ACTIVE:
-      set = tp_intset_new ();
-
-      /* add the peer to the member list */
-      tp_intset_add (set, peer);
-      tp_group_mixin_change_members ((GObject *)channel,
-                                     "Call active",
-                                     set,     /* add */
-                                     NULL,    /* remove */
-                                     NULL,
-                                     NULL,
-                                     0, 0);
-
-      /* update flags: allow removal, deny adding and rescinding */
-      tp_group_mixin_change_flags ((GObject *)channel,
-                                   TP_CHANNEL_GROUP_FLAG_CAN_REMOVE,
-                                   TP_CHANNEL_GROUP_FLAG_CAN_ADD
-                                        | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND);
+      if (priv->creator == mixin->self_handle)
+        {
+          /* add the peer to the member list */
+          set = tp_intset_new ();
+
+          tp_intset_add (set, peer);
+          tp_group_mixin_change_members ((GObject *)channel,
+                                         "Call active",
+                                         set,     /* add */
+                                         NULL,    /* remove */
+                                         NULL,
+                                         NULL,
+                                         0, 0);
+
+          /* update flags: allow removal, deny adding and rescinding */
+          tp_group_mixin_change_flags ((GObject *)channel,
+              TP_CHANNEL_GROUP_FLAG_CAN_REMOVE,
+              TP_CHANNEL_GROUP_FLAG_CAN_ADD
+              | TP_CHANNEL_GROUP_FLAG_CAN_RESCIND);
+        }
       break;
     case TPSIP_MEDIA_SESSION_STATE_ENDED:
       set = tp_intset_new ();
@@ -1327,9 +1381,9 @@ priv_outbound_call (TpsipMediaChannel *channel,
 
 static gboolean
 tpsip_media_channel_add_member (GObject *iface,
-                              TpHandle handle,
-                              const gchar *message,
-                              GError **error)
+                                TpHandle handle,
+                                const gchar *message,
+                                GError **error)
 {
   TpsipMediaChannel *self = TPSIP_MEDIA_CHANNEL (iface);
   TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self);
@@ -1337,26 +1391,23 @@ tpsip_media_channel_add_member (GObject *iface,
 
   DEBUG("mixin->self_handle=%d, handle=%d", mixin->self_handle, handle);
 
-  /* case a: outgoing call (we are the initiator, a new handle added) */
-  if (mixin->self_handle != handle)
+  if (priv->creator == mixin->self_handle)
     {
-      TpIntSet *lset, *rset;
+      /* case a: outgoing call (we are the initiator, a new handle added) */
+      TpIntSet *set;
 
       priv_outbound_call (self, handle);
 
       /* make remote pending */
-      rset = tp_intset_new ();
-      lset = tp_intset_new ();
-      tp_intset_add (lset, mixin->self_handle);
-      tp_intset_add (rset, handle);
+      set = tp_intset_new ();
+      tp_intset_add (set, handle);
       tp_group_mixin_change_members (iface, "Sending INVITE",
-                                     lset,      /* add */
+                                     NULL,      /* add */
                                      NULL,      /* remove */
                                      NULL,      /* local pending */
-                                     rset,      /* remote pending */
-                                     0, 0);
-      tp_intset_destroy (lset);
-      tp_intset_destroy (rset);
+                                     set,       /* remote pending */
+                                     mixin->self_handle, 0);
+      tp_intset_destroy (set);
 
       /* and update flags accordingly */
       tp_group_mixin_change_flags (iface,
@@ -1366,9 +1417,11 @@ tpsip_media_channel_add_member (GObject *iface,
 
       return TRUE;
     }
-  /* case b: an incoming invite */
-  if (tp_handle_set_is_member (mixin->local_pending, handle))
+  if (priv->session &&
+      handle == mixin->self_handle &&
+      tp_handle_set_is_member (mixin->local_pending, handle))
     {
+      /* case b: an incoming invite */
       TpIntSet *set;
 
       DEBUG("accepting an incoming invite");
@@ -1390,11 +1443,10 @@ tpsip_media_channel_add_member (GObject *iface,
       return TRUE;
     }
 
-  /* This can only legitimately happen if the user is trying to call themselves */
   g_message ("unsupported member change requested for a media channel");
 
-  g_set_error (error, TP_ERRORS, TP_ERROR_INVALID_ARGUMENT,
-               "Can't call yourself");
+  g_set_error (error, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+      "handle %u cannot be added in the current state", handle);
   return FALSE;
 }
 
@@ -1422,17 +1474,28 @@ tpsip_status_from_tp_reason (TpChannelGroupChangeReason reason)
 
 static gboolean
 tpsip_media_channel_remove_with_reason (GObject *obj,
-                                      TpHandle handle,
-                                      const gchar *message,
-                                      guint reason,
-                                      GError **error)
+                                        TpHandle handle,
+                                        const gchar *message,
+                                        guint reason,
+                                        GError **error)
 {
   TpsipMediaChannel *self = TPSIP_MEDIA_CHANNEL (obj);
   TpsipMediaChannelPrivate *priv = TPSIP_MEDIA_CHANNEL_GET_PRIVATE (self);
   TpGroupMixin *mixin = TP_GROUP_MIXIN (obj);
 
+  if (priv->creator != mixin->self_handle &&
+      handle != mixin->self_handle)
+    {
+      g_set_error (error, TP_ERRORS, TP_ERROR_PERMISSION_DENIED,
+          "handle %u cannot be removed because you are not the creator of the"
+          " channel", handle);
+
+      return FALSE;
+    }
+
   /* We handle only one case: removal of the self handle from local pending
    * due to the user rejecting the call */
+  /* FIXME: handle also rescinding and removal of self from members */
   if (priv->session &&
       handle == mixin->self_handle &&
       tp_handle_set_is_member (mixin->local_pending, handle))
diff --git a/src/sip-media-channel.h b/src/sip-media-channel.h
index 807d75a..221d973 100644
--- a/src/sip-media-channel.h
+++ b/src/sip-media-channel.h
@@ -72,9 +72,8 @@ void tpsip_media_channel_close (TpsipMediaChannel *self);
  * Additional declarations (not based on generated templates)
  ***********************************************************************/
 
-void tpsip_media_channel_receive_invite   (TpsipMediaChannel *self,
-                                           nua_handle_t *nh,
-                                           TpHandle handle);
+void tpsip_media_channel_receive_invite (TpsipMediaChannel *self,
+                                         nua_handle_t *nh);
 
 guint
 tpsip_media_channel_change_call_state (TpsipMediaChannel *self,
-- 
1.5.6.5




More information about the Telepathy-commits mailing list