Esempio n. 1
0
void
subscription_free (subscriptionPtr subscription)
{
	if (!subscription)
		return;
		
	g_free (subscription->updateError);
	g_free (subscription->filterError);
	g_free (subscription->httpError);
	g_free (subscription->source);
	g_free (subscription->origSource);
	g_free (subscription->filtercmd);
	
	update_job_cancel_by_owner (subscription);
	update_options_free (subscription->updateOptions);
	update_state_free (subscription->updateState);
	metadata_list_free (subscription->metadata);
	
	g_free (subscription);
}
Esempio n. 2
0
/**
 * itemset_generic_merge_check: (skip)
 * @items:		existing items
 * @newItem:		new item to merge
 * @maxChecks: 		maximum number of item checks
 * @allowUpdates:	TRUE if item content update is to be
 *      		allowed for existing items
 * @allowStateChanges:	TRUE if item state shall be
 *				overwritten by source
 *
 * Generic merge logic suitable for feeds
 *
 * Returns: TRUE if merging instead of updating is necessary)
 */
static gboolean
itemset_generic_merge_check (GList *items, itemPtr newItem, gint maxChecks, gboolean allowUpdates, gboolean allowStateChanges)
{
	GList		*oldItemIdIter = items;
	itemPtr		oldItem = NULL;
	gboolean	found, equal = FALSE;
	guint		reason = 0;

	/* determine if we should add it... */
	debug3 (DEBUG_CACHE, "check new item for merging: \"%s\", %i, %i", item_get_title (newItem), allowUpdates, allowStateChanges);

	/* compare to every existing item in this feed */
	found = FALSE;
	while (oldItemIdIter) {
		oldItem = (itemPtr)(oldItemIdIter->data);

		/* try to compare the two items */

		/* trivial case: one item has id the other doesn't -> they can't be equal */
		if (((item_get_id (oldItem) == NULL) && (item_get_id (newItem) != NULL)) ||
		    ((item_get_id (oldItem) != NULL) && (item_get_id (newItem) == NULL))) {
			/* cannot be equal (different ids) so compare to
			   next old item */
			oldItemIdIter = g_list_next (oldItemIdIter);
		   	continue;
		}

		/* just for the case there are no ids: compare titles and HTML descriptions */
		equal = TRUE;

		if (((item_get_title (oldItem) != NULL) && (item_get_title (newItem) != NULL)) &&
		     (0 != strcmp (item_get_title (oldItem), item_get_title (newItem)))) {
	    		equal = FALSE;
			reason |= 1;
		}

		if (((item_get_description (oldItem) != NULL) && (item_get_description (newItem) != NULL)) &&
		     (0 != strcmp (item_get_description(oldItem), item_get_description (newItem)))) {
	    		equal = FALSE;
			reason |= 2;
		}

		/* best case: they both have ids (position important: id check is useless without knowing if the items are different!) */
		if (item_get_id (oldItem)) {
			if (0 == strcmp (item_get_id (oldItem), item_get_id (newItem))) {
				found = TRUE;

				if (allowStateChanges) {
					/* found corresponding item, check if they are REALLY equal (eg, read status may have changed) */
					if(oldItem->readStatus != newItem->readStatus) {
						equal = FALSE;
						reason |= 4;
					}
					if(oldItem->flagStatus != newItem->flagStatus) {
						equal = FALSE;
						reason |= 8;
					}
				}
				break;
			} else {
				/* different ids, but the content might be still equal (e.g. empty)
				   so we need to explicitly unset the equal flag !!!  */
				equal = FALSE;
				reason |= 16;
			}
		}

		if (equal) {
			found = TRUE;
			break;
		}

		oldItemIdIter = g_list_next (oldItemIdIter);
	}

	if (!found) {
		debug0 (DEBUG_CACHE, "-> item is to be added");
	} else {
		/* if the item was found but has other contents -> update contents */
		if (!equal) {
			if (allowUpdates) {
				/* no item_set_new_status() - we don't treat changed items as new items! */
				item_set_title (oldItem, item_get_title (newItem));

				/* don't use item_set_description as it does some unwanted length handling
				   and we want to enforce the new description */
				g_free (oldItem->description);
				oldItem->description = newItem->description;
				newItem->description = NULL;

				oldItem->time = newItem->time;
				oldItem->updateStatus = TRUE;
				// FIXME: this does not remove metadata from DB
				metadata_list_free (oldItem->metadata);
				oldItem->metadata = newItem->metadata;
				newItem->metadata = NULL;

				/* Only update item state for feed sources where it is necessary
				   which means online accounts we sync against, but not normal
				   online feeds where items have no read status. */
				if (allowStateChanges) {
					/* To avoid notification spam from external
					   sources: never set read items to unread again! */
					if ((!oldItem->readStatus) && (newItem->readStatus))
						oldItem->readStatus = newItem->readStatus;

					oldItem->flagStatus = newItem->flagStatus;
				}

				db_item_update (oldItem);
				debug1 (DEBUG_CACHE, "-> item already existing and was updated, reason %x", reason);
			} else {
				debug0 (DEBUG_CACHE, "-> item updates not merged because of parser errors");
			}
		} else {
			debug0 (DEBUG_CACHE, "-> item already exists");
		}
	}

	return !found;
}
Esempio n. 3
0
/**
 * General feed source parsing function. Parses the passed feed source
 * and tries to determine the source type. 
 *
 * @param ctxt		feed parsing context
 *
 * @returns FALSE if auto discovery is indicated, 
 *          TRUE if feed type was recognized and parsing was successful
 */
gboolean
feed_parse (feedParserCtxtPtr ctxt)
{
	xmlNodePtr	cur;
	gboolean	success = FALSE;

	debug_enter("feed_parse");

	g_assert(NULL == ctxt->items);
	
	ctxt->failed = TRUE;	/* reset on success ... */

	if(ctxt->feed->parseErrors)
		g_string_truncate(ctxt->feed->parseErrors, 0);
	else
		ctxt->feed->parseErrors = g_string_new(NULL);

	/* try to parse buffer with XML and to create a DOM tree */	
	do {
		if(NULL == xml_parse_feed (ctxt)) {
			g_string_append_printf (ctxt->feed->parseErrors, _("XML error while reading feed! Feed \"%s\" could not be loaded!"), subscription_get_source (ctxt->subscription));
			break;
		}
		
		if(NULL == (cur = xmlDocGetRootElement(ctxt->doc))) {
			g_string_append(ctxt->feed->parseErrors, _("Empty document!"));
			break;
		}
		
		while(cur && xmlIsBlankNode(cur)) {
			cur = cur->next;
		}
		
		if(!cur)
			break;
				
		if(!cur->name) {
			g_string_append(ctxt->feed->parseErrors, _("Invalid XML!"));
			break;
		}

		/* determine the syndication format and start parser */
		GSList *handlerIter = feed_parsers_get_list ();
		while(handlerIter) {
			feedHandlerPtr handler = (feedHandlerPtr)(handlerIter->data);
			if(handler && handler->checkFormat && (*(handler->checkFormat))(ctxt->doc, cur)) {
				/* free old temp. parsing data, don't free right after parsing because
				   it can be used until the last feed request is finished, move me 
				   to the place where the last request in list otherRequests is 
				   finished :-) */
				g_hash_table_destroy(ctxt->tmpdata);
				ctxt->tmpdata = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
				
				/* we always drop old metadata */
				metadata_list_free(ctxt->subscription->metadata);
				ctxt->subscription->metadata = NULL;
				ctxt->failed = FALSE;

				ctxt->feed->fhp = handler;
				(*(handler->feedParser))(ctxt, cur);		/* parse it */

				break;
			}
			handlerIter = handlerIter->next;
		}
	} while(0);
	
	/* if the given URI isn't valid we need to start auto discovery */
	if(ctxt->failed)
		feed_parser_auto_discover (ctxt);

	if(ctxt->failed) {
		/* Autodiscovery failed */
		/* test if we have a HTML page */
		if((strstr(ctxt->data, "<html>") || strstr(ctxt->data, "<HTML>") ||
		    strstr(ctxt->data, "<html ") || strstr(ctxt->data, "<HTML "))) {
			debug0(DEBUG_UPDATE, "HTML document detected!");
			g_string_append(ctxt->feed->parseErrors, _("Source points to HTML document."));
		} else {
			debug0(DEBUG_UPDATE, "neither a known feed type nor a HTML document!");
			g_string_append(ctxt->feed->parseErrors, _("Could not determine the feed type."));
		}
	} else {
		debug1(DEBUG_UPDATE, "discovered feed format: %s", feed_type_fhp_to_str(ctxt->feed->fhp));
		success = TRUE;
	}
	
	if(ctxt->doc) {
		xmlFreeDoc(ctxt->doc);
		ctxt->doc = NULL;
	}
		
	debug_exit("feed_parse");
	
	return success;
}