Your message dated Mon, 13 Mar 2023 21:18:22 +0000
with message-id <e1pbpyk-00br9b...@respighi.debian.org>
and subject line unblock liferea
has caused the Debian Bug report #1032903,
regarding unblock: liferea/1.14.1-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact ow...@bugs.debian.org
immediately.)


-- 
1032903: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032903
Debian Bug Tracking System
Contact ow...@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian....@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: life...@packages.debian.org
Control: affects -1 + src:liferea

Please unblock package liferea

[ Reason ]

A CVE was discovered in liferea and upstream quickly released a new
version including the fix. The new version also fixes a crash on
double free. Unfortunately it also included one more less important
improvement and an updated translation. Considering my options, I
decided it was best to upload the new version instead of only fixing
the CVE.

https://security-tracker.debian.org/tracker/CVE-2023-1350

[ Impact ]

The CVE is about a Remote Code Excecution of RSS feed information when
the user has opted-in to "Extract full content from HTML5 and Google
AMP". I believe that's pretty bad, but luckily it's not the default.

[ Tests ]

liferea doesn't have autopkgtests (yet), but I do activate the
upstream tests during build. Unfortunately, that currently fails
(because liferea isn't installed during build and if that's worked
around something fails due to being root; sorry, haven't fixed that
yet), but I ran the tests locally and then all regular tests pass. The
memtest fails in the same way as before. I also eat my own dogfood as
I'm a user of liferea and have the binaries installed since I built
them.

[ Risks ]

In the end, the changes are a bit more than trivial, but the delta in
this release is targetted to specific issues. I have a good relation
with upstream and he even supported me in the discussion with the
security team. Unfortunately, liferea isn't a leaf package as the
bfh-desktop (new in bookworm) and progress-linux-desktop (already in
bullseye) depend on it.

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]

I recommend viewing the debdiff with the following filter to ignore
upstream workflow items, the translation update and additional test
cases added for the purpose of testing the fix:

filterdiff -x '*/.gitignore' -x '*/.github/workflows/cb.yml' -x '*/po/fr.po' -x 
'*/src/tests' liferea_1.14.1-1.debdiff

unblock liferea/1.14.1-1

Paul
diff -Nru liferea-1.14.0/ChangeLog liferea-1.14.1/ChangeLog
--- liferea-1.14.0/ChangeLog    2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/ChangeLog    2023-03-12 21:00:51.000000000 +0100
@@ -1,3 +1,17 @@
+2023-03-12  Lars Windolf <lars.wind...@gmx.de>
+
+       Version 1.14.1
+
+       * Fixes CVE-2023-1350: RCE vulnerability on feed enrichment
+         (patch by Alexander Erwin Ittner)
+
+       * Fixes #1200: Crash on double free
+         (mozbugbox)
+
+       * Improve #1192 be reordering widget creation order
+         (Lars Windolf)
+
+
 2023-01-10  Lars Windolf <lars.wind...@gmx.de>
 
        Version 1.14.0
diff -Nru liferea-1.14.0/configure.ac liferea-1.14.1/configure.ac
--- liferea-1.14.0/configure.ac 2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/configure.ac 2023-03-12 21:00:51.000000000 +0100
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 
-AC_INIT([liferea],[1.14.0],[liferea-de...@lists.sourceforge.net])
+AC_INIT([liferea],[1.14.1],[liferea-de...@lists.sourceforge.net])
 AC_CANONICAL_HOST
 AC_CONFIG_SRCDIR([src/feedlist.c])
 
diff -Nru liferea-1.14.0/debian/changelog liferea-1.14.1/debian/changelog
--- liferea-1.14.0/debian/changelog     2023-01-15 21:14:44.000000000 +0100
+++ liferea-1.14.1/debian/changelog     2023-03-12 21:32:33.000000000 +0100
@@ -1,3 +1,12 @@
+liferea (1.14.1-1) unstable; urgency=medium
+
+  * New upstream version 1.14.1
+    Contains fix for CVE-2023-1350 which is a RCE when the option "Extract
+    full content from HTML5 and Google AMP" is enable on a feed (Closes:
+    #1032822)
+
+ -- Paul Gevers <elb...@debian.org>  Sun, 12 Mar 2023 21:32:33 +0100
+
 liferea (1.14.0-1) unstable; urgency=medium
 
   * New upstream version 1.14.0
diff -Nru liferea-1.14.0/.github/workflows/cb.yml 
liferea-1.14.1/.github/workflows/cb.yml
--- liferea-1.14.0/.github/workflows/cb.yml     2023-01-10 21:12:42.000000000 
+0100
+++ liferea-1.14.1/.github/workflows/cb.yml     2023-03-12 21:00:51.000000000 
+0100
@@ -24,7 +24,7 @@
 
     - run: |
        sudo apt-get update -qq
-       sudo apt-get install -y -qq libxml2-dev libxslt1-dev libsqlite3-dev 
libwebkit2gtk-4.0-dev libjson-glib-dev libgirepository1.0-dev libpeas-dev 
gsettings-desktop-schemas-dev python3 libtool intltool valgrind libfribidi-dev 
gla11y
+       sudo apt-get install -y -qq libxml2-dev libxslt1-dev libsqlite3-dev 
libwebkit2gtk-4.0-dev libjson-glib-dev libgirepository1.0-dev libpeas-dev 
gsettings-desktop-schemas-dev python3 libtool intltool valgrind libfribidi-dev 
gla11y appstream-util desktop-file-utils
        mkdir inst
 
     - run: |
@@ -35,6 +35,8 @@
     - run: make && make install
     - run: sudo cp net.sf.liferea.gschema.xml /usr/share/glib-2.0/schemas
     - run: sudo /usr/bin/glib-compile-schemas /usr/share/glib-2.0/schemas/
-    - run: ls -l /usr/share/glib-2.0/schemas 
+    - run: ls -l /usr/share/glib-2.0/schemas
     - run: cd src/tests && make test
     - run: cd src/tests && ./memcheck.sh parse_xml parse_date
+    - run: desktop-file-validate net.sourceforge.liferea.desktop
+    - run: appstream-util validate net.sourceforge.liferea.appdata.xml
diff -Nru liferea-1.14.0/.gitignore liferea-1.14.1/.gitignore
--- liferea-1.14.0/.gitignore   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/.gitignore   2023-03-12 21:00:51.000000000 +0100
@@ -50,8 +50,9 @@
 src/Liferea-3.0.typelib
 src/tests/favicon
 src/tests/html_auto
-src/tests/parse_html
 src/tests/parse_date
+src/tests/parse_html
+src/tests/parse_rss
 src/tests/parse_xml
 src/tests/social
 xslt/*.xml
diff -Nru liferea-1.14.0/net.sourceforge.liferea.appdata.xml.in 
liferea-1.14.1/net.sourceforge.liferea.appdata.xml.in
--- liferea-1.14.0/net.sourceforge.liferea.appdata.xml.in       2023-01-10 
21:12:42.000000000 +0100
+++ liferea-1.14.1/net.sourceforge.liferea.appdata.xml.in       2023-03-12 
21:00:51.000000000 +0100
@@ -201,8 +201,6 @@
            Now Liferea will never allow the panes to be smaller than 5% in 
height or width
            regarding to there orientation. If a pane is smaller than 5% 
height/width it will be
            set to 30% width or 50% height on startup.
-
-           The intention here is that panes are never invisible after startup.
         </li>
         <li>
           Wait for network to be fully available before updating: sometimes 
when real internet
diff -Nru liferea-1.14.0/po/fr.po liferea-1.14.1/po/fr.po
--- liferea-1.14.0/po/fr.po     2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/po/fr.po     2023-03-12 21:00:51.000000000 +0100
@@ -13,15 +13,15 @@
 "Project-Id-Version: Liferea 1.8\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-10-26 01:24+0200\n"
-"PO-Revision-Date: 2022-09-16 10:26+0200\n"
-"Last-Translator: Guillaume Bernard <associati...@guillaume-bernard.fr>\n"
+"PO-Revision-Date: 2023-01-13 12:16+0100\n"
+"Last-Translator: Irénée Thirion <irenee.thirion@e.email>\n"
 "Language-Team: français <>\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 3.1.1\n"
+"X-Generator: Poedit 3.2.2\n"
 
 #: ../net.sourceforge.liferea.desktop.in.h:1 ../src/liferea_application.c:349
 #: ../glade/mainwindow.ui.h:1
@@ -439,18 +439,17 @@
 msgstr "La connexion a échoué !"
 
 #: ../src/fl_sources/google_source.c:404
-#, fuzzy
 msgid "Google Reader API"
-msgstr "Google Reader"
+msgstr "API Google Reader"
 
 #: ../src/fl_sources/google_source_feed.c:159
-#, fuzzy
 msgid "Could not parse JSON returned by Google Reader API!"
-msgstr "Impossible d’analyser le JSON envoyé par l’API Reedah !"
+msgstr ""
+"Impossible d’analyser le fichier JSON retourné par l’API Google Reader !"
 
 #: ../src/fl_sources/node_source.c:117
 msgid "Miniflux"
-msgstr ""
+msgstr "Miniflux"
 
 #: ../src/fl_sources/node_source.c:332
 msgid "No feed list source types found!"
@@ -717,30 +716,28 @@
 
 #. http 5xx server errors
 #: ../src/net.c:493
-#, fuzzy
 msgid "Internal Server Error"
-msgstr "Erreur du serveur"
+msgstr "Erreur interne du serveur"
 
 #: ../src/net.c:494
 msgid "Not Implemented"
-msgstr ""
+msgstr "Non implémenté"
 
 #: ../src/net.c:495
 msgid "Bad Gateway"
-msgstr ""
+msgstr "Mauvaise passerelle"
 
 #: ../src/net.c:496
-#, fuzzy
 msgid "Service Unavailable"
-msgstr "« %s » n’est pas disponible"
+msgstr "Service indisponible"
 
 #: ../src/net.c:497
 msgid "Gateway Timeout"
-msgstr ""
+msgstr "Délai d’attente de la passerelle écoulé"
 
 #: ../src/net.c:498
 msgid "HTTP Version Not Supported"
-msgstr ""
+msgstr "Version HTTP non prise en charge"
 
 #: ../src/net.c:503
 msgid "There was an internal error in the update process"
@@ -819,9 +816,8 @@
 msgstr "Le corps de l’élément"
 
 #: ../src/rule.c:277
-#, fuzzy
 msgid "Item author"
-msgstr "Le corps de l’élément"
+msgstr "L’auteur de l’élément"
 
 #: ../src/rule.c:278
 msgid "Read status"
@@ -1091,14 +1087,14 @@
 msgstr "Aucun élément n’a été sélectionné"
 
 #: ../src/ui/liferea_browser.c:482
-#, fuzzy
 msgid "Content download failed! Try disabling reader mode."
-msgstr "Impossible de télécharger le contenu."
+msgstr ""
+"Impossible de télécharger le contenu. Essayez de désactiver le mode lecture."
 
 #: ../src/ui/liferea_browser.c:495
-#, fuzzy
 msgid "Content extraction failed! Try disabling reader mode."
-msgstr "Impossible d’extraire le contenu."
+msgstr ""
+"Impossible d’extraire le contenu. Essayez de désactiver le mode lecture."
 
 #: ../src/ui/liferea_shell.c:409
 #, c-format
@@ -1325,9 +1321,8 @@
 msgstr "Programme"
 
 #: ../src/ui/rule_editor.c:257
-#, fuzzy
 msgid "Remove"
-msgstr "_Supprimer"
+msgstr "Supprimer"
 
 #: ../src/ui/search_dialog.c:106
 msgid "Saved Search"
@@ -1504,15 +1499,16 @@
 "de maintenant."
 
 #: ../glade/google_source.ui.h:1
-#, fuzzy
 msgid "Add Google Reader API Account"
-msgstr "Ajouter un compte Google Reader"
+msgstr "Ajouter un compte API Google Reader"
 
 #: ../glade/google_source.ui.h:2
 msgid ""
 "Please enter the details of the new Google Reader API compatible "
 "subscription."
 msgstr ""
+"Veuillez saisir les détails du nouvel abonnement compatible avec l’API "
+"Google Reader."
 
 #: ../glade/google_source.ui.h:3 ../glade/reedah_source.ui.h:3
 #: ../glade/theoldreader_source.ui.h:3 ../glade/ttrss_source.ui.h:4
@@ -1525,14 +1521,12 @@
 msgstr "Nom d’_utilisateur (e-mail)"
 
 #: ../glade/google_source.ui.h:5
-#, fuzzy
 msgid "_Server"
-msgstr "URL du _serveur"
+msgstr "_Serveur"
 
 #: ../glade/google_source.ui.h:6
-#, fuzzy
 msgid "_Name"
-msgstr "_Nom du flux"
+msgstr "_Nom"
 
 #: ../glade/liferea_menu.ui.h:1
 msgid "_Subscriptions"
@@ -1886,9 +1880,8 @@
 "recherche."
 
 #: ../glade/prefs.ui.h:22
-#, fuzzy
 msgid "Ask for confirmation when marking all items as read."
-msgstr "Demander confirmation pour marquer tous les éléments comme lus"
+msgstr "Demander confirmation pour marquer tous les éléments comme lus."
 
 #: ../glade/prefs.ui.h:23
 msgid "Web Integration"
diff -Nru liferea-1.14.0/src/common.c liferea-1.14.1/src/common.c
--- liferea-1.14.0/src/common.c 2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/common.c 2023-03-12 21:00:51.000000000 +0100
@@ -138,7 +138,9 @@
        g_assert (NULL != url);
 
        /* xmlURIEscape returns NULL if spaces are in the URL,
-          so we need to replace them first (see SF #2965158) */
+          so we need to replace them first (see SF #2965158).
+          TODO: perhaps replace xmlURIEscape with g_uri_escape_string ?
+        */
        tmp = (xmlChar *)common_strreplace (g_strdup ((gchar *)url), " ", 
"%20");
        result = xmlURIEscape (tmp);
        g_free (tmp);
diff -Nru liferea-1.14.0/src/feed.c liferea-1.14.1/src/feed.c
--- liferea-1.14.0/src/feed.c   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/feed.c   2023-03-12 21:00:51.000000000 +0100
@@ -460,7 +460,7 @@
                NODE_CAPABILITY_EXPORT |
                NODE_CAPABILITY_EXPORT_ITEMS,
                "feed",         /* not used, feed format ids are used instead */
-               NULL,
+               ICON_DEFAULT,
                feed_import,
                feed_export,
                feed_load,
@@ -472,7 +472,6 @@
                feed_properties,
                feed_free
        };
-       nti.icon = icon_get (ICON_DEFAULT);
 
        return &nti;
 }
diff -Nru liferea-1.14.0/src/feed_parser.h liferea-1.14.1/src/feed_parser.h
--- liferea-1.14.0/src/feed_parser.h    2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/feed_parser.h    2023-03-12 21:00:51.000000000 +0100
@@ -1,7 +1,7 @@
 /**
  * @file feed_parser.h  parsing of different feed formats
  *
- * Copyright (C) 2008-2021 Lars Windolf <lars.wind...@gmx.de>
+ * Copyright (C) 2008-2023 Lars Windolf <lars.wind...@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@
        subscriptionPtr subscription;           /**< the subscription the feed 
belongs to (optional) */
        feedPtr         feed;                   /**< the feed structure to fill 
*/
        GList           *items;                 /**< the list of new items */
-       struct item     *item;                  /**< the item currently parsed 
(or NULL) */
+       itemPtr         item;                   /**< the item currently parsed 
(or NULL) */
 
        GHashTable      *tmpdata;               /**< tmp data hash used during 
stateful parsing */
 
diff -Nru liferea-1.14.0/src/fl_sources/node_source.c 
liferea-1.14.1/src/fl_sources/node_source.c
--- liferea-1.14.0/src/fl_sources/node_source.c 2023-01-10 21:12:42.000000000 
+0100
+++ liferea-1.14.1/src/fl_sources/node_source.c 2023-03-12 21:00:51.000000000 
+0100
@@ -1,7 +1,7 @@
 /*
  * @file node_source.c  generic node source provider implementation
  *
- * Copyright (C) 2005-2022 Lars Windolf <lars.wind...@gmx.de>
+ * Copyright (C) 2005-2023 Lars Windolf <lars.wind...@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -622,7 +622,7 @@
                /* derive the node source node type from the folder node type */
                nodeType = (nodeTypePtr) g_new0 (struct nodeType, 1);
                nodeType->id                    = "source";
-               nodeType->icon                  = icon_get (ICON_DEFAULT);
+               nodeType->icon                  = ICON_DEFAULT;
                nodeType->capabilities          = 
NODE_CAPABILITY_SHOW_UNREAD_COUNT |
                                                  
NODE_CAPABILITY_SHOW_ITEM_FAVICONS |
                                                  NODE_CAPABILITY_UPDATE_CHILDS 
|
diff -Nru liferea-1.14.0/src/folder.c liferea-1.14.1/src/folder.c
--- liferea-1.14.0/src/folder.c 2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/folder.c 2023-03-12 21:00:51.000000000 +0100
@@ -119,7 +119,7 @@
                NODE_CAPABILITY_UPDATE_CHILDS |
                NODE_CAPABILITY_EXPORT,
                "folder",
-               NULL,
+               ICON_FOLDER,
                folder_import,
                folder_export,
                folder_load,
@@ -131,7 +131,6 @@
                feed_list_view_rename_node,
                NULL
        };
-       fnti.icon = icon_get (ICON_FOLDER);
 
        return &fnti;
 }
@@ -150,7 +149,7 @@
                NODE_CAPABILITY_UPDATE_CHILDS |
                NODE_CAPABILITY_EXPORT,
                "root",
-               NULL,           /* and no need for an icon */
+               0,              /* and no need for an icon */
                folder_import,
                folder_export,
                folder_load,
diff -Nru liferea-1.14.0/src/html.c liferea-1.14.1/src/html.c
--- liferea-1.14.0/src/html.c   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/html.c   2023-03-12 21:00:51.000000000 +0100
@@ -221,7 +221,7 @@
 GSList *
 html_auto_discover_feed (const gchar* data, const gchar *defaultBaseUri)
 {
-       GSList          *iter, *links = NULL;
+       GSList          *iter, *links = NULL, *valid_links = NULL;
        gchar           *baseUri = NULL;
        xmlDocPtr       doc;
        xmlNodePtr      node, root;
@@ -253,17 +253,25 @@
        /* Turn relative URIs into absolute URIs */
        iter = links;
        while (iter) {
-               gchar *tmp = iter->data;
-               iter->data = common_build_url (tmp, baseUri);
-               g_free (tmp);
-               debug1 (DEBUG_UPDATE, "search result: %s", (gchar *)iter->data);
+               gchar *tmp = (gchar *)common_build_url (iter->data, baseUri);
+
+               /* We expect only relative URIs starting with '/' or absolute 
URIs starting with 'http://' or 'https://' */
+               if ('h' == tmp[0] || '/' == tmp[0]) {
+                       debug1 (DEBUG_UPDATE, "search result: %s", (gchar 
*)iter->data);
+                       valid_links = g_slist_append (valid_links, tmp);
+               } else {
+                       debug1 (DEBUG_UPDATE, "html_auto_discover_feed: 
discarding invalid URL %s", tmp ? tmp : "NULL");
+                       g_free (tmp);
+               }
+
                iter = g_slist_next (iter);
        }
+       g_slist_free_full (links, g_free);
 
        g_free (baseUri);
        xmlFreeDoc (doc);
 
-       return links;
+       return valid_links;
 }
 
 GSList *
diff -Nru liferea-1.14.0/src/item.c liferea-1.14.1/src/item.c
--- liferea-1.14.0/src/item.c   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/item.c   2023-03-12 21:00:51.000000000 +0100
@@ -1,7 +1,7 @@
 /**
  * @file item.c item handling
  *
- * Copyright (C) 2003-2021 Lars Windolf <lars.wind...@gmx.de>
+ * Copyright (C) 2003-2023 Lars Windolf <lars.wind...@gmx.de>
  * Copyright (C) 2004-2006 Nathan J. Conrad <t98...@users.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -34,27 +34,55 @@
 #include "render.h"
 #include "xml.h"
 
-itemPtr
-item_new (void)
+G_DEFINE_TYPE (LifereaItem, liferea_item, G_TYPE_OBJECT);
+
+static void
+liferea_item_finalize (GObject *object)
 {
-       itemPtr         item;
+       LifereaItem *item = LIFEREA_ITEM (object);
+
+       g_free (item->title);
+       g_free (item->source);
+       g_free (item->sourceId);
+       g_free (item->description);
+       g_free (item->commentFeedId);
+       g_free (item->nodeId);
+       g_free (item->parentNodeId);
 
-       item = g_new0 (struct item, 1);
+       g_assert (NULL == item->tmpdata);       /* should be free after 
rendering */
+       metadata_list_free (item->metadata);
+}
+
+static void
+liferea_item_class_init (LifereaItemClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = liferea_item_finalize;
+}
+
+static void
+liferea_item_init (LifereaItem *item)
+{
        item->popupStatus = TRUE;
+}
 
-       return item;
+LifereaItem *
+item_new (void)
+{
+       return LIFEREA_ITEM (g_object_new (LIFEREA_ITEM_TYPE, NULL));
 }
 
-itemPtr
+LifereaItem *
 item_load (gulong id)
 {
        return db_item_load (id);
 }
 
-itemPtr
-item_copy (itemPtr item)
+LifereaItem *
+item_copy (LifereaItem *item)
 {
-       itemPtr copy = item_new ();
+       LifereaItem *copy = item_new ();
 
        item_set_title (copy, item->title);
        item_set_source (copy, item->source);
@@ -84,7 +112,7 @@
 }
 
 void
-item_set_title (itemPtr item, const gchar * title)
+item_set_title (LifereaItem *item, const gchar * title)
 {
        g_free (item->title);
 
@@ -95,7 +123,7 @@
 }
 
 void
-item_set_description (itemPtr item, const gchar *description)
+item_set_description (LifereaItem *item, const gchar *description)
 {
        if (!description)
                return;
@@ -109,39 +137,41 @@
 }
 
 void
-item_set_source (itemPtr item, const gchar * source)
+item_set_source (LifereaItem *item, const gchar * source)
 {
        g_free (item->source);
-       if (source)
+
+       /* We expect only relative URIs starting with '/' or absolute URIs 
starting with 'http://' or 'https://' */
+       if (source && ('/' == source[0] || 'h' == source[0]))
                item->source = g_strstrip (g_strdup (source));
        else
                item->source = NULL;
 }
 
 void
-item_set_id (itemPtr item, const gchar * id)
+item_set_id (LifereaItem *item, const gchar * id)
 {
        g_free (item->sourceId);
        item->sourceId = g_strdup (id);
 }
 
 void
-item_set_time (itemPtr item, gint64 time)
+item_set_time (LifereaItem *item, gint64 time)
 {
        item->time = time;
        if (item->time > 0)
                item->validTime = TRUE;
 }
 
-const gchar *  item_get_id(itemPtr item) { return item->sourceId; }
-const gchar *  item_get_title(itemPtr item) {return item->title; }
-const gchar *  item_get_description(itemPtr item) { return item->description; }
-const gchar *  item_get_source(itemPtr item) { return item->source; }
+const gchar *  item_get_id(LifereaItem *item) { return item->sourceId; }
+const gchar *  item_get_title(LifereaItem *item) {return item->title; }
+const gchar *  item_get_description(LifereaItem *item) { return 
item->description; }
+const gchar *  item_get_source(LifereaItem *item) { return item->source; }
 
 static GRegex *whitespace_strip_re = NULL;
 
 gchar *
-item_get_teaser (itemPtr item)
+item_get_teaser (LifereaItem *item)
 {
        gchar           *input, *tmpDesc;
        gchar           *teaser = NULL;
@@ -176,7 +206,7 @@
 }
 
 gchar *
-item_make_link (itemPtr item)
+item_make_link (LifereaItem *item)
 {
        const gchar     *src;
        gchar           *link;
@@ -202,7 +232,7 @@
 }
 
 const gchar *
-item_get_author(itemPtr item)
+item_get_author(LifereaItem *item)
 {
        gchar *author;
 
@@ -210,25 +240,8 @@
        return author;
 }
 
-void
-item_unload (itemPtr item)
-{
-       g_free (item->title);
-       g_free (item->source);
-       g_free (item->sourceId);
-       g_free (item->description);
-       g_free (item->commentFeedId);
-       g_free (item->nodeId);
-       g_free (item->parentNodeId);
-
-       g_assert (NULL == item->tmpdata);       /* should be free after 
rendering */
-       metadata_list_free (item->metadata);
-
-       g_free (item);
-}
-
 const gchar *
-item_get_base_url (itemPtr item)
+item_get_base_url (LifereaItem *item)
 {
        /* item->node is always the source node for the item
           never a search folder or folder */
@@ -236,7 +249,7 @@
 }
 
 void
-item_to_xml (itemPtr item, gpointer xmlNode)
+item_to_xml (LifereaItem *item, gpointer xmlNode)
 {
        xmlNodePtr      parentNode = (xmlNodePtr)xmlNode;
        xmlNodePtr      duplicatesNode;
@@ -293,7 +306,7 @@
                duplicates = iter = db_item_get_duplicates(item->sourceId);
                while (iter) {
                        gulong id = GPOINTER_TO_UINT (iter->data);
-                       itemPtr duplicate = item_load (id);
+                       LifereaItem * duplicate = item_load (id);
                        if (duplicate) {
                                nodePtr duplicateNode = node_from_id 
(duplicate->nodeId);
                                if (duplicateNode && (item->id != 
duplicate->id))
@@ -328,7 +341,7 @@
 }
 
 static const gchar *
-item_get_text_direction (itemPtr item)
+item_get_text_direction (LifereaItem *item)
 {
        if (item_get_title (item))
                return (common_get_text_direction (item_get_title (item)));
@@ -340,7 +353,7 @@
 }
 
 gchar *
-item_render (itemPtr item, guint viewMode)
+item_render (LifereaItem *item, guint viewMode)
 {
        renderParamPtr  params;
        gchar           *output = NULL, *baseUrl = NULL;
diff -Nru liferea-1.14.0/src/item.h liferea-1.14.1/src/item.h
--- liferea-1.14.0/src/item.h   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/item.h   2023-03-12 21:00:51.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * @file item.h item handling
  *
- * Copyright (C) 2003-2022 Lars Windolf <lars.wind...@gmx.de>
+ * Copyright (C) 2003-2023 Lars Windolf <lars.wind...@gmx.de>
  * Copyright (C) 2004-2006 Nathan J. Conrad <t98...@users.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -23,24 +23,27 @@
 #define _ITEM_H
 
 #include <glib.h>
+#include <glib-object.h>
 
-/* Currently Liferea knows only a single type of items used
-   for the itemset types feed, folder and search folder. So each
-   feed list type provider must provide it's data using the
-   item interface. */
-
-/* ------------------------------------------------------------ */
-/* item interface                                              */
-/* ------------------------------------------------------------ */
+/* Each feed/subscription type provider must provide it's data using `Item` */
+
+G_BEGIN_DECLS
+
+#define LIFEREA_ITEM_TYPE      (liferea_item_get_type ())
+G_DECLARE_FINAL_TYPE (LifereaItem, liferea_item, LIFEREA, ITEM, GObject)
 
 /*
  * An item stores a particular entry in a feed or a search.
+ *
  *  Each item belongs to an item set. An itemset is a collection
  *  of items. There are different item set types (e.g. feed,
- *  folder,vfolder or plugin). Each item has a source node.
+ *  folder, search folder or plugin). Each item has a source node.
  *  The item set node and the item source node is different
- *  for folders and vfolders. */
-typedef struct item {
+ *  for folders and search folders.
+ */
+struct _LifereaItem {
+       GObject parent_instance;
+
        gulong          id;                     /*<< internally unique item id 
*/
 
        /* those fields should not be accessed directly. Accessors are 
provided. */
@@ -75,7 +78,9 @@
        /* remote states used during sync of remote accounts */
        gboolean        remoteReadStatus;       /*<< TRUE if the remote copy of 
the item has been read */
        gboolean        remoteFlagStatus;       /*<< TRUE if the remote copy of 
the item has been flagged */
-} *itemPtr;
+};
+
+typedef struct _LifereaItem *itemPtr;
 
 /**
  * item_new: (skip)
@@ -83,7 +88,7 @@
  *
  * Returns: (transfer full): the new structure
  */
-itemPtr        item_new(void);
+LifereaItem *  item_new(void);
 
 /**
  * item_load: (skip)
@@ -95,7 +100,10 @@
  *
  * Returns: (transfer full) (nullable): item structure
  */
-itemPtr                item_load(gulong id);
+LifereaItem *  item_load(gulong id);
+
+// For legacy code let's keep item_unload()
+#define item_unload(a) g_object_unref(a)
 
 /**
  * item_copy: (skip)
@@ -107,7 +115,7 @@
  *
  * Returns: (transfer full): copy of the item.
  */
-itemPtr                item_copy(itemPtr item);
+LifereaItem *  item_copy(LifereaItem * item);
 
 /**
  * item_get_base_url: (skip)
@@ -117,27 +125,17 @@
  *
  * Returns: base URL
  */
-const gchar * item_get_base_url(itemPtr item);
-
-/**
- * item_unload: (skip)
- * @item:      the item to unload
- *
- * Free the memory used by an itempointer. The item needs to be
- * removed from the itemlist before calling this function.
- *
- */
-void   item_unload(itemPtr item);
+const gchar * item_get_base_url(LifereaItem *item);
 
 /* methods to access properties */
 /* Returns the id of item. */
-const gchar *  item_get_id(itemPtr item);
+const gchar *  item_get_id(LifereaItem *item);
 /* Returns the title of item. */
-const gchar *  item_get_title(itemPtr item);
+const gchar *  item_get_title(LifereaItem *item);
 /* Returns the description of item. */
-const gchar *  item_get_description(itemPtr item);
+const gchar *  item_get_description(LifereaItem *item);
 /* Returns the source of item. */
-const gchar *  item_get_source(itemPtr item);
+const gchar *  item_get_source(LifereaItem *item);
 
 /**
  * item_get_teaser: (skip)
@@ -147,7 +145,7 @@
  *
  * Returns: (transfer full): newly allocated string to be free'd using 
g_free() (or NULL)
  */
-gchar * item_get_teaser(itemPtr item);
+gchar * item_get_teaser(LifereaItem *item);
 
 /**
  * item_make_link: (skip)
@@ -157,7 +155,7 @@
  *
  * Returns: (transfer full): newly allocated URI to be free'd using g_free()
  */
-gchar *        item_make_link(itemPtr item);
+gchar *        item_make_link(LifereaItem *item);
 
 /**
  * item_get_author: (skip)
@@ -167,7 +165,7 @@
  *
  * Returns: pointer to string in GSList meta data
  */
-const gchar * item_get_author  (itemPtr item);
+const gchar * item_get_author(LifereaItem *item);
 
 /**
  * item_set_title: (skip)
@@ -176,7 +174,7 @@
  *
  * Sets the item title
  */
-void item_set_title(itemPtr item, const gchar * title);
+void item_set_title(LifereaItem *item, const gchar * title);
 
 /**
  * item_set_description: (skip)
@@ -187,7 +185,7 @@
  * will merge the new description against the old one deciding
  * on the best to keep.
  */
-void item_set_description (itemPtr item, const gchar *description);
+void item_set_description (LifereaItem *item, const gchar *description);
 
 /**
  * item_set_source: (skip)
@@ -196,7 +194,7 @@
  *
  * Sets the item source 
  */
-void item_set_source(itemPtr item, const gchar * source);
+void item_set_source(LifereaItem *item, const gchar * source);
 
 /**
  * item_set_id: (skip)
@@ -205,7 +203,7 @@
  *
  * Sets the item id 
  */
-void item_set_id (itemPtr item, const gchar * id);
+void item_set_id (LifereaItem *item, const gchar * id);
 
 /**
  * item_set_time: (skip)
@@ -215,7 +213,7 @@
  * Sets the item time. Always use this when a valid date was 
  * supplied for the item!
  */
-void item_set_time (itemPtr item, gint64 time);
+void item_set_time (LifereaItem *item, gint64 time);
 
 /**
  * item_to_xml: (skip)
@@ -225,7 +223,7 @@
  * Adds an XML node to the given item.
  *
  */
-void item_to_xml (itemPtr item, gpointer parentNode);
+void item_to_xml (LifereaItem *item, gpointer parentNode);
 
 /**
  * item_render: (skip)
@@ -236,6 +234,8 @@
  *
  * Returns XML string (to be free'd using g_free())
  */
-gchar * item_render (itemPtr item, guint viewMode);
+gchar * item_render (LifereaItem *item, guint viewMode);
+
+G_END_DECLS
 
-#endif
+#endif
\ No newline at end of file
diff -Nru liferea-1.14.0/src/itemlist.c liferea-1.14.1/src/itemlist.c
--- liferea-1.14.0/src/itemlist.c       2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/itemlist.c       2023-03-12 21:00:51.000000000 +0100
@@ -237,9 +237,9 @@
        if (itemlist->priv->deferredRemove) {
                itemlist->priv->deferredRemove = FALSE;
                itemlist_remove_item (item);
+       } else {
+               item_unload (item);
        }
-
-       item_unload (item);
 }
 
 static void
@@ -499,16 +499,8 @@
 
        while (iter) {
                itemPtr item = (itemPtr) iter->data;
-
-               if (itemlist->priv->selectedId != item->id) {
-                       /* don't call itemlist_remove_item() here, because it's 
to slow */
-                       itemview_remove_item (item);
-                       db_item_remove (item->id);
-               } else {
-                       /* go the normal and selection-safe way to avoid 
disturbing the user */
-                       itemlist_request_remove_item (item);
-               }
-               item_unload (item);
+               itemlist_request_remove_item (item);
+               db_item_remove (item->id);
                iter = g_list_next (iter);
        }
 
@@ -590,7 +582,7 @@
        }
 
        if (item)
-               item_unload (item);
+               g_object_unref (item);
 
        debug_end_measurement (DEBUG_GUI, "itemlist selection");
        debug_exit ("itemlist_selection_changed");
diff -Nru liferea-1.14.0/src/itemset.c liferea-1.14.1/src/itemset.c
--- liferea-1.14.0/src/itemset.c        2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/itemset.c        2023-03-12 21:00:51.000000000 +0100
@@ -44,7 +44,7 @@
                itemPtr item = item_load (GPOINTER_TO_UINT (iter->data));
                if (item) {
                        (*callback) (item, userdata);
-                       item_unload (item);
+                       g_object_unref (item);
                }
                iter = g_list_next (iter);
        }
diff -Nru liferea-1.14.0/src/newsbin.c liferea-1.14.1/src/newsbin.c
--- liferea-1.14.0/src/newsbin.c        2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/newsbin.c        2023-03-12 21:00:51.000000000 +0100
@@ -217,7 +217,7 @@
                                                  
NODE_CAPABILITY_SHOW_ITEM_COUNT |
                                                  NODE_CAPABILITY_EXPORT_ITEMS;
                nodeType->id                    = "newsbin";
-               nodeType->icon                  = icon_get (ICON_NEWSBIN);
+               nodeType->icon                  = ICON_NEWSBIN;
                nodeType->load                  = feed_get_node_type()->load;
                nodeType->import                = newsbin_import;
                nodeType->export                = newsbin_export;
diff -Nru liferea-1.14.0/src/node.c liferea-1.14.1/src/node.c
--- liferea-1.14.0/src/node.c   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/node.c   2023-03-12 21:00:51.000000000 +0100
@@ -43,6 +43,7 @@
 #include "date.h"
 #include "fl_sources/node_source.h"
 #include "ui/feed_list_view.h"
+#include "ui/icons.h"
 #include "ui/liferea_shell.h"
 
 static GHashTable *nodes = NULL;       /*<< node id -> node lookup table */
@@ -431,7 +432,7 @@
 node_get_icon (nodePtr node)
 {
        if (!node->icon)
-               return (gpointer) NODE_TYPE(node)->icon;
+               return (gpointer) icon_get (NODE_TYPE(node)->icon);
 
        return node->icon;
 }
diff -Nru liferea-1.14.0/src/node_type.h liferea-1.14.1/src/node_type.h
--- liferea-1.14.0/src/node_type.h      2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/node_type.h      2023-03-12 21:00:51.000000000 +0100
@@ -54,7 +54,7 @@
 typedef struct nodeType {
        gulong          capabilities;   /**< bitmask of node type capabilities 
*/
        const gchar     *id;            /**< type id (used for type attribute 
in OPML export) */
-       const GIcon     *icon;          /**< default icon for nodes of this 
type (if no favicon available) */
+       guint           icon;           /**< default icon for nodes of this 
type (if no favicon available) */
        
        /* For method documentation see the wrappers defined below! 
           All methods are mandatory for each node type. */
diff -Nru liferea-1.14.0/src/subscription.c liferea-1.14.1/src/subscription.c
--- liferea-1.14.0/src/subscription.c   2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/subscription.c   2023-03-12 21:00:51.000000000 +0100
@@ -282,6 +282,7 @@
                        subscription->updateState,
                        subscription->updateOptions
                );
+               update_request_allow_commands (request, TRUE);
 
                if (subscription_get_filter (subscription))
                        request->filtercmd = g_strdup (subscription_get_filter 
(subscription));
diff -Nru liferea-1.14.0/src/tests/Makefile.am 
liferea-1.14.1/src/tests/Makefile.am
--- liferea-1.14.0/src/tests/Makefile.am        2023-01-10 21:12:42.000000000 
+0100
+++ liferea-1.14.1/src/tests/Makefile.am        2023-03-12 21:00:51.000000000 
+0100
@@ -2,7 +2,7 @@
 
 noinst_PROGRAMS = $(TEST_PROGS)
 
-TEST_PROGS = parse_html favicon parse_date parse_xml social
+TEST_PROGS = parse_html favicon parse_date parse_rss parse_xml social
 
 test: $(TEST_PROGS)
        echo $(TEST_PROGS) |\
@@ -93,6 +93,9 @@
 parse_date_CFLAGS = $(AM_CPPFLAGS)
 parse_date_LDADD = $(favicon_LDADD)
 
+parse_rss_CFLAGS = $(AM_CPPFLAGS)
+parse_rss_LDADD = $(favicon_LDADD)
+
 parse_xml_CFLAGS = $(AM_CPPFLAGS)
 parse_xml_LDADD = $(favicon_LDADD)
 
diff -Nru liferea-1.14.0/src/tests/parse_html.c 
liferea-1.14.1/src/tests/parse_html.c
--- liferea-1.14.0/src/tests/parse_html.c       2023-01-10 21:12:42.000000000 
+0100
+++ liferea-1.14.1/src/tests/parse_html.c       2023-03-12 21:00:51.000000000 
+0100
@@ -1,7 +1,7 @@
 /**
- * @file html.c  Test cases for feed link auto discovery
+ * @file parse_html.c  Test cases for feed link auto discovery
  *
- * Copyright (C) 2014-2019 Lars Windolf <lars.wind...@gmx.de>
+ * Copyright (C) 2014-2023 Lars Windolf <lars.wind...@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@
 
 #include <glib.h>
 
+#include "debug.h"
 #include "html.h"
 
 /* We need two groups of autodiscovery test cases, one for the tag soup fuzzy
@@ -115,6 +116,13 @@
        NULL
 };
 
+// Injection via "|"" command must not result in command subscription
+gchar *tc_xml_rce[] = {
+       "<html><head><link rel=\"alternate\" type=\"application/rss+xml\" 
href=\"|date &gt;/tmp/bad-feed-discovery.txt\"></html>",
+       NULL,
+       NULL
+};
+
 /* HTML5 extraction test cases */
 
 gchar *tc_article[] = {
@@ -214,6 +222,9 @@
 {
        g_test_init (&argc, &argv, NULL);
 
+       if (argv[1] && g_str_equal (argv[1], "--debug"))
+               set_debug_level (DEBUG_UPDATE | DEBUG_HTML | DEBUG_PARSING);
+
        g_test_add_data_func ("/html/auto_discover_link_xml", &tc_xml, 
&tc_auto_discover_link);
        g_test_add_data_func ("/html/auto_discover_link_xml_base_url", 
&tc_xml_base_url, &tc_auto_discover_link);
        g_test_add_data_func ("/html/auto_discover_link_rss", &tc_rss, 
&tc_auto_discover_link);
@@ -225,6 +236,7 @@
        g_test_add_data_func ("/html/auto_discover_link_xml_atom", 
&tc_xml_atom, &tc_auto_discover_link);
        g_test_add_data_func ("/html/auto_discover_link_xml_atom2", 
&tc_xml_atom2, &tc_auto_discover_link);
        g_test_add_data_func ("/html/auto_discover_link_xml_atom3", 
&tc_xml_atom3, &tc_auto_discover_link);
+       g_test_add_data_func ("/html/auto_discover_link_xml_rce", &tc_xml_rce, 
&tc_auto_discover_link);
 
        g_test_add_data_func ("/html/html5_extract_article", &tc_article, 
&tc_get_article);
        g_test_add_data_func ("/html/html5_extract_article_main", 
&tc_article_main, &tc_get_article);
diff -Nru liferea-1.14.0/src/tests/parse_rss.c 
liferea-1.14.1/src/tests/parse_rss.c
--- liferea-1.14.0/src/tests/parse_rss.c        1970-01-01 01:00:00.000000000 
+0100
+++ liferea-1.14.1/src/tests/parse_rss.c        2023-03-12 21:00:51.000000000 
+0100
@@ -0,0 +1,128 @@
+/**
+ * @file parse_rss.c  Test cases for RSS parsing
+ *
+ * Copyright (C) 2023 Lars Windolf <lars.wind...@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <glib.h>
+#include <string.h>
+
+#include "debug.h"
+#include "feed.h"
+#include "feed_parser.h"
+#include "item.h"
+#include "subscription.h"
+#include "xml.h"
+
+/* Format of test cases:
+
+   1.     feed XML string
+   2.     "true" for successfully parsed feed, "false" for unparseable
+   3.     number of items
+   4..n   string of XML serialized items
+ */
+
+gchar *tc_rss_feed1[] = {
+       "<rss 
version=\"2.0\"><channel><title>T</title><link>http://localhost</link><item><title>i1</title><link>http://localhost/item1.html</link><description>D</description></item><item><title>i2</title><link>https://localhost/item2.html</link></item></channel></rss>",
+       "true",
+       "2",
+       "<item><title>i1</title><description>&lt;div 
xmlns=\"http://www.w3.org/1999/xhtml\"&gt;&lt;p&gt;D&lt;/p&gt;&lt;/div&gt;</description><source>http://localhost/item1.html</source><nr>0</nr><readStatus>0</readStatus><updateStatus>0</updateStatus><mark>0</mark><time>1678397817</time><sourceId/><sourceNr>0</sourceNr><attributes/></item>",
+       
"<item><title>i2</title><source>https://localhost/item2.html</source><nr>0</nr><readStatus>0</readStatus><updateStatus>0</updateStatus><mark>0</mark><time>1678397817</time><sourceId/><sourceNr>0</sourceNr><attributes/></item>",
+       NULL
+};
+
+/* Test case to prevent | command injection in item link which could trigger
+   a HTML5 extraction */
+gchar *tc_rss_feed2_rce[] = {
+       "<rss 
version=\"2.0\"><channel><title>T</title><item><title>i1</title><link>|date 
>/tmp/bad-item-link.txt</link></item></channel></rss>",
+       "true",
+       "1",
+       
"<item><title>i1</title><nr>0</nr><readStatus>0</readStatus><updateStatus>0</updateStatus><mark>0</mark><time>1678397817</time><sourceId/><sourceNr>0</sourceNr><attributes/></item>",
+       NULL
+};
+
+static void
+tc_parse_feed (gconstpointer user_data)
+{
+       gchar                   **tc = (gchar **)user_data;
+       nodePtr                 node;
+       feedParserCtxtPtr       ctxt;
+       int                     i;
+       GList                   *iter;
+
+       node = node_new (feed_get_node_type ());
+       node_set_data (node, feed_new ());
+       node_set_subscription (node, subscription_new (NULL, NULL, NULL));
+       ctxt = feed_parser_ctxt_new (node->subscription, tc[0], strlen(tc[0]));
+
+       g_assert_cmpstr (feed_parse (ctxt)?"true":"false", ==, tc[1]);
+       g_assert (g_list_length (ctxt->items) == atoi(tc[2]));
+
+       i = 2;
+       iter = ctxt->items;
+       while (tc[++i]) {
+               gchar           *buffer, *tmp, *tmp2;
+               gint            buffersize;
+               xmlDocPtr       doc = xmlNewDoc (BAD_CAST"1.0");
+               xmlNodePtr      rootNode = xmlNewDocNode (doc, NULL, 
BAD_CAST"result", NULL);
+
+               xmlDocSetRootElement (doc, rootNode);
+
+               // Force time and delete <timestr> to make result compareable
+               itemPtr item = (itemPtr)iter->data;
+               item->time = 1678397817;
+               item_to_xml (item, rootNode);
+
+               xmlNode *timestr = xpath_find (rootNode, "//timestr");
+               if (timestr) {
+                       xmlUnlinkNode (timestr);
+                       xmlFreeNode (timestr);
+               }
+               xmlDocDumpMemory(doc, (xmlChar **)&buffer, &buffersize);
+
+               /* strip boilerplate */
+               tmp = buffer;
+               if ((tmp = strstr (tmp, "<result>")))
+                       tmp += 8;               
+               if ((tmp2 = strstr (tmp, "</result>")))
+                       *tmp2 = 0;
+
+               g_assert_cmpstr (tc[i], ==, tmp);
+
+               xmlFreeDoc (doc);
+               xmlFree (buffer);
+
+               iter = g_list_next (iter);
+       }       
+
+       feed_parser_ctxt_free (ctxt);
+       node_free (node);
+}
+
+int
+main (int argc, char *argv[])
+{
+       g_test_init (&argc, &argv, NULL);
+
+       if (argv[1] && g_str_equal (argv[1], "--debug"))
+               set_debug_level (DEBUG_UPDATE | DEBUG_HTML | DEBUG_PARSING);
+
+       g_test_add_data_func ("/rss/feed1",     &tc_rss_feed1,          
&tc_parse_feed);
+       g_test_add_data_func ("/rss/feed2_rce", &tc_rss_feed2_rce,      
&tc_parse_feed);
+
+       return g_test_run();
+}
diff -Nru liferea-1.14.0/src/ui/liferea_shell.c 
liferea-1.14.1/src/ui/liferea_shell.c
--- liferea-1.14.0/src/ui/liferea_shell.c       2023-01-10 21:12:42.000000000 
+0100
+++ liferea-1.14.1/src/ui/liferea_shell.c       2023-03-12 21:00:51.000000000 
+0100
@@ -1387,7 +1387,6 @@
        liferea_shell_update_toolbar ();
        liferea_shell_update_history_actions ();
        liferea_shell_setup_URL_receiver ();
-       liferea_shell_restore_state (overrideWindowState);
 
        gtk_widget_set_sensitive (GTK_WIDGET (shell->feedlistViewWidget), TRUE);
 
@@ -1407,6 +1406,7 @@
                          G_CALLBACK (liferea_shell_update_node_actions), NULL);
 
        /* 11.) Restore latest layout and selection */
+       liferea_shell_restore_state (overrideWindowState);
        conf_get_int_value (DEFAULT_VIEW_MODE, &mode);
        itemview_set_layout (mode);
 
diff -Nru liferea-1.14.0/src/update.c liferea-1.14.1/src/update.c
--- liferea-1.14.0/src/update.c 2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/update.c 2023-03-12 21:00:51.000000000 +0100
@@ -234,6 +234,13 @@
        request->authValue = g_strdup (authValue);
 }
 
+void
+update_request_allow_commands (UpdateRequest *request, gboolean allowCommands)
+{
+       request->allowCommands = allowCommands;
+}
+
+
 /* update result object */
 
 updateResultPtr
@@ -672,8 +679,14 @@
 
        /* everything starting with '|' is a local command */
        if (*(job->request->source) == '|') {
-               debug1 (DEBUG_UPDATE, "Recognized local command: %s", 
job->request->source);
-               update_exec_cmd (job);
+               if (job->request->allowCommands) {
+                       debug1 (DEBUG_UPDATE, "Recognized local command: %s", 
job->request->source);
+                       update_exec_cmd (job);
+               } else {
+                       debug1 (DEBUG_UPDATE, "Refusing to run local command 
from unexpected source: %s", job->request->source);
+                       job->result->httpstatus = 403;  /* Forbidden. */
+                       update_process_finished_job (job);
+               }
                return;
        }
 
diff -Nru liferea-1.14.0/src/update.h liferea-1.14.1/src/update.h
--- liferea-1.14.0/src/update.h 2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/update.h 2023-03-12 21:00:51.000000000 +0100
@@ -103,6 +103,7 @@
        updateOptionsPtr options;       /**< Update options for the request */
        gchar           *filtercmd;     /**< Command will filter output of URL 
*/
        updateStatePtr  updateState;    /**< Update state of the requested 
object (etags, last modified...) */
+       gboolean        allowCommands;  /**< Allow this requests to run 
commands */
 };
 
 /** structure to store results of the processing of an update request */
@@ -229,6 +230,21 @@
 void update_request_set_auth_value (UpdateRequest *request, const gchar* 
authValue);
 
 /**
+ * Allows *this* request to run local commands.
+ *
+ * At first it may look this flag should be in updateOptions, but we can
+ * take a safer path: feed commands are restricted to a few use cases while
+ * options are propagated to downstream requests (feed enrichment, comments,
+ * etc.), so it is a good idea to prevent these from running commands in the
+ * local system via tricky URLs without needing to validate these options
+ * everywhere (which is error-prone).
+ *
+ * @param request      the update request
+ * @param can_run      TRUE if the request can run commands, FALSE otherwise.
+ */
+void update_request_allow_commands (UpdateRequest *request, gboolean 
allowCommands);
+
+/**
  * Creates a new update result for the given update request.
  *
  * @returns update result (to be free'd using update_result_free())
diff -Nru liferea-1.14.0/src/vfolder.c liferea-1.14.1/src/vfolder.c
--- liferea-1.14.0/src/vfolder.c        2023-01-10 21:12:42.000000000 +0100
+++ liferea-1.14.1/src/vfolder.c        2023-03-12 21:00:51.000000000 +0100
@@ -308,7 +308,7 @@
                NODE_CAPABILITY_SHOW_UNREAD_COUNT |
                NODE_CAPABILITY_EXPORT_ITEMS,
                "vfolder",
-               NULL,
+               ICON_VFOLDER,
                vfolder_import,
                vfolder_export,
                vfolder_load,
@@ -320,7 +320,6 @@
                vfolder_properties,
                vfolder_free
        };
-       nti.icon = icon_get (ICON_VFOLDER);
 
        return &nti;
 }

--- End Message ---
--- Begin Message ---
Unblocked.

--- End Message ---

Reply via email to