static GPtrArray *
get_data_forms (WockyNode *node)
{
  GPtrArray *out = g_ptr_array_new_with_free_func (g_object_unref);

  WockyNodeIter iter;
  WockyNode *x_node = NULL;

  wocky_node_iter_init (&iter, node, "x", WOCKY_XMPP_NS_DATA);
  while (wocky_node_iter_next (&iter, &x_node))
    {
      WockyDataForm *form  = wocky_data_form_new_from_node (x_node, NULL);

      /* we've already parsed the reply to check the hash matches, so
       * we can already guarantee these data forms will be parsed
       * fine */
      if (G_LIKELY (form != NULL))
        g_ptr_array_add (out, form);
   }

  return out;
}
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 gboolean
update_location_from_item (
    GabbleConnection *conn,
    TpHandle contact,
    WockyNode *item_node)
{
  WockyNode *node;
  GHashTable *location = g_hash_table_new_full (g_direct_hash, g_direct_equal,
      g_free, (GDestroyNotify) tp_g_value_slice_free);
  TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
      (TpBaseConnection *) conn, TP_HANDLE_TYPE_CONTACT);
  const gchar *from = tp_handle_inspect (contact_repo, contact);
  WockyNodeIter i;
  WockyNode *subloc_node;
  const gchar *lang;

  if (item_node == NULL)
    return FALSE;

  node = wocky_node_get_child_ns (item_node, "geoloc", NS_GEOLOC);
  if (node == NULL)
    return FALSE;

  DEBUG ("LocationsUpdate for %s:", from);

  lang = wocky_node_get_language (node);
  if (lang != NULL)
    {
      g_hash_table_insert (location, g_strdup ("language"),
          tp_g_value_slice_new_string (lang));
    }

  build_mapping_tables ();

  wocky_node_iter_init (&i, node, NULL, NULL);
  while (wocky_node_iter_next (&i, &subloc_node))
    {
      GValue *value = NULL;
      gchar *xmpp_name;
      const gchar *str;
      LocationMapping *mapping;

      xmpp_name = subloc_node->name;
      str = subloc_node->content;
      if (str == NULL)
        continue;

      mapping = g_hash_table_lookup (xmpp_to_tp, xmpp_name);
      if (mapping == NULL)
        {
          DEBUG ("Unknown location attribute: %s\n", xmpp_name);
          continue;
        }

      if (mapping->type == G_TYPE_DOUBLE)
        {
          gdouble double_value;
          gchar *end;

          double_value = g_ascii_strtod (str, &end);

          if (end == str)
            continue;

          value = tp_g_value_slice_new_double (double_value);
          DEBUG ("\t - %s: %f", xmpp_name, double_value);
        }
      else if (strcmp (xmpp_name, "timestamp") == 0)
        {
          GTimeVal timeval;
          if (g_time_val_from_iso8601 (str, &timeval))
            {
              value = tp_g_value_slice_new_int64 (timeval.tv_sec);
              DEBUG ("\t - %s: %s", xmpp_name, str);
            }
          else
            {
              DEBUG ("\t - %s: %s: unknown date format", xmpp_name, str);
              continue;
            }
        }
      else if (mapping->type == G_TYPE_STRING)
        {
          value = tp_g_value_slice_new_string (str);
          DEBUG ("\t - %s: %s", xmpp_name, str);
        }
      else
        {
          g_assert_not_reached ();
        }

      g_hash_table_insert (location, g_strdup (mapping->tp_name), value);
    }

  tp_svc_connection_interface_location_emit_location_updated (conn,
      contact, location);
  gabble_presence_cache_update_location (conn->presence_cache, contact,
      location);

  return TRUE;
}
static void
parse_description (WockyJingleContent *content,
    WockyNode *desc_node, GError **error)
{
  GabbleJingleShare *self = GABBLE_JINGLE_SHARE (content);
  GabbleJingleSharePrivate *priv = self->priv;
  WockyNodeIter i;
  WockyNode *manifest_node = NULL;
  WockyNode *protocol_node = NULL;
  WockyNode *http_node = NULL;
  WockyNode *node;

  DEBUG ("parse description called");

  if (priv->manifest != NULL)
    {
      DEBUG ("Not parsing description, we already have a manifest");
      return;
    }

  manifest_node = wocky_node_get_child (desc_node, "manifest");

  if (manifest_node == NULL)
    {
      g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
          "description missing <manifest/> node");
      return;
    }

  protocol_node = wocky_node_get_child (desc_node, "protocol");
  if (protocol_node != NULL)
    http_node = wocky_node_get_child (protocol_node, "http");

  free_manifest (self);
  priv->manifest = g_slice_new0 (GabbleJingleShareManifest);

  /* Build the manifest */
  wocky_node_iter_init (&i, manifest_node, NULL, NULL);
  while (wocky_node_iter_next (&i, &node))
    {
      WockyNode *name = NULL;
      WockyNode *image = NULL;
      gboolean folder;
      const gchar *size;
      GabbleJingleShareManifestEntry *m = NULL;

      if (!wocky_strdiff (node->name, "folder"))
        folder = TRUE;
      else if (!wocky_strdiff (node->name, "file"))
        folder = FALSE;
      else
        continue;

      name = wocky_node_get_child (node, "name");
      if (name == NULL)
        continue;

      m = g_slice_new0 (GabbleJingleShareManifestEntry);
      m->folder = folder;
      m->name = g_strdup (name->content);

      size = wocky_node_get_attribute (node, "size");
      if (size)
        m->size = g_ascii_strtoull (size, NULL, 10);

      image = wocky_node_get_child (node, "image");
      if (image)
        {
          const gchar *width;
          const gchar *height;

          m->image = TRUE;

          width = wocky_node_get_attribute (image, "width");
          if (width)
            m->image_width = g_ascii_strtoull (width, NULL, 10);

          height =wocky_node_get_attribute (image, "height");
          if (height)
            m->image_height = g_ascii_strtoull (height, NULL, 10);
        }
      priv->manifest->entries = g_list_prepend (priv->manifest->entries, m);
    }

  /* Get the source and preview url paths from the protocol/http node */
  if (http_node != NULL)
    {
      /* clear the previously set values */
      wocky_node_iter_init (&i, http_node, "url", NULL);
      while (wocky_node_iter_next (&i, &node))
        {
          const gchar *name = wocky_node_get_attribute (node, "name");
          if (name == NULL)
            continue;

          if (!wocky_strdiff (name, "source-path"))
            {
              const gchar *url = node->content;
              priv->manifest->source_url = g_strdup (url);
            }

          if (!wocky_strdiff (name, "preview-path"))
            {
              const gchar *url = node->content;
              priv->manifest->preview_url = g_strdup (url);
            }
        }
    }

  /* Build the filename/filesize property values based on the new manifest */
  g_free (priv->filename);
  priv->filename = NULL;
  priv->filesize = 0;

  if (g_list_length (priv->manifest->entries) > 0)
    {
      if (g_list_length (priv->manifest->entries) == 1)
        {
          GabbleJingleShareManifestEntry *m = priv->manifest->entries->data;

          if (m->folder)
            priv->filename = g_strdup_printf ("%s.tar", m->name);
          else
            priv->filename = g_strdup (m->name);

          priv->filesize = m->size;
        }
      else
        {
          GList *li;
          gchar *temp;

          priv->filename = g_strdup ("");
          for (li = priv->manifest->entries; li; li = li->next)
            {
              GabbleJingleShareManifestEntry *m = li->data;

              temp = priv->filename;
              priv->filename = g_strdup_printf ("%s%s%s%s",  temp, m->name,
                  m->folder? ".tar":"", li->next == NULL? "": "-");
              g_free (temp);

              priv->filesize += m->size;
            }
          temp = priv->filename;
          priv->filename = g_strdup_printf ("%s.tar", temp);
          g_free (temp);
        }
    }
  _wocky_jingle_content_set_media_ready (content);
}
static void
parse_candidates (WockyJingleTransportIface *obj,
    WockyNode *transport_node, GError **error)
{
  WockyJingleTransportIceUdp *t = WOCKY_JINGLE_TRANSPORT_ICEUDP (obj);
  WockyJingleTransportIceUdpPrivate *priv = t->priv;
  gboolean node_contains_a_candidate = FALSE;
  GList *candidates = NULL;
  WockyNodeIter i;
  WockyNode *node;

  DEBUG ("called");

  wocky_node_iter_init (&i, transport_node, "candidate", NULL);
  while (wocky_node_iter_next (&i, &node))
    {
      const gchar *id, *address, *user, *pass, *str;
      guint port, net, gen, component = 1;
      gdouble pref;
      WockyJingleTransportProtocol proto;
      WockyJingleCandidateType ctype;
      WockyJingleCandidate *c;

      node_contains_a_candidate = TRUE;

      id = wocky_node_get_attribute (node, "foundation");
      if (id == NULL)
        {
          DEBUG ("candidate doesn't contain foundation");
          continue;
        }

      address = wocky_node_get_attribute (node, "ip");
      if (address == NULL)
        {
          DEBUG ("candidate doesn't contain ip");
          continue;
        }

      str = wocky_node_get_attribute (node, "port");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain port");
          continue;
        }
      port = atoi (str);

      str = wocky_node_get_attribute (node, "protocol");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain protocol");
          continue;
        }

      if (!wocky_strdiff (str, "udp"))
        {
          proto = WOCKY_JINGLE_TRANSPORT_PROTOCOL_UDP;
        }
      else
        {
          /* unknown protocol */
          DEBUG ("unknown protocol: %s", str);
          continue;
        }

      str = wocky_node_get_attribute (node, "priority");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain priority");
          continue;
        }
      pref = g_ascii_strtod (str, NULL);

      str = wocky_node_get_attribute (node, "type");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain type");
          continue;
        }

      if (!wocky_strdiff (str, "host"))
        {
          ctype = WOCKY_JINGLE_CANDIDATE_TYPE_LOCAL;
        }
      else if (!wocky_strdiff (str, "srflx") || !wocky_strdiff (str, "prflx"))
        {
          /* FIXME Strictly speaking a prflx candidate should be a different
           * type, but the TP spec has now way to distinguish and it doesn't
           * matter much anyway.. */
          ctype = WOCKY_JINGLE_CANDIDATE_TYPE_STUN;
        }
      else if (!wocky_strdiff (str, "relay"))
        {
          ctype = WOCKY_JINGLE_CANDIDATE_TYPE_RELAY;
        }
      else
        {
          /* unknown candidate type */
          DEBUG ("unknown candidate type: %s", str);
          continue;
        }

      user = wocky_node_get_attribute (transport_node, "ufrag");
      if (user == NULL)
        {
          DEBUG ("transport doesn't contain ufrag");
          continue;
        }

      pass = wocky_node_get_attribute (transport_node, "pwd");
      if (pass == NULL)
        {
          DEBUG ("transport doesn't contain pwd");
          continue;
        }

      str = wocky_node_get_attribute (node, "network");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain network");
          continue;
        }
      net = atoi (str);

      str = wocky_node_get_attribute (node, "generation");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain generation");
          continue;
        }
      gen = atoi (str);

      str = wocky_node_get_attribute (node, "component");
      if (str == NULL)
        {
          DEBUG ("candidate doesn't contain component");
          continue;
        }
      component = atoi (str);

      if (priv->ufrag == NULL || strcmp (priv->ufrag, user))
        {
          g_free (priv->ufrag);
          priv->ufrag = g_strdup (user);
        }

      if (priv->pwd == NULL || strcmp (priv->pwd, pass))
        {
          g_free (priv->pwd);
          priv->pwd = g_strdup (pass);
        }

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

      candidates = g_list_append (candidates, c);
    }

  if (candidates == NULL)
    {
      if (node_contains_a_candidate)
        {
          DEBUG_NODE (transport_node,
              "couldn't parse any of the given candidates");
          g_set_error (error, WOCKY_XMPP_ERROR, WOCKY_XMPP_ERROR_BAD_REQUEST,
              "could not parse any of the given candidates");
        }
      else
        {
          DEBUG ("no candidates in this stanza");
        }
    }
  else
    {
      DEBUG ("emitting %d new remote candidates", g_list_length (candidates));

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

      priv->remote_candidates = g_list_concat (priv->remote_candidates,
          candidates);
    }
}