2 * Copyright (C) 2006 Andrej Kacian <andrej@kacian.sk>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 #include <curl/curl.h>
31 * Initializes new Feed struct, setting its url and a default timeout. */
32 Feed *feed_new(gchar *url)
36 g_return_val_if_fail(url != NULL, NULL);
38 feed = malloc( sizeof(Feed) );
39 g_return_val_if_fail(feed != NULL, NULL);
41 feed->timeout = FEED_DEFAULT_TIMEOUT;
42 feed->url = g_strdup(url);
44 feed->description = NULL;
45 feed->language = NULL;
47 feed->generator = NULL;
50 feed->fetcherr = NULL;
51 feed->cookies_path = NULL;
56 static void _free_items(gpointer item, gpointer nada)
61 void feed_free(Feed *feed)
64 return; /* Return silently, without printing a glib error. */
68 g_free(feed->description);
69 g_free(feed->language);
71 g_free(feed->generator);
72 g_free(feed->fetcherr);
73 g_free(feed->cookies_path);
75 if( feed->items != NULL ) {
76 g_slist_foreach(feed->items, _free_items, NULL);
77 g_slist_free(feed->items);
84 void feed_free_items(Feed *feed)
89 if( feed->items != NULL ) {
90 g_slist_foreach(feed->items, _free_items, NULL);
91 g_slist_free(feed->items);
97 void feed_set_timeout(Feed *feed, guint timeout)
99 g_return_if_fail(feed != NULL);
100 feed->timeout = timeout;
103 guint feed_get_timeout(Feed *feed)
105 g_return_val_if_fail(feed != NULL, 0);
106 return feed->timeout;
110 void feed_set_url(Feed *feed, gchar *url)
112 g_return_if_fail(feed != NULL);
113 g_return_if_fail(url != NULL);
115 if( feed->url != NULL ) {
120 feed->url = g_strdup(url);
123 gchar *feed_get_url(Feed *feed)
125 g_return_val_if_fail(feed != NULL, NULL);
130 gchar *feed_get_title(Feed *feed)
132 g_return_val_if_fail(feed != NULL, NULL);
136 void feed_set_title(Feed *feed, gchar *new_title)
138 g_return_if_fail(feed != NULL);
139 g_return_if_fail(new_title != NULL);
141 if (feed->title != NULL) {
146 feed->title = g_strdup(new_title);
150 gchar *feed_get_description(Feed *feed)
152 g_return_val_if_fail(feed != NULL, NULL);
153 return feed->description;
157 gchar *feed_get_language(Feed *feed)
159 g_return_val_if_fail(feed != NULL, NULL);
160 return feed->language;
164 gchar *feed_get_author(Feed *feed)
166 g_return_val_if_fail(feed != NULL, NULL);
171 gchar *feed_get_generator(Feed *feed)
173 g_return_val_if_fail(feed != NULL, NULL);
174 return feed->generator;
177 /* Fetch error (if not NULL, supplied by libcurl) */
178 gchar *feed_get_fetcherror(Feed *feed)
180 g_return_val_if_fail(feed != NULL, NULL);
181 return feed->fetcherr;
184 /* Returns number of items currently in the feed. */
185 gint feed_n_items(Feed *feed)
187 g_return_val_if_fail(feed != NULL, -1);
189 if( feed->items == NULL ) /* No items here. */
192 return g_slist_length(feed->items);
195 /* Returns nth item from feed. */
196 FeedItem *feed_nth_item(Feed *feed, guint n)
198 g_return_val_if_fail(feed != NULL, NULL);
200 return g_slist_nth_data(feed->items, n);
204 * Takes initialized feed with url set, fetches the feed from this url,
205 * updates rest of Feed struct members and returns HTTP response code
206 * we got from url's server. */
207 guint feed_update(Feed *feed, time_t last_update)
211 FeedParserCtx *feed_ctx = NULL;
212 glong response_code = 0;
214 g_return_val_if_fail(feed != NULL, FEED_ERR_NOFEED);
215 g_return_val_if_fail(feed->url != NULL, FEED_ERR_NOURL);
217 /* Init curl before anything else. */
218 eh = curl_easy_init();
220 g_return_val_if_fail(eh != NULL, FEED_ERR_INIT);
222 /* Curl initialized, create parser context now. */
223 feed_ctx = malloc( sizeof(FeedParserCtx) );
225 feed_ctx->parser = XML_ParserCreate(NULL);
227 feed_ctx->str = NULL;
228 feed_ctx->feed = feed;
229 feed_ctx->location = 0;
230 feed_ctx->curitem = NULL;
231 feed_ctx->id_is_permalink = TRUE;
233 feed_ctx->name = NULL;
234 feed_ctx->mail = NULL;
236 /* Set initial expat handlers, which will take care of choosing
237 * correct parser later. */
238 feed_parser_set_expat_handlers(feed_ctx);
240 curl_easy_setopt(eh, CURLOPT_URL, feed->url);
241 curl_easy_setopt(eh, CURLOPT_NOPROGRESS, 1);
243 curl_easy_setopt(eh, CURLOPT_MUTE, 1);
245 curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, feed_writefunc);
246 curl_easy_setopt(eh, CURLOPT_WRITEDATA, feed_ctx);
247 curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
248 curl_easy_setopt(eh, CURLOPT_MAXREDIRS, 3);
249 curl_easy_setopt(eh, CURLOPT_TIMEOUT, feed->timeout);
250 curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
251 curl_easy_setopt(eh, CURLOPT_ENCODING, "");
252 curl_easy_setopt(eh, CURLOPT_USERAGENT, "libfeed 0.1");
254 /* Use HTTP's If-Modified-Since feature, if application provided
255 * the timestamp of last update. */
256 if( last_update != -1 ) {
257 curl_easy_setopt(eh, CURLOPT_TIMECONDITION,
258 CURL_TIMECOND_IFMODSINCE);
259 curl_easy_setopt(eh, CURLOPT_TIMEVALUE, last_update);
262 #if LIBCURL_VERSION_NUM >= 0x070a00
263 if (feed->ssl_verify_peer == FALSE) {
264 curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
265 curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
269 if(feed->cookies_path != NULL)
270 curl_easy_setopt(eh, CURLOPT_COOKIEFILE, feed->cookies_path);
272 res = curl_easy_perform(eh);
273 XML_Parse(feed_ctx->parser, "", 0, TRUE);
275 if( res != CURLE_OK ) {
276 feed->fetcherr = g_strdup(curl_easy_strerror(res));
277 response_code = FEED_ERR_FETCH;
279 curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &response_code);
281 curl_easy_cleanup(eh);
283 /* Cleanup, we should be done. */
284 XML_ParserFree(feed_ctx->parser);
285 g_free(feed_ctx->name);
286 g_free(feed_ctx->mail);
289 return response_code;
292 void feed_foreach_item(Feed *feed, GFunc func, gpointer data)
294 g_return_if_fail(feed != NULL);
295 g_return_if_fail(feed->items != NULL);
297 g_slist_foreach(feed->items, func, data);
300 gboolean feed_prepend_item(Feed *feed, FeedItem *item)
302 g_return_val_if_fail(feed != NULL, FALSE);
303 g_return_val_if_fail(item != NULL, FALSE);
305 feed->items = g_slist_prepend(feed->items, item);
309 gboolean feed_append_item(Feed *feed, FeedItem *item)
311 g_return_val_if_fail(feed != NULL, FALSE);
312 g_return_val_if_fail(item != NULL, FALSE);
314 feed->items = g_slist_append(feed->items, item);
318 gboolean feed_insert_item(Feed *feed, FeedItem *item, gint pos)
320 g_return_val_if_fail(feed != NULL, FALSE);
321 g_return_val_if_fail(item != NULL, FALSE);
322 g_return_val_if_fail(pos < 0, FALSE);
324 feed->items = g_slist_insert(feed->items, item, pos);
328 gchar *feed_get_cookies_path(Feed *feed)
330 g_return_val_if_fail(feed != NULL, NULL);
331 return feed->cookies_path;
334 void feed_set_cookies_path(Feed *feed, gchar *path)
336 g_return_if_fail(feed != NULL);
338 if( feed->cookies_path != NULL ) {
339 g_free(feed->cookies_path);
340 feed->cookies_path = NULL;
343 feed->cookies_path = (path != NULL ? g_strdup(path) : NULL);
346 gboolean feed_get_ssl_verify_peer(Feed *feed)
348 g_return_val_if_fail(feed != NULL, FALSE);
349 return feed->ssl_verify_peer;
352 void feed_set_ssl_verify_peer(Feed *feed, gboolean ssl_verify_peer)
354 g_return_if_fail(feed != NULL);
355 feed->ssl_verify_peer = ssl_verify_peer;