summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2023-04-18 15:07:11 +0200
committerMilan Crha <mcrha@redhat.com>2023-04-18 15:07:11 +0200
commitf939a483d238ca529af4e2cbb03b3513d87b6ea8 (patch)
treed7359b759cf75c4df17e3f48249e23597774898a
parent199787af388e744f6d9a5ad1d6f1a29d0c310f82 (diff)
downloadevolution-f939a483d238ca529af4e2cbb03b3513d87b6ea8.tar.gz
I#2326 - RSS: Limit re-download on content change, if possible
Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/2326
-rw-r--r--src/modules/rss/camel-rss-store-summary.c106
-rw-r--r--src/modules/rss/camel-rss-store-summary.h12
-rw-r--r--src/modules/rss/camel/camel-rss-folder.c62
-rw-r--r--src/modules/rss/e-rss-parser.c5
-rw-r--r--src/modules/rss/evolution/e-rss-shell-view-extension.c2
5 files changed, 182 insertions, 5 deletions
diff --git a/src/modules/rss/camel-rss-store-summary.c b/src/modules/rss/camel-rss-store-summary.c
index ec9a6bf431..f4683d1f4f 100644
--- a/src/modules/rss/camel-rss-store-summary.c
+++ b/src/modules/rss/camel-rss-store-summary.c
@@ -34,6 +34,8 @@ typedef struct _RssFeed {
gchar *href;
gchar *display_name;
gchar *icon_filename;
+ gchar *last_etag;
+ gchar *last_modified;
CamelRssContentType content_type;
guint32 total_count;
guint32 unread_count;
@@ -216,6 +218,8 @@ camel_rss_store_summary_load (CamelRssStoreSummary *self,
feed->href = g_key_file_get_string (key_file, group, "href", NULL);
feed->display_name = g_key_file_get_string (key_file, group, "display-name", NULL);
feed->icon_filename = g_key_file_get_string (key_file, group, "icon-filename", NULL);
+ feed->last_etag = g_key_file_get_string (key_file, group, "last-etag", NULL);
+ feed->last_modified = g_key_file_get_string (key_file, group, "last-modified", NULL);
feed->content_type = g_key_file_get_integer (key_file, group, "content-type", NULL);
feed->total_count = (guint32) g_key_file_get_uint64 (key_file, group, "total-count", NULL);
feed->unread_count = (guint32) g_key_file_get_uint64 (key_file, group, "unread-count", NULL);
@@ -291,6 +295,8 @@ camel_rss_store_summary_save (CamelRssStoreSummary *self,
g_key_file_set_string (key_file, group, "href", feed->href);
g_key_file_set_string (key_file, group, "display-name", feed->display_name);
g_key_file_set_string (key_file, group, "icon-filename", feed->icon_filename ? feed->icon_filename : "");
+ g_key_file_set_string (key_file, group, "last-etag", feed->last_etag ? feed->last_etag : "");
+ g_key_file_set_string (key_file, group, "last-modified", feed->last_modified ? feed->last_modified : "");
g_key_file_set_integer (key_file, group, "content-type", feed->content_type);
g_key_file_set_uint64 (key_file, group, "total-count", feed->total_count);
g_key_file_set_uint64 (key_file, group, "unread-count", feed->unread_count);
@@ -850,3 +856,103 @@ camel_rss_store_summary_set_last_updated (CamelRssStoreSummary *self,
camel_rss_store_summary_unlock (self);
}
+
+const gchar *
+camel_rss_store_summary_get_last_etag (CamelRssStoreSummary *self,
+ const gchar *id)
+{
+ RssFeed *feed;
+ const gchar *result = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_RSS_STORE_SUMMARY (self), NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ camel_rss_store_summary_lock (self);
+
+ feed = g_hash_table_lookup (self->priv->feeds, id);
+ if (feed)
+ result = feed->last_etag;
+
+ camel_rss_store_summary_unlock (self);
+
+ return result;
+}
+
+void
+camel_rss_store_summary_set_last_etag (CamelRssStoreSummary *self,
+ const gchar *id,
+ const gchar *last_etag)
+{
+ RssFeed *feed;
+ gboolean changed = FALSE;
+
+ g_return_if_fail (CAMEL_IS_RSS_STORE_SUMMARY (self));
+ g_return_if_fail (id != NULL);
+
+ camel_rss_store_summary_lock (self);
+
+ feed = g_hash_table_lookup (self->priv->feeds, id);
+ if (feed) {
+ if (g_strcmp0 (feed->last_etag, last_etag) != 0) {
+ g_free (feed->last_etag);
+ feed->last_etag = g_strdup (last_etag);
+ self->priv->dirty = TRUE;
+ changed = TRUE;
+ }
+ }
+
+ camel_rss_store_summary_unlock (self);
+
+ if (changed)
+ camel_rss_store_summary_schedule_feed_changed (self, id);
+}
+
+const gchar *
+camel_rss_store_summary_get_last_modified (CamelRssStoreSummary *self,
+ const gchar *id)
+{
+ RssFeed *feed;
+ const gchar *result = NULL;
+
+ g_return_val_if_fail (CAMEL_IS_RSS_STORE_SUMMARY (self), NULL);
+ g_return_val_if_fail (id != NULL, NULL);
+
+ camel_rss_store_summary_lock (self);
+
+ feed = g_hash_table_lookup (self->priv->feeds, id);
+ if (feed)
+ result = feed->last_modified;
+
+ camel_rss_store_summary_unlock (self);
+
+ return result;
+}
+
+void
+camel_rss_store_summary_set_last_modified (CamelRssStoreSummary *self,
+ const gchar *id,
+ const gchar *last_modified)
+{
+ RssFeed *feed;
+ gboolean changed = FALSE;
+
+ g_return_if_fail (CAMEL_IS_RSS_STORE_SUMMARY (self));
+ g_return_if_fail (id != NULL);
+
+ camel_rss_store_summary_lock (self);
+
+ feed = g_hash_table_lookup (self->priv->feeds, id);
+ if (feed) {
+ if (g_strcmp0 (feed->last_modified, last_modified) != 0) {
+ g_free (feed->last_modified);
+ feed->last_modified = g_strdup (last_modified);
+ self->priv->dirty = TRUE;
+ changed = TRUE;
+ }
+ }
+
+ camel_rss_store_summary_unlock (self);
+
+ if (changed)
+ camel_rss_store_summary_schedule_feed_changed (self, id);
+}
diff --git a/src/modules/rss/camel-rss-store-summary.h b/src/modules/rss/camel-rss-store-summary.h
index 9c1b2b36e0..2272a8f429 100644
--- a/src/modules/rss/camel-rss-store-summary.h
+++ b/src/modules/rss/camel-rss-store-summary.h
@@ -110,6 +110,18 @@ gint64 camel_rss_store_summary_get_last_updated(CamelRssStoreSummary *self,
void camel_rss_store_summary_set_last_updated(CamelRssStoreSummary *self,
const gchar *id,
gint64 last_updated);
+const gchar * camel_rss_store_summary_get_last_etag (CamelRssStoreSummary *self,
+ const gchar *id);
+void camel_rss_store_summary_set_last_etag (CamelRssStoreSummary *self,
+ const gchar *id,
+ const gchar *last_etag);
+const gchar * camel_rss_store_summary_get_last_modified
+ (CamelRssStoreSummary *self,
+ const gchar *id);
+void camel_rss_store_summary_set_last_modified
+ (CamelRssStoreSummary *self,
+ const gchar *id,
+ const gchar *last_modified);
G_END_DECLS
diff --git a/src/modules/rss/camel/camel-rss-folder.c b/src/modules/rss/camel/camel-rss-folder.c
index 13a783efd7..d6bd517be0 100644
--- a/src/modules/rss/camel/camel-rss-folder.c
+++ b/src/modules/rss/camel/camel-rss-folder.c
@@ -240,6 +240,8 @@ rss_folder_refresh_info_sync (CamelFolder *folder,
CamelFolderChangeInfo *changes = NULL;
CamelSession *session;
gchar *href;
+ gchar *last_etag;
+ gchar *last_modified;
gint64 last_updated;
gboolean success = TRUE;
@@ -260,14 +262,18 @@ rss_folder_refresh_info_sync (CamelFolder *folder,
camel_rss_store_summary_lock (rss_store_summary);
href = g_strdup (camel_rss_store_summary_get_href (rss_store_summary, self->priv->id));
+ last_etag = g_strdup (camel_rss_store_summary_get_last_etag (rss_store_summary, self->priv->id));
+ last_modified = g_strdup (camel_rss_store_summary_get_last_modified (rss_store_summary, self->priv->id));
last_updated = camel_rss_store_summary_get_last_updated (rss_store_summary, self->priv->id);
camel_rss_store_summary_unlock (rss_store_summary);
if (href && *href) {
SoupSession *soup_session;
+ SoupMessageHeaders *request_headers;
SoupMessage *message;
GBytes *bytes;
+ GError *local_error = NULL;
message = soup_message_new (SOUP_METHOD_GET, href);
if (!message) {
@@ -290,10 +296,22 @@ rss_folder_refresh_info_sync (CamelFolder *folder,
g_object_unref (logger);
}
- bytes = soup_session_send_and_read (soup_session, message, cancellable, error);
+ request_headers = soup_message_get_request_headers (message);
+
+ soup_message_headers_append (request_headers, "Connection", "close");
+
+ if (last_etag && *last_etag)
+ soup_message_headers_append (request_headers, "If-None-Match", last_etag);
+ else if (last_modified && *last_modified)
+ soup_message_headers_append (request_headers, "If-Modified-Since", last_modified);
- if (bytes) {
+ bytes = soup_session_send_and_read (soup_session, message, cancellable, &local_error);
+
+ if (soup_message_get_status (message) == SOUP_STATUS_NOT_MODIFIED) {
+ g_clear_error (&local_error);
+ } else if (bytes) {
GSList *feeds = NULL;
+ gboolean save_summary = FALSE;
success = SOUP_STATUS_IS_SUCCESSFUL (soup_message_get_status (message));
@@ -392,13 +410,49 @@ rss_folder_refresh_info_sync (CamelFolder *folder,
camel_rss_store_summary_set_last_updated (rss_store_summary, self->priv->id, max_last_modified);
camel_rss_store_summary_unlock (rss_store_summary);
- success = camel_rss_store_summary_save (rss_store_summary, error);
+ save_summary = TRUE;
}
}
g_slist_free_full (feeds, e_rss_feed_free);
+
+ if (success) {
+ SoupMessageHeaders *response_headers;
+
+ response_headers = soup_message_get_response_headers (message);
+
+ if (response_headers) {
+ const gchar *tmp;
+
+ camel_rss_store_summary_lock (rss_store_summary);
+
+ tmp = soup_message_headers_get_one (response_headers, "ETag");
+ /* ignore weak ETag-s */
+ if (tmp && (g_ascii_strncasecmp (tmp, "W/", 2) == 0 || g_ascii_strncasecmp (tmp, "\"W/", 3) == 0))
+ tmp = NULL;
+ if (tmp && !*tmp)
+ tmp = NULL;
+
+ camel_rss_store_summary_set_last_etag (rss_store_summary, self->priv->id, tmp);
+
+ tmp = soup_message_headers_get_one (response_headers, "Last-Modified");
+ if (tmp && !*tmp)
+ tmp = NULL;
+
+ camel_rss_store_summary_set_last_modified (rss_store_summary, self->priv->id, tmp);
+
+ camel_rss_store_summary_unlock (rss_store_summary);
+
+ save_summary = TRUE;
+ }
+ }
+
+ if (success && save_summary)
+ success = camel_rss_store_summary_save (rss_store_summary, error);
} else {
success = FALSE;
+ if (local_error)
+ g_propagate_error (error, local_error);
}
g_clear_pointer (&bytes, g_bytes_unref);
@@ -409,6 +463,8 @@ rss_folder_refresh_info_sync (CamelFolder *folder,
success = FALSE;
}
+ g_free (last_modified);
+ g_free (last_etag);
g_free (href);
if (changes) {
diff --git a/src/modules/rss/e-rss-parser.c b/src/modules/rss/e-rss-parser.c
index 54b5a9bfc8..3bc0a7c329 100644
--- a/src/modules/rss/e-rss-parser.c
+++ b/src/modules/rss/e-rss-parser.c
@@ -592,11 +592,12 @@ e_rss_parser_parse (const gchar *xml,
xmlDoc *doc;
xmlNodePtr root;
- g_return_val_if_fail (xml != NULL, FALSE);
-
if (out_feeds)
*out_feeds = NULL;
+ if (!xml || !xml_len)
+ return FALSE;
+
doc = e_xml_parse_data (xml, xml_len);
if (!doc)
diff --git a/src/modules/rss/evolution/e-rss-shell-view-extension.c b/src/modules/rss/evolution/e-rss-shell-view-extension.c
index ecb5ef6cdf..948bd4eb61 100644
--- a/src/modules/rss/evolution/e-rss-shell-view-extension.c
+++ b/src/modules/rss/evolution/e-rss-shell-view-extension.c
@@ -124,6 +124,8 @@ action_rss_mail_folder_reload_cb (GtkAction *action,
g_object_get (store, "summary", &store_summary, NULL);
camel_rss_store_summary_set_last_updated (store_summary, folder_path, 0);
+ camel_rss_store_summary_set_last_etag (store_summary, folder_path, NULL);
+ camel_rss_store_summary_set_last_modified (store_summary, folder_path, NULL);
camel_store_get_folder (store, folder_path, CAMEL_STORE_FOLDER_NONE, G_PRIORITY_DEFAULT, NULL,
e_rss_mail_folder_reload_got_folder_cb, shell_view);