void test_flickr_error (void) { RestXmlParser *parser; RestXmlNode *root; GError *error; const char test_1[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<rsp stat=\"ok\"><auth></auth></rsp>"; const char test_2[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<foobar/>"; const char test_3[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<rsp stat=\"fail\"><err code=\"108\" msg=\"Invalid frob\" /></rsp>"; parser = rest_xml_parser_new (); root = rest_xml_parser_parse_from_data (parser, test_1, sizeof (test_1) - 1); error = NULL; flickr_proxy_is_successful (root, &error); g_assert_no_error (error); rest_xml_node_unref (root); error = NULL; root = rest_xml_parser_parse_from_data (parser, test_2, sizeof (test_2) - 1); flickr_proxy_is_successful (root, &error); g_assert_error (error, FLICKR_PROXY_ERROR, 0); g_error_free (error); rest_xml_node_unref (root); error = NULL; root = rest_xml_parser_parse_from_data (parser, test_3, sizeof (test_3) - 1); flickr_proxy_is_successful (root, &error); g_assert_error (error, FLICKR_PROXY_ERROR, 108); g_error_free (error); rest_xml_node_unref (root); }
int main (int argc, char **argv) { GError *error = NULL; RestXmlParser *parser; RestXmlNode *root, *node; char *xml; g_thread_init (NULL); g_type_init (); parser = rest_xml_parser_new (); root = rest_xml_parser_parse_from_data (parser, TEST_XML, strlen (TEST_XML)); g_assert (root); xml = rest_xml_node_print (root); g_assert (xml); if (strcmp (TEST_XML, xml)) { g_error ("Generated output for parsed XML does not match:\n" "in: %s\n" "out: %s\n", TEST_XML, xml); } rest_xml_node_unref (root); root = rest_xml_node_add_child (NULL, "node0"); rest_xml_node_add_attr (root, "a00", "v00"); rest_xml_node_add_attr (root, "a01", "v01"); node = rest_xml_node_add_child (root, "node1"); rest_xml_node_add_attr (node, "a10", "v10"); node = rest_xml_node_add_child (root, "node1"); rest_xml_node_add_attr (node, "a10", "v10"); rest_xml_node_set_content (root, "Cont0"); xml = rest_xml_node_print (root); g_assert (xml); if (strcmp (TEST_XML, xml)) { g_error ("Generated output for constructed XML does not match:\n" "in: %s\n" "out: %s\n", TEST_XML, xml); } rest_xml_node_unref (root); return 0; }
static void got_user_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer userdata) { SwService *service = SW_SERVICE (weak_object); SwServiceSina *sina = SW_SERVICE_SINA (service); SwServiceSinaPrivate *priv = GET_PRIVATE (sina); RestXmlNode *root; if (error) { g_message ("Error: %s", error->message); return; } root = xml_node_from_call (call, "Sina"); if (!root) return; priv->user_id = xml_get_child_node_value (root, "id"); priv->image_url = xml_get_child_node_value (root, "profile_image_url"); rest_xml_node_unref (root); sw_service_emit_capabilities_changed (service, get_dynamic_caps (service)); }
static void verify_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer userdata) { SwService *service = SW_SERVICE (weak_object); SwServiceTwitter *twitter = SW_SERVICE_TWITTER (service); SwServiceTwitterPrivate *priv = twitter->priv; RestXmlNode *node; SW_DEBUG (TWITTER, "Verified credentials"); node = node_from_call (call); if (!node) return; priv->credentials = CREDS_VALID; priv->user_id = g_strdup (rest_xml_node_find (node, "id")->content); priv->image_url = g_strdup (rest_xml_node_find (node, "profile_image_url")->content); priv->geotag_enabled = g_str_equal (rest_xml_node_find (node, "geo_enabled")->content, "true"); rest_xml_node_unref (node); sw_service_emit_capabilities_changed (service, get_dynamic_caps (service)); g_object_unref (call); }
static void verify_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer userdata) { MojitoService *service = MOJITO_SERVICE (weak_object); MojitoServiceTwitter *twitter = MOJITO_SERVICE_TWITTER (service); RestXmlNode *node; if (error) { sanity_check_date (call); g_message ("Error: %s", error->message); return; } MOJITO_DEBUG (TWITTER, "Authentication verified"); node = node_from_call (call); if (!node) return; twitter->priv->user_id = g_strdup (rest_xml_node_find (node, "id")->content); twitter->priv->image_url = g_strdup (rest_xml_node_find (node, "profile_image_url")->content); rest_xml_node_unref (node); mojito_service_emit_capabilities_changed (service, get_dynamic_caps (service)); if (twitter->priv->running) get_status_updates (twitter); }
static void _check_access_token_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer user_data) { RestXmlNode *root; GError *err = NULL; SwServiceVimeo *self = SW_SERVICE_VIMEO (weak_object); SwService *service = SW_SERVICE (self); SwServiceVimeoPrivate *priv = self->priv; root = node_from_call (call, &err); if (root == NULL) { g_assert (err != NULL); SW_DEBUG (VIMEO, "Invalid access token: %s", err->message); g_error_free (err); } else { RestXmlNode *username = rest_xml_node_find (root, "username"); priv->username = g_strdup (username->content); rest_proxy_bind (priv->simple_proxy, priv->username); rest_xml_node_unref (root); } sw_service_emit_capabilities_changed (service, get_dynamic_caps (service)); }
static void on_upload_cb (RestProxyCall *call, gsize total, gsize uploaded, const GError *error, GObject *weak_object, gpointer user_data) { SwServiceTwitter *twitter = SW_SERVICE_TWITTER (weak_object); RestXmlNode *root; char *tweet; int opid = GPOINTER_TO_INT (user_data); gint percent; if (error) { sw_photo_upload_iface_emit_photo_upload_progress (twitter, opid, -1, error->message); return; } /* Now post to Twitter */ root = node_from_call (call); if (root == NULL || g_strcmp0 (root->name, "image") != 0) { sw_photo_upload_iface_emit_photo_upload_progress (twitter, opid, -1, "Unexpected response from Twitpic"); if (root) rest_xml_node_unref (root); return; } /* This format is for tweets announcing twitpic URLs, "[tweet] [url]". */ tweet = g_strdup_printf (_("%s %s"), rest_xml_node_find (root, "text")->content, rest_xml_node_find (root, "url")->content); call = rest_proxy_new_call (twitter->priv->proxy); rest_proxy_call_set_method (call, "POST"); rest_proxy_call_set_function (call, "1/statuses/update.xml"); rest_proxy_call_add_param (call, "status", tweet); rest_proxy_call_async (call, on_upload_tweet_cb, (GObject *)twitter, NULL, NULL); percent = (gdouble) uploaded / (gdouble) total * 100; sw_photo_upload_iface_emit_photo_upload_progress (twitter, opid, percent, ""); rest_xml_node_unref (root); g_free (tweet); }
static void _got_status_updates_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer userdata) { SwTwitterItemView *item_view = SW_TWITTER_ITEM_VIEW (weak_object); SwTwitterItemViewPrivate *priv = GET_PRIVATE (item_view); RestXmlNode *root, *node; SwSet *set; SwService *service; if (error) { g_warning (G_STRLOC ": Error getting Tweets: %s", error->message); return; } root = _make_node_from_call (call); if (!root) return; set = sw_item_set_new (); SW_DEBUG (TWITTER, "Got tweets!"); service = sw_item_view_get_service (SW_ITEM_VIEW (item_view)); for (node = rest_xml_node_find (root, "status"); node; node = node->next) { SwItem *item; item = _make_item (item_view, node); sw_item_set_service (item, service); if (item) { if (!sw_service_is_uid_banned (service, sw_item_get (item, "id"))) { sw_set_add (set, (GObject *)item); } g_object_unref (item); } } sw_item_view_set_from_set (SW_ITEM_VIEW (item_view), set); /* Save the results of this set to the cache */ sw_cache_save (service, priv->query, priv->params, set); sw_set_unref (set); rest_xml_node_unref (root); }
static RestXmlNode * node_from_call (RestProxyCall *call, GError **error) { static RestXmlParser *parser = NULL; RestXmlNode *node; if (call == NULL) return NULL; if (parser == NULL) parser = rest_xml_parser_new (); if (!SOUP_STATUS_IS_SUCCESSFUL (rest_proxy_call_get_status_code (call))) { g_set_error (error, SW_SERVICE_ERROR, SW_SERVICE_ERROR_REMOTE_ERROR, "HTTP error: %s (%d)", rest_proxy_call_get_status_message (call), rest_proxy_call_get_status_code (call)); return NULL; } node = rest_xml_parser_parse_from_data (parser, rest_proxy_call_get_payload (call), rest_proxy_call_get_payload_length (call)); /* Invalid XML, or incorrect root */ if (node == NULL || !g_str_equal (node->name, "rsp")) { g_set_error (error, SW_SERVICE_ERROR, SW_SERVICE_ERROR_REMOTE_ERROR, "malformed remote response: %s", rest_proxy_call_get_payload (call)); if (node) rest_xml_node_unref (node); return NULL; } if (g_strcmp0 (rest_xml_node_get_attr (node, "stat"), "ok") != 0) { RestXmlNode *err; err = rest_xml_node_find (node, "err"); g_set_error (error, SW_SERVICE_ERROR, SW_SERVICE_ERROR_REMOTE_ERROR, "remote Vimeo error: %s", err ? rest_xml_node_get_attr (err, "msg") : "unknown"); rest_xml_node_unref (node); return NULL; } return node; }
static RestXmlNode * node_from_call (RestProxyCall *call) { static RestXmlParser *parser = NULL; RestXmlNode *node; if (call == NULL) return NULL; if (parser == NULL) parser = rest_xml_parser_new (); if (!SOUP_STATUS_IS_SUCCESSFUL (rest_proxy_call_get_status_code (call))) { g_message (G_STRLOC ": error from Last.fm: %s (%d)", rest_proxy_call_get_status_message (call), rest_proxy_call_get_status_code (call)); return NULL; } node = rest_xml_parser_parse_from_data (parser, rest_proxy_call_get_payload (call), rest_proxy_call_get_payload_length (call)); /* No content, or wrong content */ if (node == NULL || strcmp (node->name, "lfm") != 0) { g_message (G_STRLOC ": cannot make Last.fm call"); /* TODO: display the payload if its short */ if (node) rest_xml_node_unref (node); return NULL; } if (strcmp (rest_xml_node_get_attr (node, "status"), "ok") != 0) { RestXmlNode *err_node; err_node = rest_xml_node_find (node, "error"); g_message (G_STRLOC ": cannot make Last.fm call: %s (code %s)", err_node->content, rest_xml_node_get_attr (err_node, "code")); rest_xml_node_unref (node); return NULL; } return node; }
static void _got_videos_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer user_data) { SwYoutubeItemView *item_view = SW_YOUTUBE_ITEM_VIEW (weak_object); SwYoutubeItemViewPrivate *priv = GET_PRIVATE (item_view); SwService *service; RestXmlNode *root, *node; if (error) { g_message (G_STRLOC ": error from Youtube: %s", error->message); /* TODO: cleanup or something */ return; } root = xml_node_from_call (call, "Youtube"); if (!root) return; node = rest_xml_node_find (root, "channel"); if (!node) return; /* Clean up the thumbnail mapping cache */ g_hash_table_remove_all (priv->thumb_map); service = sw_item_view_get_service (SW_ITEM_VIEW (item_view)); for (node = rest_xml_node_find (node, "item"); node; node = node->next) { SwItem *item; item = make_item (item_view, service, node); if (!sw_service_is_uid_banned (service, sw_item_get (item, "id"))) { sw_set_add (priv->set, (GObject *)item); } g_object_unref (item); } sw_item_view_set_from_set ((SwItemView *)item_view, priv->set); /* Save the results of this set to the cache */ sw_cache_save (service, priv->query, priv->params, priv->set); sw_set_empty (priv->set); rest_xml_node_unref (root); }
static void _got_videos_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer user_data) { SwVimeoItemView *item_view = SW_VIMEO_ITEM_VIEW (weak_object); SwVimeoItemViewPrivate *priv = GET_PRIVATE (item_view); SwService *service; RestXmlNode *root, *video_n; sw_call_list_remove (priv->calls, call); if (error) { g_message (G_STRLOC ": error from Vimeo: %s", error->message); /* TODO: cleanup or something */ return; } SW_DEBUG (VIMEO, "Got videos"); root = node_from_call (call); if (!root) return; SW_DEBUG (VIMEO, "Parsed videos"); service = sw_item_view_get_service (SW_ITEM_VIEW (item_view)); for (video_n = rest_xml_node_find (root, "video"); video_n; video_n = video_n->next) { SwItem *item; /* Vimeo is stupid and returns an empty <video> element if there are no videos, so check for this and skip it */ if (rest_xml_node_find (video_n, "url") == NULL) continue; item = make_item (item_view, service, video_n); if (!sw_service_is_uid_banned (service, sw_item_get (item, "id"))) { sw_set_add (priv->set, (GObject *)item); } g_object_unref (item); } rest_xml_node_unref (root); _update_if_done (item_view); }
static gchar * _construct_upload_atom_xml (GHashTable *fields, gboolean incomplete) { GHashTableIter iter; gpointer key, value; RestXmlNode *entry = rest_xml_node_add_child (NULL, "entry"); RestXmlNode *group = rest_xml_node_add_child (entry, "media:group"); gchar *bare_xml; gchar *full_xml; rest_xml_node_add_attr (entry, "xmlns", "http://www.w3.org/2005/Atom"); rest_xml_node_add_attr (entry, "xmlns:media", "http://search.yahoo.com/mrss/"); rest_xml_node_add_attr (entry, "xmlns:yt", "http://gdata.youtube.com/schemas/2007"); if (incomplete) rest_xml_node_add_child (group, "yt:incomplete"); g_hash_table_iter_init (&iter, fields); while (g_hash_table_iter_next (&iter, &key, &value)) { RestXmlNode *node; gchar *tag_name; const gchar* field_value = value; const gchar* field_key = key; tag_name = g_strdup_printf ("media:%s", field_key); node = rest_xml_node_add_child (group, tag_name); if (g_strcmp0 (field_key, "title") == 0 || g_strcmp0 (field_key, "description") == 0) rest_xml_node_add_attr (node, "type", "plain"); if (g_strcmp0 (field_key, "category") == 0) rest_xml_node_add_attr (node, "scheme", "http://gdata.youtube.com/" "schemas/2007/categories.cat"); rest_xml_node_set_content (node, field_value); } bare_xml = rest_xml_node_print (entry); full_xml = g_strdup_printf ("<?xml version=\"1.0\"?>\n%s", bare_xml); rest_xml_node_unref (entry); g_free (bare_xml); return full_xml; }
static RestXmlNode * xml_node_from_call (RestProxyCall *call, const char *name) { static RestXmlParser *parser = NULL; RestXmlNode *root; if (call == NULL) return NULL; if (parser == NULL) parser = rest_xml_parser_new (); if (!SOUP_STATUS_IS_SUCCESSFUL (rest_proxy_call_get_status_code (call))) { g_message ("Error from %s: %s (%d)", name, rest_proxy_call_get_status_message (call), rest_proxy_call_get_status_code (call)); return NULL; } root = rest_xml_parser_parse_from_data (parser, rest_proxy_call_get_payload (call), rest_proxy_call_get_payload_length (call)); if (root == NULL) { g_message ("Error from %s: %s", name, rest_proxy_call_get_payload (call)); return NULL; } /* Exception handling */ if (strcmp (name, "Youtube") == 0) { if (strcmp (root->name, "error_response") == 0) { RestXmlNode *node; node = rest_xml_node_find (root, "error_msg"); g_message ("Error response from Youtube: %s\n", node->content); rest_xml_node_unref (root); return NULL; } } return root; }
/** * ovirt_collection_fetch: * @collection: a #OvirtCollection * @proxy: a #OvirtProxy * @error: #GError to set on error, or NULL */ gboolean ovirt_collection_fetch(OvirtCollection *collection, OvirtProxy *proxy, GError **error) { RestXmlNode *xml; g_return_val_if_fail(OVIRT_IS_COLLECTION(collection), FALSE); g_return_val_if_fail(OVIRT_IS_PROXY(proxy), FALSE); g_return_val_if_fail(collection->priv->href != NULL, FALSE); xml = ovirt_proxy_get_collection_xml(proxy, collection->priv->href, NULL); if (xml == NULL) return FALSE; ovirt_collection_refresh_from_xml(collection, xml, error); rest_xml_node_unref(xml); return TRUE; }
static void _mobile_session_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer userdata) { const gchar *status; SwService *service = SW_SERVICE (weak_object); SwServiceLastfm *lastfm = SW_SERVICE_LASTFM (service); SwServiceLastfmPrivate *priv = lastfm->priv; RestXmlNode *node; priv->checked_with_server = TRUE; if (error) { g_message ("Error: %s", error->message); g_object_unref (call); sw_service_emit_capabilities_changed (service, get_dynamic_caps (service)); return; } node = node_from_call (call); if (!node) return; status = g_hash_table_lookup (node->attrs, "status"); if (g_strcmp0 (status, "ok") == 0) { RestXmlNode *session_key = rest_xml_node_find (node, "key"); if (session_key) { g_free (priv->session_key); priv->session_key = g_strdup (session_key->content); } } rest_xml_node_unref (node); g_object_unref (call); sw_service_emit_capabilities_changed (service, get_dynamic_caps (service)); }
/** * rest_xml_node_unref: (skip) * @node: a #RestXmlNode * * Decreases the reference count of @node. When its reference count drops to 0, * the node is finalized (i.e. its memory is freed). */ void rest_xml_node_unref (RestXmlNode *node) { GList *l; RestXmlNode *next = NULL; g_return_if_fail (node); g_return_if_fail (node->ref_count > 0); /* Try and unref the chain, this is equivalent to being tail recursively * unreffing the next pointer */ while (node && g_atomic_int_dec_and_test (&node->ref_count)) { /* * Save this pointer now since we are going to free the structure it * contains soon. */ next = node->next; l = g_hash_table_get_values (node->children); while (l) { rest_xml_node_unref ((RestXmlNode *)l->data); l = g_list_delete_link (l, l); } g_hash_table_unref (node->children); g_hash_table_unref (node->attrs); g_free (node->content); g_slice_free (RestXmlNode, node); /* * Free the next in the chain by updating node. If we're at the end or * there are no siblings then the next = NULL definition deals with this * case */ node = next; } }
static void tweets_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer userdata) { MojitoServiceTwitter *service = MOJITO_SERVICE_TWITTER (weak_object); RestXmlNode *root, *node; MojitoSet *set; if (error) { g_message ("Error: %s", error->message); return; } root = node_from_call (call); if (!root) return; set = mojito_item_set_new (); MOJITO_DEBUG (TWITTER, "Got tweets!"); for (node = rest_xml_node_find (root, "status"); node; node = node->next) { MojitoItem *item; /* TODO: skip the user's own tweets */ item = make_item (service, node); if (item) mojito_set_add (set, (GObject *)item); } mojito_service_emit_refreshed ((MojitoService *)service, set); /* TODO cleanup */ rest_xml_node_unref (root); }
static void _get_friends_cb (RestProxyCall *call, const GError *error, GObject *weak_object, gpointer user_data) { SwLastfmContactView *contact_view = SW_LASTFM_CONTACT_VIEW (weak_object); SwLastfmContactViewPrivate *priv = GET_PRIVATE (weak_object); gboolean updated = FALSE; RestXmlNode *root, *node; sw_call_list_remove (priv->calls, call); if (error) { g_message (G_STRLOC ": error from Last.fm: %s", error->message); g_object_unref (call); return; } SW_DEBUG (LASTFM, "Got result of getFriends call"); root = node_from_call (call); g_object_unref (call); if (!root) return; SW_DEBUG (LASTFM, "Parsed results of getFriends call"); for (node = rest_xml_node_find (root, "user"); node; node = node->next) { SwContact *contact; SwService *service; const gchar *id; const gchar *realname; const gchar *url; service = sw_contact_view_get_service (SW_CONTACT_VIEW (contact_view)); contact = sw_contact_new (); sw_contact_set_service (contact, service); id = rest_xml_node_find (node, "name")->content; realname = rest_xml_node_find (node, "realname")->content; url = rest_xml_node_find (node, "url")->content; if (!id) { g_object_unref (contact); continue; } sw_contact_put (contact, "id", id); if (!realname) realname = id; sw_contact_put (contact, "name", realname); if (url) sw_contact_put (contact, "url", url); if (!sw_service_is_uid_banned (service, sw_contact_get (contact, "id"))) { sw_set_add (priv->set, (GObject *)contact); updated = TRUE; } /* No date, so use now at the timestamp */ sw_contact_take (contact, "date", sw_time_t_to_string (time (NULL))); g_object_unref (contact); } rest_xml_node_unref (root); if (updated) _update_if_done (contact_view); }
static void mex_suggest_complete_cb (MexDownloadQueue *queue, const gchar *uri, const gchar *buffer, gsize count, const GError *error, gpointer userdata) { RestXmlNode *root, *n; RestXmlParser *parser; MexSearchPlugin *self = userdata; MexSearchPluginPrivate *priv = self->priv; priv->suggest_id = NULL; /* hide spinner */ mx_spinner_set_animating (MX_SPINNER (priv->spinner), FALSE); clutter_actor_hide (priv->spinner); if (error) { g_warning ("Error querying Google suggestions: %s", error->message); return; } parser = rest_xml_parser_new (); root = rest_xml_parser_parse_from_data (parser, buffer, count); if (!root) { g_warning ("Unknown error parsing Google suggestions XML"); g_object_unref (parser); return; } /* Clear model */ mex_model_clear (MEX_MODEL (priv->suggest_model)); /* Add new suggestions to model */ n = rest_xml_node_find (root, "CompleteSuggestion"); for (; n; n = n->next) { MexContent *content; const gchar *suggestion; RestXmlNode *node = rest_xml_node_find (n, "suggestion"); if (!node) continue; suggestion = rest_xml_node_get_attr (node, "data"); if (!suggestion) continue; content = MEX_CONTENT (mex_program_new (priv->suggest_model)); mex_content_set_metadata (content, MEX_CONTENT_METADATA_TITLE, suggestion); mex_content_set_metadata (content, MEX_CONTENT_METADATA_MIMETYPE, "x-mex/search"); mex_model_add_content (MEX_MODEL (priv->suggest_model), content); } /* Unref */ rest_xml_node_unref (root); g_object_unref (parser); }