/* * greddit - a very simple GLib-friendly reddit client * Copyright (c) 2009 Thomas Thurman * thomas@thurman.org.uk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have be able to view the GNU General Public License at * http://www.gnu.org/copyleft/gpl.html ; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include "greddit2.h" #define REDDIT_FRONT_PAGE_IN_JSON "http://www.reddit.com/.json" /** * Comparison function for sorting GRedditPost objects by * score. */ static int greddit_post_compare (gconstpointer a, gconstpointer b) { GRedditPost* grpa = (GRedditPost*) a; GRedditPost* grpb = (GRedditPost*) b; if (grpa->score == grpb->score) return 0; else if (grpa->score < grpb->score) return 1; else return -1; } typedef struct { size_t size; size_t total; char *content; GRedditLoadingCallback callback; } GRedditIncomingData; static size_t greddit_eat_data (void *buffer, size_t size, size_t nmemb, void *targetp) { GRedditIncomingData *target = (GRedditIncomingData*) targetp; target->content = g_realloc (target->content, target->size + size*nmemb + 1); g_memmove (target->content + target->size, buffer, size*nmemb); target->size += size*nmemb; /* make sure it's null-terminated */ target->content[target->size] = 0; if (target->callback) target->callback (target->size, target->total); return size*nmemb; } size_t greddit_get_total_size (void *ptr, size_t size, size_t nmemb, void *stream) { GRedditIncomingData *target = (GRedditIncomingData*) stream; if (strncasecmp ((char*) ptr, "Content-Length:", 15)==0) { target->total = atoi(ptr+15); } return size*nmemb; } GSList * greddit_get_posts (void) { return greddit_get_posts_with_callback (NULL); } GSList * greddit_get_posts_with_callback (GRedditLoadingCallback callback) { JsonParser *parser = json_parser_new (); GSList *result = NULL; GList *posts, *cursor; CURL *curl = curl_easy_init (); GRedditIncomingData json; int curl_status; json.size = 0; json.total = 0; json.content = NULL; json.callback = callback; /* set curl_easy_setopt (curl, CURLOPT_VERBOSE, 1); for debugging here */ curl_easy_setopt (curl, CURLOPT_URL, REDDIT_FRONT_PAGE_IN_JSON); curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, greddit_get_total_size); curl_easy_setopt (curl, CURLOPT_HEADERDATA, &json); curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, greddit_eat_data); curl_easy_setopt (curl, CURLOPT_WRITEDATA, &json); curl_status = curl_easy_perform (curl); if (curl_status != CURLE_OK) { fprintf (stderr, "Warning: curl error %d\n", curl_status); return NULL; } if (json.content==NULL) { fprintf (stderr, "Warning: empty document\n"); return NULL; } if (!json_parser_load_from_data (parser, json.content, -1, NULL)) { fprintf (stderr, "Warning: malformed JSON:\n%s\n", json.content); g_free (json.content); return NULL; } g_free (json.content); posts = json_array_get_elements (json_node_get_array (json_object_get_member (json_node_get_object (json_object_get_member (json_node_get_object (json_parser_get_root (parser)), "data") ), "children") ) ); for (cursor=posts; cursor; cursor=cursor->next) { JsonNode *wrapper = (JsonNode *) cursor->data; JsonObject *post = json_node_get_object (json_object_get_member (json_node_get_object (wrapper), "data")); GRedditPost *p = g_new(GRedditPost, 1); p->id = g_strdup (json_node_get_string (json_object_get_member (post, "id"))); p->url = g_strdup (json_node_get_string (json_object_get_member (post, "url"))); p->title = g_strdup (json_node_get_string (json_object_get_member (post, "title"))); p->author = g_strdup (json_node_get_string (json_object_get_member (post, "author"))); p->subreddit = g_strdup (json_node_get_string (json_object_get_member (post, "subreddit"))); p->score = json_node_get_int (json_object_get_member (post, "score")); result = g_slist_insert_sorted (result, p, greddit_post_compare); } g_list_free (posts); g_object_unref (parser); curl_easy_cleanup (curl); return result; } void greddit_free_posts (GSList *posts) { GSList *cursor; for (cursor=posts; cursor; cursor=cursor->next) { GRedditPost *grp = (GRedditPost*) cursor->data; g_free (grp->id); g_free (grp->url); g_free (grp->title); g_free (grp->author); g_free (grp->subreddit); } g_slist_free (posts); } /* eof greddit.c */