/* Copyright (C) 2009-2010 Dale Whittaker This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. See the file COPYING for the full license text. */ #include "feed-atom.h" static gboolean atom_is_valid (FeedParser* fparser) { xmlNodePtr node; node = fparser->node; if (!(xmlStrcmp (node->name, BAD_CAST "feed")) && !(xmlStrcmp (node->ns->href, BAD_CAST "http://www.w3.org/2005/Atom")) ) return TRUE; return FALSE; } static gboolean atom_update (FeedParser* fparser) { xmlNodePtr node; xmlNodePtr child; gint64 date; gint64 newdate; date = katze_item_get_added (fparser->item); node = fparser->node; child = node->children; while (child) { if (child->type == XML_ELEMENT_NODE) { if (!(xmlStrcmp (child->name, BAD_CAST "updated"))) { fparser->node = child; newdate = feed_get_element_date (fparser); fparser->node = node; return (date != newdate); } } child = child->next; } return TRUE; } static gboolean atom_preferred_link (const gchar* old, const gchar* new) { guint i; gint iold; gint inew; gchar* rels[5] = { "enclosure", "via", "related", "alternate", "self", }; iold = inew = -1; for (i = 0; i < 5; i++) { if (old && g_str_equal (old, rels[i])) iold = i; if (new && g_str_equal (new, rels[i])) inew = i; } return (inew > iold); } static void atom_get_link (KatzeItem* item, xmlNodePtr node) { gchar* oldtype; gchar* newtype; gchar* oldrel; gchar* newrel; gchar* href; gboolean oldishtml; gboolean newishtml; gboolean newlink; newlink = FALSE; oldtype = (gchar*)katze_item_get_meta_string (item, "feedpanel:linktype"); oldrel = (gchar*)katze_item_get_meta_string (item, "feedpanel:linkrel"); newtype = (gchar*)xmlGetProp (node, BAD_CAST "type"); newrel = (gchar*)xmlGetProp (node, BAD_CAST "rel"); href = (gchar*)xmlGetProp (node, BAD_CAST "href"); if (!newrel) newrel = g_strdup ("alternate"); oldishtml = (oldtype && g_str_equal (oldtype, "text/html")); newishtml = (newtype && g_str_equal (newtype, "text/html")); /* prefer HTML links over anything else. * if the previous link was already HTML, decide which link * we prefer. */ if ((newishtml && oldishtml) || (!newishtml && !oldishtml)) newlink = atom_preferred_link (oldrel, newrel); else newlink = newishtml; if (newlink) { katze_item_set_uri (item, href); katze_item_set_meta_string (item, "feedpanel:linkrel", newrel); katze_item_set_meta_string (item, "feedpanel:linktype", newtype); } xmlFree (href); xmlFree (newrel); xmlFree (newtype); } static void atom_preparse_entry (FeedParser* fparser) { fparser->item = katze_item_new (); } static void atom_parse_entry (FeedParser* fparser) { xmlNodePtr node; gchar* content; gint64 date; node = fparser->node; content = NULL; if (!xmlStrcmp (node->name, BAD_CAST "id")) { content = feed_get_element_string (fparser); katze_item_set_token (fparser->item, content); } else if (!xmlStrcmp (node->name, BAD_CAST "title")) { content = feed_get_element_string (fparser); katze_item_set_name (fparser->item, content); } else if (!xmlStrcmp (node->name, BAD_CAST "summary")) { content = feed_get_element_markup (fparser); katze_item_set_text (fparser->item, content); } else if (!xmlStrcmp (node->name, BAD_CAST "updated")) { date = feed_get_element_date (fparser); katze_item_set_added (fparser->item, date); } else if (!xmlStrcmp (node->name, BAD_CAST "icon")) { content = feed_get_element_string (fparser); katze_item_set_icon (fparser->item, content); } /* FIXME content can be used in some cases where there * is no summary, but it needs additional work, * as it can be HTML, or base64 encoded. * see the spec. */ else if (!xmlStrcmp (node->name, BAD_CAST "content")) { /* Only retrieve content if there is no summary */ if (!katze_item_get_text (fparser->item)) { content = feed_get_element_markup (fparser); katze_item_set_text (fparser->item, content); } } else if (!(xmlStrcmp (node->name, BAD_CAST "link"))) atom_get_link (fparser->item, node); g_free (content); } static void atom_postparse_entry (FeedParser* fparser) { if (!*fparser->error) { /* * Verify that the required Atom elements are added * (as per the spec) */ if (!katze_item_get_token (fparser->item) || !katze_item_get_name (fparser->item) || !katze_item_get_uri (fparser->item) || !katze_item_get_added (fparser->item)) { feed_parser_set_error (fparser, FEED_PARSE_ERROR_MISSING_ELEMENT, _("Failed to find required Atom \"entry\" elements in XML data.")); } } if (KATZE_IS_ITEM (fparser->item)) { katze_item_set_meta_string (fparser->item, "feedpanel:linkrel", NULL); katze_item_set_meta_string (fparser->item, "feedpanel:linktype", NULL); if (*fparser->error) { g_object_unref (fparser->item); fparser->item = NULL; } } } static void atom_parse_feed (FeedParser* fparser) { FeedParser* eparser; xmlNodePtr node; gchar* content; gint64 date; node = fparser->node; content = NULL; if (!xmlStrcmp (node->name, BAD_CAST "id")) { content = feed_get_element_string (fparser); katze_item_set_token (fparser->item, content); } else if (!xmlStrcmp (node->name, BAD_CAST "title")) { content = feed_get_element_string (fparser); katze_item_set_name (fparser->item, content); } else if (!xmlStrcmp (node->name, BAD_CAST "subtitle")) { content = feed_get_element_markup (fparser); katze_item_set_text (fparser->item, content); } else if (!xmlStrcmp (node->name, BAD_CAST "updated")) { date = feed_get_element_date (fparser); katze_item_set_added (fparser->item, date); } else if (!xmlStrcmp (node->name, BAD_CAST "icon")) { content = feed_get_element_string (fparser); katze_item_set_icon (fparser->item, content); } else if (!(xmlStrcmp (node->name, BAD_CAST "link"))) { atom_get_link (fparser->item, node); } else if (!xmlStrcmp (node->name, BAD_CAST "entry")) { eparser = g_new0 (FeedParser, 1); eparser->doc = fparser->doc; eparser->node = fparser->node; eparser->error = fparser->error; eparser->preparse = atom_preparse_entry; eparser->parse = atom_parse_entry; eparser->postparse = atom_postparse_entry; feed_parse_node (eparser); if (KATZE_IS_ITEM (eparser->item)) { KatzeItem* item; if (!(item = feed_item_exists (KATZE_ARRAY (fparser->item), eparser->item))) katze_array_add_item (KATZE_ARRAY (fparser->item), eparser->item); else { g_object_unref (eparser->item); katze_array_move_item (KATZE_ARRAY (fparser->item), item, 0); } } g_free (eparser); } g_free (content); } static void atom_postparse_feed (FeedParser* fparser) { if (KATZE_IS_ARRAY (fparser->item)) { katze_item_set_meta_string (fparser->item, "feedpanel:linkrel", NULL); katze_item_set_meta_string (fparser->item, "feedpanel:linktype", NULL); } if (!*fparser->error) { /* * Verify that the required Atom elements are added * (as per the spec) */ if (!katze_item_get_token (fparser->item) || !katze_item_get_name (fparser->item) || !katze_item_get_added (fparser->item)) { feed_parser_set_error (fparser, FEED_PARSE_ERROR_MISSING_ELEMENT, _("Failed to find required Atom \"feed\" elements in XML data.")); } } } FeedParser* atom_init_parser (void) { FeedParser* fparser; fparser = g_new0 (FeedParser, 1); g_return_val_if_fail (fparser, NULL); fparser->isvalid = atom_is_valid; fparser->update = atom_update; fparser->parse = atom_parse_feed; fparser->postparse = atom_postparse_feed; return fparser; }