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);
45 feed->description = NULL;
46 feed->language = NULL;
48 feed->generator = NULL;
52 feed->fetcherr = NULL;
53 feed->cookies_path = NULL;
55 feed->ssl_verify_peer = TRUE;
56 feed->cacert_file = NULL;
61 static void _free_items(gpointer item, gpointer nada)
66 static void _free_auth(Feed *feed)
71 if (feed->auth != NULL) {
72 if (feed->auth->username != NULL)
73 g_free(feed->auth->username);
74 if (feed->auth->password != NULL)
75 g_free(feed->auth->password);
81 void feed_free(Feed *feed)
84 return; /* Return silently, without printing a glib error. */
89 g_free(feed->description);
90 g_free(feed->language);
92 g_free(feed->generator);
94 g_free(feed->fetcherr);
95 g_free(feed->cookies_path);
96 g_free(feed->cacert_file);
98 if( feed->items != NULL ) {
99 g_slist_foreach(feed->items, _free_items, NULL);
100 g_slist_free(feed->items);
107 void feed_free_items(Feed *feed)
112 if( feed->items != NULL ) {
113 g_slist_foreach(feed->items, _free_items, NULL);
114 g_slist_free(feed->items);
120 void feed_set_timeout(Feed *feed, guint timeout)
122 g_return_if_fail(feed != NULL);
123 feed->timeout = timeout;
126 guint feed_get_timeout(Feed *feed)
128 g_return_val_if_fail(feed != NULL, 0);
129 return feed->timeout;
133 void feed_set_url(Feed *feed, gchar *url)
135 g_return_if_fail(feed != NULL);
136 g_return_if_fail(url != NULL);
138 if( feed->url != NULL ) {
143 feed->url = g_strdup(url);
146 gchar *feed_get_url(Feed *feed)
148 g_return_val_if_fail(feed != NULL, NULL);
153 void feed_set_auth(Feed *feed, FeedAuth *auth)
155 g_return_if_fail(feed != NULL);
156 g_return_if_fail(auth != NULL);
159 feed->auth = g_new0(FeedAuth, 1);
160 feed->auth->type = auth->type;
161 feed->auth->username = g_strdup(auth->username);
162 feed->auth->password = g_strdup(auth->password);
165 FeedAuth *feed_get_auth(Feed *feed)
167 g_return_val_if_fail(feed != NULL, NULL);
172 gchar *feed_get_title(Feed *feed)
174 g_return_val_if_fail(feed != NULL, NULL);
178 void feed_set_title(Feed *feed, gchar *new_title)
180 g_return_if_fail(feed != NULL);
181 g_return_if_fail(new_title != NULL);
183 if (feed->title != NULL) {
188 feed->title = g_strdup(new_title);
192 gchar *feed_get_description(Feed *feed)
194 g_return_val_if_fail(feed != NULL, NULL);
195 return feed->description;
199 gchar *feed_get_language(Feed *feed)
201 g_return_val_if_fail(feed != NULL, NULL);
202 return feed->language;
206 gchar *feed_get_author(Feed *feed)
208 g_return_val_if_fail(feed != NULL, NULL);
213 gchar *feed_get_generator(Feed *feed)
215 g_return_val_if_fail(feed != NULL, NULL);
216 return feed->generator;
219 /* Fetch error (if not NULL, supplied by libcurl) */
220 gchar *feed_get_fetcherror(Feed *feed)
222 g_return_val_if_fail(feed != NULL, NULL);
223 return feed->fetcherr;
226 /* Returns number of items currently in the feed. */
227 gint feed_n_items(Feed *feed)
229 g_return_val_if_fail(feed != NULL, -1);
231 if( feed->items == NULL ) /* No items here. */
234 return g_slist_length(feed->items);
237 /* Returns nth item from feed. */
238 FeedItem *feed_nth_item(Feed *feed, guint n)
240 g_return_val_if_fail(feed != NULL, NULL);
242 return g_slist_nth_data(feed->items, n);
246 * Takes initialized feed with url set, fetches the feed from this url,
247 * updates rest of Feed struct members and returns HTTP response code
248 * we got from url's server. */
249 guint feed_update(Feed *feed, time_t last_update)
253 FeedParserCtx *feed_ctx = NULL;
254 glong response_code = 0;
256 g_return_val_if_fail(feed != NULL, FEED_ERR_NOFEED);
257 g_return_val_if_fail(feed->url != NULL, FEED_ERR_NOURL);
259 /* Init curl before anything else. */
260 eh = curl_easy_init();
262 g_return_val_if_fail(eh != NULL, FEED_ERR_INIT);
264 /* Curl initialized, create parser context now. */
265 feed_ctx = malloc( sizeof(FeedParserCtx) );
267 feed_ctx->parser = XML_ParserCreate(NULL);
269 feed_ctx->str = NULL;
270 feed_ctx->feed = feed;
271 feed_ctx->location = 0;
272 feed_ctx->curitem = NULL;
273 feed_ctx->id_is_permalink = TRUE;
275 feed_ctx->name = NULL;
276 feed_ctx->mail = NULL;
278 /* Set initial expat handlers, which will take care of choosing
279 * correct parser later. */
280 feed_parser_set_expat_handlers(feed_ctx);
282 curl_easy_setopt(eh, CURLOPT_URL, feed->url);
283 curl_easy_setopt(eh, CURLOPT_NOPROGRESS, 1);
285 curl_easy_setopt(eh, CURLOPT_MUTE, 1);
287 curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, feed_writefunc);
288 curl_easy_setopt(eh, CURLOPT_WRITEDATA, feed_ctx);
289 curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
290 curl_easy_setopt(eh, CURLOPT_MAXREDIRS, 3);
291 curl_easy_setopt(eh, CURLOPT_TIMEOUT, feed->timeout);
292 curl_easy_setopt(eh, CURLOPT_NOSIGNAL, 1);
293 curl_easy_setopt(eh, CURLOPT_ENCODING, "");
294 curl_easy_setopt(eh, CURLOPT_USERAGENT, "libfeed 0.1");
295 curl_easy_setopt(eh, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
297 /* Use HTTP's If-Modified-Since feature, if application provided
298 * the timestamp of last update. */
299 if( last_update != -1 ) {
300 curl_easy_setopt(eh, CURLOPT_TIMECONDITION,
301 CURL_TIMECOND_IFMODSINCE);
302 curl_easy_setopt(eh, CURLOPT_TIMEVALUE, last_update);
305 #if LIBCURL_VERSION_NUM >= 0x070a00
306 if (feed->ssl_verify_peer == FALSE) {
307 curl_easy_setopt(eh, CURLOPT_SSL_VERIFYPEER, 0);
308 curl_easy_setopt(eh, CURLOPT_SSL_VERIFYHOST, 0);
312 if (feed->cacert_file != NULL)
313 curl_easy_setopt(eh, CURLOPT_CAINFO, feed->cacert_file);
315 if(feed->cookies_path != NULL)
316 curl_easy_setopt(eh, CURLOPT_COOKIEFILE, feed->cookies_path);
318 if (feed->auth != NULL) {
319 switch (feed->auth->type) {
322 case FEED_AUTH_BASIC:
323 curl_easy_setopt(eh, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
324 curl_easy_setopt(eh, CURLOPT_USERNAME,
325 feed->auth->username);
326 curl_easy_setopt(eh, CURLOPT_PASSWORD,
327 feed->auth->password);
330 response_code = FEED_ERR_UNAUTH; /* unknown auth */
335 res = curl_easy_perform(eh);
336 XML_Parse(feed_ctx->parser, "", 0, TRUE);
338 if( res != CURLE_OK ) {
339 feed->fetcherr = g_strdup(curl_easy_strerror(res));
340 response_code = FEED_ERR_FETCH;
342 curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &response_code);
345 curl_easy_cleanup(eh);
347 /* Cleanup, we should be done. */
348 XML_ParserFree(feed_ctx->parser);
349 g_free(feed_ctx->name);
350 g_free(feed_ctx->mail);
353 return response_code;
356 void feed_foreach_item(Feed *feed, GFunc func, gpointer data)
358 g_return_if_fail(feed != NULL);
359 g_return_if_fail(feed->items != NULL);
361 g_slist_foreach(feed->items, func, data);
364 gboolean feed_prepend_item(Feed *feed, FeedItem *item)
366 g_return_val_if_fail(feed != NULL, FALSE);
367 g_return_val_if_fail(item != NULL, FALSE);
369 feed->items = g_slist_prepend(feed->items, item);
373 gboolean feed_append_item(Feed *feed, FeedItem *item)
375 g_return_val_if_fail(feed != NULL, FALSE);
376 g_return_val_if_fail(item != NULL, FALSE);
378 feed->items = g_slist_append(feed->items, item);
382 gboolean feed_insert_item(Feed *feed, FeedItem *item, gint pos)
384 g_return_val_if_fail(feed != NULL, FALSE);
385 g_return_val_if_fail(item != NULL, FALSE);
386 g_return_val_if_fail(pos < 0, FALSE);
388 feed->items = g_slist_insert(feed->items, item, pos);
392 gchar *feed_get_cookies_path(Feed *feed)
394 g_return_val_if_fail(feed != NULL, NULL);
395 return feed->cookies_path;
398 void feed_set_cookies_path(Feed *feed, gchar *path)
400 g_return_if_fail(feed != NULL);
402 if( feed->cookies_path != NULL ) {
403 g_free(feed->cookies_path);
404 feed->cookies_path = NULL;
407 feed->cookies_path = (path != NULL ? g_strdup(path) : NULL);
410 gboolean feed_get_ssl_verify_peer(Feed *feed)
412 g_return_val_if_fail(feed != NULL, FALSE);
413 return feed->ssl_verify_peer;
416 void feed_set_ssl_verify_peer(Feed *feed, gboolean ssl_verify_peer)
418 g_return_if_fail(feed != NULL);
419 feed->ssl_verify_peer = ssl_verify_peer;
422 gchar *feed_get_cacert_file(Feed *feed)
424 g_return_val_if_fail(feed != NULL, NULL);
425 return feed->cacert_file;
428 void feed_set_cacert_file(Feed *feed, gchar *path)
430 g_return_if_fail(feed != NULL);
432 if( feed->cacert_file != NULL ) {
433 g_free(feed->cacert_file);
434 feed->cacert_file = NULL;
437 feed->cacert_file = (path != NULL ? g_strdup(path) : NULL);