static void ttrss_feed_subscription_process_update_result (subscriptionPtr subscription, const struct updateResult* const result, updateFlags flags) { if (result->data && result->httpstatus == 200) { JsonParser *parser = json_parser_new (); if (json_parser_load_from_data (parser, result->data, -1, NULL)) { JsonArray *array = json_node_get_array (json_get_node (json_parser_get_root (parser), "content")); GList *elements = json_array_get_elements (array); GList *iter = elements; GList *items = NULL; /* We expect to get something like this [{"id":118, "unread":true, "marked":false, "updated":1287927675, "is_updated":false, "title":"IBM Says New ...", "link":"http:\/\/rss.slashdot.org\/~r\/Slashdot\/slashdot\/~3\/ALuhNKO3NV4\/story01.htm", "feed_id":"5", "content":"coondoggie writes ..." }, {"id":117, "unread":true, "marked":false, "updated":1287923814, [...] */ while (iter) { JsonNode *node = (JsonNode *)iter->data; itemPtr item = item_new (); gchar *id; const gchar *content; gchar *xhtml; id = g_strdup_printf ("%" G_GINT64_FORMAT, json_get_int (node, "id")); item_set_id (item, id); g_free (id); item_set_title (item, json_get_string (node, "title")); item_set_source (item, json_get_string (node, "link")); content = json_get_string (node, "content"); xhtml = xhtml_extract_from_string (content, NULL); item_set_description (item, xhtml); xmlFree (xhtml); item->time = json_get_int (node, "updated"); if (json_get_bool (node, "unread")) { item->readStatus = FALSE; } else { item->readStatus = TRUE; } if (json_get_bool (node, "marked")) item->flagStatus = TRUE; items = g_list_append (items, (gpointer)item); iter = g_list_next (iter); } g_list_free (elements); /* merge against feed cache */ if (items) { itemSetPtr itemSet = node_get_itemset (subscription->node); gint newCount = itemset_merge_items (itemSet, items, TRUE /* feed valid */, FALSE /* markAsRead */); itemlist_merge_itemset (itemSet); itemset_free (itemSet); feedlist_node_was_updated (subscription->node, newCount); } subscription->node->available = TRUE; } else { subscription->node->available = FALSE; g_string_append (((feedPtr)subscription->node->data)->parseErrors, _("Could not parse JSON returned by TinyTinyRSS API!")); } g_object_unref (parser); } else { subscription->node->available = FALSE; } }
static void ttrss_source_subscription_list_cb (const struct updateResult * const result, gpointer user_data, guint32 flags) { subscriptionPtr subscription = (subscriptionPtr) user_data; ttrssSourcePtr source = (ttrssSourcePtr) subscription->node->data; debug1 (DEBUG_UPDATE,"ttrss_subscription_cb(): %s", result->data); subscription->updateJob = NULL; if (result->data && result->httpstatus == 200) { JsonParser *parser = json_parser_new (); if (json_parser_load_from_data (parser, result->data, -1, NULL)) { JsonNode *content = json_get_node (json_parser_get_root (parser), "content"); JsonArray *array; GList *iter, *elements; /* We expect something like this: [ {"feed_url":"http://feeds.arstechnica.com/arstechnica/everything", "title":"Ars Technica", "id":6, "unread":20, "has_icon":true, "cat_id":0, "last_updated":1287853210}, {"feed_url":"http://rss.slashdot.org/Slashdot/slashdot", "title":"Slashdot", "id":5, "unread":33, "has_icon":true, "cat_id":0, "last_updated":1287853206}, [...] Or an error message that could look like this: {"seq":null,"status":1,"content":{"error":"NOT_LOGGED_IN"}} */ if (!content || (JSON_NODE_TYPE (content) != JSON_NODE_ARRAY)) { debug0 (DEBUG_UPDATE, "ttrss_subscription_cb(): Failed to get subscription list!"); subscription->node->available = FALSE; return; } array = json_node_get_array (content); elements = iter = json_array_get_elements (array); /* Add all new nodes we find */ while (iter) { JsonNode *node = (JsonNode *)iter->data; /* ignore everything without a feed url */ if (json_get_string (node, "feed_url")) { ttrss_source_merge_feed (source, json_get_string (node, "feed_url"), json_get_string (node, "title"), json_get_int (node, "id")); } iter = g_list_next (iter); } g_list_free (elements); /* Remove old nodes we cannot find anymore */ node_foreach_child_data (source->root, ttrss_source_check_node_for_removal, array); /* Save new subscription tree to OPML cache file */ opml_source_export (subscription->node); subscription->node->available = TRUE; } else { g_warning ("Invalid JSON returned on TinyTinyRSSS request! >>>%s<<<", result->data); } g_object_unref (parser); } else { subscription->node->available = FALSE; debug0 (DEBUG_UPDATE, "ttrss_subscription_cb(): ERROR: failed to get TinyTinyRSS subscription list!"); } if (!(flags & TTRSS_SOURCE_UPDATE_ONLY_LIST)) node_foreach_child_data (subscription->node, node_update_subscription, GUINT_TO_POINTER (0)); }
int test_basic (void) { json_t *root; json_t *o; json_t *i; char *str; const char *s; int n; double d; int boolval; str = " {\"l1\" : 1111, " " \"l2\" : {\"l3\": {\"l4\": \"s2\", \"l5\": 2222 } }, " " \"l6\" : [1,2,3,4,5], " " \"l7\" : { \"l8\" : \"Hello World\" }, " " \"float\": 273.93," " \"b1\": trUe," " \"nil\": nulL," " \"b2\": false} \n\t"; str = strdup (str); root = json_from_string (str, NULL); assert (root); n = json_get_int (root, "l1", NULL); assert (n == 1111); d = json_get_double (root, "float", NULL); assert (d == 273.93); i = json_get_array (root, "l6", NULL); assert (i->type == JSON_TYPE_ARRAY); i = json_get_first (i); for (n = 0; i; n++, i = i->next) { int data[] = {1,2,3,4,5}; assert (i->type == JSON_TYPE_INT); assert (i->val.num == data[n]); } o = json_get (root, "nil", NULL); assert (o->type == JSON_TYPE_NULL); o = json_get (root, "b1", NULL); assert (o->type == JSON_TYPE_TRUE); o = json_get (root, "b2", NULL); assert (o->type == JSON_TYPE_FALSE); boolval = json_get_bool (root, "b1", NULL); assert (boolval == 1); boolval = json_get_bool (root, "b2", NULL); assert (boolval == 0); boolval = json_get_bool (root, "nonexisting", NULL); assert (boolval == -1); o = json_get_object (root, "l7", NULL); assert (o); if (o) { s = json_get_string (o, "l8", NULL); printf ("str = %s\n", s); } printf ("\n"); json_print (root); printf ("\n"); json_free (root); free (str); return 0; }