void item_read_state_changed (itemPtr item, gboolean newState) { nodePtr node; debug_start_measurement (DEBUG_GUI); /* 1. set values in memory */ item->readStatus = newState; item->updateStatus = FALSE; /* 2. propagate to vfolders */ vfolder_foreach_data (vfolder_merge_item, item); vfolder_foreach (node_update_counters); /* 3. apply to DB */ db_item_state_update (item); /* 4. update item list GUI state */ itemlist_update_item (item); /* 5. updated feed list unread counters */ node = node_from_id (item->nodeId); node_update_counters (node); /* 6. update notification statistics */ feedlist_reset_new_item_count (); /* 7. duplicate state propagation */ if (item->validGuid) { GSList *duplicates, *iter; duplicates = iter = db_item_get_duplicates (item->sourceId); while (iter) { itemPtr duplicate = item_load (GPOINTER_TO_UINT (iter->data)); /* The check on node_from_id() is an evil workaround to handle "lost" items in the DB that have no associated node in the feed list. This should be fixed by having the feed list in the DB too, so we can clean up correctly after crashes. */ if (duplicate && duplicate->id != item->id && node_from_id (duplicate->nodeId)) { item_set_read_state (duplicate, newState); } if (duplicate) item_unload (duplicate); iter = g_slist_next (iter); } g_slist_free (duplicates); } debug_end_measurement (DEBUG_GUI, "set read status"); }
static gboolean itemset_merge_item (itemSetPtr itemSet, GList *items, itemPtr item, gint maxChecks, gboolean allowUpdates) { gboolean allowStateChanges = FALSE; gboolean merge; nodePtr node; debug2 (DEBUG_UPDATE, "trying to merge \"%s\" to node id \"%s\"", item_get_title (item), itemSet->nodeId); g_assert (itemSet->nodeId); node = node_from_id (itemSet->nodeId); if (node) allowStateChanges = NODE_SOURCE_TYPE (node)->capabilities & NODE_SOURCE_CAPABILITY_ITEM_STATE_SYNC; /* first try to merge with existing item */ merge = itemset_generic_merge_check (items, item, maxChecks, allowUpdates, allowStateChanges); /* if it is a new item add it to the item set */ if (merge) { g_assert (!item->nodeId); g_assert (!item->id); item->nodeId = g_strdup (itemSet->nodeId); if (!item->parentNodeId) item->parentNodeId = g_strdup (itemSet->nodeId); /* step 1: write item to DB */ db_item_update (item); /* step 2: add to itemset */ itemSet->ids = g_list_prepend (itemSet->ids, GUINT_TO_POINTER (item->id)); /* step 3: trigger async enrichment of item description */ if (node && IS_FEED (node) && ((feedPtr)node->data)->html5Extract) feed_enrich_item (node->subscription, item); debug3 (DEBUG_UPDATE, "-> added \"%s\" (id=%d) to item set %p...", item_get_title (item), item->id, itemSet); /* step 4: duplicate detection, mark read if it is a duplicate */ if (item->validGuid) { GSList *iter, *duplicates; duplicates = iter = db_item_get_duplicates (item->sourceId); while (iter) { debug1 (DEBUG_UPDATE, "-> duplicate guid exists: #%lu", GPOINTER_TO_UINT (iter->data)); iter = g_slist_next (iter); } if (g_slist_length (duplicates) > 1) { item->readStatus = TRUE; /* no unread counting... */ item->popupStatus = FALSE; /* no notification... */ } g_slist_free (duplicates); } /* step 5: Check item for new enclosures to download */ if (node && (((feedPtr)node->data)->encAutoDownload)) { GSList *iter = metadata_list_get_values (item->metadata, "enclosure"); while (iter) { enclosurePtr enc = enclosure_from_string (iter->data); debug1 (DEBUG_UPDATE, "download enclosure (%s)", (gchar *)iter->data); enclosure_download (NULL, enc->url, FALSE /* non interactive */); iter = g_slist_next (iter); enclosure_free (enc); } } } else { debug2 (DEBUG_UPDATE, "-> not adding \"%s\" to node id \"%s\"...", item_get_title (item), itemSet->nodeId); item_unload (item); } return merge; }