static void
gabble_jingle_transport_google_dispose (GObject *object)
{
  GabbleJingleTransportGoogle *trans = GABBLE_JINGLE_TRANSPORT_GOOGLE (object);
  GabbleJingleTransportGooglePrivate *priv = trans->priv;

  if (priv->dispose_has_run)
    return;

  DEBUG ("dispose called");
  priv->dispose_has_run = TRUE;

  g_hash_table_unref (priv->component_names);
  priv->component_names = NULL;

  jingle_transport_free_candidates (priv->remote_candidates);
  priv->remote_candidates = NULL;

  jingle_transport_free_candidates (priv->local_candidates);
  priv->local_candidates = NULL;

  g_free (priv->transport_ns);
  priv->transport_ns = NULL;

  if (G_OBJECT_CLASS (gabble_jingle_transport_google_parent_class)->dispose)
    G_OBJECT_CLASS (gabble_jingle_transport_google_parent_class)->dispose (object);
}
static void
wocky_jingle_transport_iceudp_dispose (GObject *object)
{
  WockyJingleTransportIceUdp *trans = WOCKY_JINGLE_TRANSPORT_ICEUDP (object);
  WockyJingleTransportIceUdpPrivate *priv = trans->priv;

  if (priv->dispose_has_run)
    return;

  DEBUG ("dispose called");
  priv->dispose_has_run = TRUE;

  jingle_transport_free_candidates (priv->remote_candidates);
  priv->remote_candidates = NULL;

  jingle_transport_free_candidates (priv->local_candidates);
  priv->local_candidates = NULL;

  g_free (priv->transport_ns);
  priv->transport_ns = NULL;

  g_free (priv->ufrag);
  priv->ufrag = NULL;

  g_free (priv->pwd);
  priv->pwd = NULL;

  if (G_OBJECT_CLASS (wocky_jingle_transport_iceudp_parent_class)->dispose)
    G_OBJECT_CLASS (wocky_jingle_transport_iceudp_parent_class)->dispose (object);
}
static void
gabble_jingle_transport_rawudp_dispose (GObject *object)
{
  GabbleJingleTransportRawUdp *trans = GABBLE_JINGLE_TRANSPORT_RAWUDP (object);
  GabbleJingleTransportRawUdpPrivate *priv = trans->priv;

  if (priv->dispose_has_run)
    return;

  DEBUG ("dispose called");
  priv->dispose_has_run = TRUE;

  jingle_transport_free_candidates (priv->remote_candidates);
  priv->remote_candidates = NULL;

  jingle_transport_free_candidates (priv->local_candidates);
  priv->local_candidates = NULL;

  g_free (priv->transport_ns);
  priv->transport_ns = NULL;

  if (G_OBJECT_CLASS (gabble_jingle_transport_rawudp_parent_class)->dispose)
    G_OBJECT_CLASS (gabble_jingle_transport_rawudp_parent_class)->dispose (object);
}
/* Takes in a list of slice-allocated JingleCandidate structs */
static void
new_local_candidates (GabbleJingleTransportIface *obj, GList *new_candidates)
{
  GabbleJingleTransportRawUdp *transport =
    GABBLE_JINGLE_TRANSPORT_RAWUDP (obj);
  GabbleJingleTransportRawUdpPrivate *priv = transport->priv;

  if (priv->local_candidates != NULL)
    {
      DEBUG ("ignoring new local candidates for RAW UDP");
      jingle_transport_free_candidates (new_candidates);
      return;
    }

  priv->local_candidates = new_candidates;
}
static void
parse_candidates (GabbleJingleTransportIface *obj,
    WockyNode *transport_node, GError **error)
{
  GabbleJingleTransportGoogle *t = GABBLE_JINGLE_TRANSPORT_GOOGLE (obj);
  GabbleJingleTransportGooglePrivate *priv = t->priv;
  GList *candidates = NULL;
  WockyNodeIter i;
  WockyNode *node;

  wocky_node_iter_init (&i, transport_node, "candidate", NULL);
  while (wocky_node_iter_next (&i, &node))
    {
      const gchar *name, *address, *user, *pass, *str;
      guint port, net, gen, component;
      int pref;
      JingleTransportProtocol proto;
      JingleCandidateType ctype;
      JingleCandidate *c;

      name = wocky_node_get_attribute (node, "name");
      if (name == NULL)
          break;

      if (!g_hash_table_lookup_extended (priv->component_names, name,
              NULL, NULL))
        {
          DEBUG ("component name %s unknown to this transport", name);
          continue;
        }

      component = GPOINTER_TO_INT (g_hash_table_lookup (priv->component_names,
              name));
      address = wocky_node_get_attribute (node, "address");
      if (address == NULL)
          break;

      str = wocky_node_get_attribute (node, "port");
      if (str == NULL)
          break;
      port = atoi (str);

      str = wocky_node_get_attribute (node, "protocol");
      if (str == NULL)
          break;

      if (!wocky_strdiff (str, "udp"))
        {
          proto = JINGLE_TRANSPORT_PROTOCOL_UDP;
        }
      else if (!wocky_strdiff (str, "tcp"))
        {
          /* candiates on port 443 must be "ssltcp" */
          if (port == 443)
              break;

          proto = JINGLE_TRANSPORT_PROTOCOL_TCP;
        }
      else if (!wocky_strdiff (str, "ssltcp"))
        {
          /* "ssltcp" must use port 443 */
          if (port != 443)
              break;

          /* we really don't care about "ssltcp" otherwise */
          proto = JINGLE_TRANSPORT_PROTOCOL_TCP;
        }
      else
        {
          /* unknown protocol */
          DEBUG ("unknown protocol: %s", str);
          break;
        }

      str = wocky_node_get_attribute (node, "preference");
      if (str == NULL)
          break;

      pref = g_ascii_strtod (str, NULL) * 65536;

      str = wocky_node_get_attribute (node, "type");
      if (str == NULL)
          break;

      if (!wocky_strdiff (str, "local"))
        {
          ctype = JINGLE_CANDIDATE_TYPE_LOCAL;
        }
      else if (!wocky_strdiff (str, "stun"))
        {
          ctype = JINGLE_CANDIDATE_TYPE_STUN;
        }
      else if (!wocky_strdiff (str, "relay"))
        {
          ctype = JINGLE_CANDIDATE_TYPE_RELAY;
        }
      else
        {
          /* unknown candidate type */
          DEBUG ("unknown candidate type: %s", str);
          break;
        }

      user = wocky_node_get_attribute (node, "username");
      if (user == NULL)
          break;

      pass = wocky_node_get_attribute (node, "password");
      if (pass == NULL)
          break;

      str = wocky_node_get_attribute (node, "network");
      if (str == NULL)
          break;
      net = atoi (str);

      str = wocky_node_get_attribute (node, "generation");
      if (str == NULL)
          break;
      gen = atoi (str);

      str = wocky_node_get_attribute (node, "component");
      if (str != NULL)
          component = atoi (str);

      c = jingle_candidate_new (proto, ctype, NULL, component,
          address, port, gen, pref, user, pass, net);

      candidates = g_list_append (candidates, c);
    }

  if (wocky_node_iter_next (&i, NULL))
    {
      DEBUG ("not all nodes were processed, reporting error");
      /* rollback these */
      jingle_transport_free_candidates (candidates);
      g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
          "invalid candidate");
      return;
    }

  DEBUG ("emitting %d new remote candidates", g_list_length (candidates));

  g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates);

  /* append them to the known remote candidates */
  priv->remote_candidates = g_list_concat (priv->remote_candidates, candidates);
}
static void
parse_candidates (GabbleJingleTransportIface *obj,
    LmMessageNode *transport_node, GError **error)
{
  GabbleJingleTransportRawUdp *t = GABBLE_JINGLE_TRANSPORT_RAWUDP (obj);
  GabbleJingleTransportRawUdpPrivate *priv = t->priv;
  GList *candidates = NULL;
  NodeIter i;

  DEBUG ("called");

  if (priv->remote_candidates != NULL)
    {
      DEBUG ("already have raw udp candidates, ignoring extra ones");
      return;
    }

  for (i = node_iter (transport_node); i; i = node_iter_next (i))
    {
      LmMessageNode *node = node_iter_data (i);
      const gchar *id, *ip, *str;
      guint port, gen, component = 1;
      JingleCandidate *c;

      if (tp_strdiff (node->name, "candidate"))
          continue;

      str = lm_message_node_get_attribute (node, "component");
      if (str != NULL)
          component = atoi (str);

      if ((component != 1) && (component != 2))
        {
          DEBUG ("Ignoring non-RTP/RTCP component %d", component);
          continue;
        }

      id = lm_message_node_get_attribute (node, "id");
      if (id == NULL)
          break;

      ip = lm_message_node_get_attribute (node, "ip");
      if (ip == NULL)
          break;

      str = lm_message_node_get_attribute (node, "port");
      if (str == NULL)
          break;
      port = atoi (str);

      str = lm_message_node_get_attribute (node, "generation");
      if (str == NULL)
          break;
      gen = atoi (str);

      c = jingle_candidate_new (JINGLE_TRANSPORT_PROTOCOL_UDP,
          JINGLE_CANDIDATE_TYPE_LOCAL, id, component, ip, port,
          gen, 1.0, NULL, NULL, 0);

      candidates = g_list_append (candidates, c);
    }

  if (i != NULL)
    {
      DEBUG ("not all nodes were processed, reporting error");
      /* rollback these */
      jingle_transport_free_candidates (candidates);
      g_set_error (error, GABBLE_XMPP_ERROR, XMPP_ERROR_BAD_REQUEST,
          "invalid candidate");
      return;
    }

  DEBUG ("emitting %d new remote candidates", g_list_length (candidates));
  g_signal_emit (obj, signals[NEW_CANDIDATES], 0, candidates);
  priv->remote_candidates = candidates;
}