Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package newsboat for openSUSE:Factory 
checked in at 2026-11-09 16:07:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/newsboat (Old)
 and      /work/SRC/openSUSE:Factory/.newsboat.new.3759290 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "newsboat"

Mon Nov  9 16:07:43 2026 rev:5 rq:1396290 version:2.45.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/newsboat/newsboat.changes        2026-10-09 
21:43:11.948812352 +0200
+++ /work/SRC/openSUSE:Factory/.newsboat.new.3759290/newsboat.changes   
2026-11-09 16:08:47.336233999 +0100
@@ -1,0 +2,6 @@
+Mon Nov  9 09:41:09 UTC 2026 - Michael Vetter <[email protected]>
+
+- Update to 2.45.1:
+  * GHSA-78q5-mpjq-5q34: Remote code execution via manual OPML import 
(`--import-from-opml`)
+
+-------------------------------------------------------------------

Old:
----
  newsboat-2.45.tar.xz
  newsboat-2.45.tar.xz.asc

New:
----
  newsboat-2.45.1.tar.xz
  newsboat-2.45.1.tar.xz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ newsboat.spec ++++++
--- /var/tmp/diff_new_pack.DPR1Hm/_old  2026-11-09 16:08:50.202354057 +0100
+++ /var/tmp/diff_new_pack.DPR1Hm/_new  2026-11-09 16:08:50.203354099 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           newsboat
-Version:        2.45
+Version:        2.45.1
 Release:        0
 Summary:        RSS/Atom Feed Reader for Text Terminals
 License:        MIT

++++++ newsboat-2.45.tar.xz -> newsboat-2.45.1.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/CHANGELOG.md 
new/newsboat-2.45.1/CHANGELOG.md
--- old/newsboat-2.45/CHANGELOG.md      2026-10-04 12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/CHANGELOG.md    2026-11-05 16:46:02.000000000 +0100
@@ -1,5 +1,33 @@
 # Changes for Newsboat
 
+## 2.45.1 - 2026-11-05
+
+### Security
+
+- GHSA-78q5-mpjq-5q34: Remote code execution via manual OPML import 
(`--import-from-opml`)
+
+    All Newsboat releases are affected.
+
+    CVE ID pending.
+
+    This is a more specific version of GHSA-4m8m-vj3m-hfxx: the vulnerability 
is
+    the same, but the attack vector is a bit more complex.
+
+    When importing an OPML document, Newsboat doesn't sanitise newlines in the
+    data it reads. This data is then written into a plain-text file (the urls
+    file) which is then read back line-by-line. Specially crafted OPML 
documents
+    could utilise this to add more lines to the urls file and inject `exec:` 
and
+    `filter:` special URLs that contain shell commands to be executed when such
+    URL is reloaded.
+
+    In order to resolve this, URLs are sanitized by percent-encoding them, 
while
+    newlines in tags are replaced by underscore character.
+
+    Responsibly disclosed via email by @ghozt, who also provided the essence
+    of the fix.
+
+
+
 ## 2.45 - 2026-10-04
 
 This release was delayed by a week in order to work on security fixes.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/Cargo.lock 
new/newsboat-2.45.1/Cargo.lock
--- old/newsboat-2.45/Cargo.lock        2026-10-04 12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/Cargo.lock      2026-11-05 16:46:02.000000000 +0100
@@ -901,7 +901,7 @@
 
 [[package]]
 name = "libnewsboat"
-version = "2.45.0"
+version = "2.45.1"
 dependencies = [
  "backtrace",
  "chrono",
@@ -928,7 +928,7 @@
 
 [[package]]
 name = "libnewsboat-ffi"
-version = "2.45.0"
+version = "2.45.1"
 dependencies = [
  "cxx",
  "cxx-build",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/README.md new/newsboat-2.45.1/README.md
--- old/newsboat-2.45/README.md 2026-10-04 12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/README.md       2026-11-05 16:46:02.000000000 +0100
@@ -31,18 +31,18 @@
 * Powerful built-in HTML renderer — no need to start the web browser to view
     text-only entries
 * Send links and whole articles to third-party services using [bookmarking
-    
scripts](https://newsboat.org/releases/2.45/docs/newsboat.html#_bookmarking)
-* [Filter articles 
out](https://newsboat.org/releases/2.45/docs/newsboat.html#_killfiles)
+    
scripts](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_bookmarking)
+* [Filter articles 
out](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_killfiles)
     based on title, author, contents etc.
-* [Aggregate 
articles](https://newsboat.org/releases/2.45/docs/newsboat.html#_query_feeds)
+* [Aggregate 
articles](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_query_feeds)
     into meta-feeds by arbitrary criteria
-* [Apply 
transformations](https://newsboat.org/releases/2.45/docs/newsboat.html#_scripts_and_filters_snownews_extensions)
+* [Apply 
transformations](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_scripts_and_filters_snownews_extensions)
     to feeds before passing them into Newsboat
 * Integrates with services like The Old Reader, NewsBlur, FeedHQ
-    and [many 
more](https://newsboat.org/releases/2.45/docs/newsboat.html#_newsboat_as_a_client_for_newsreading_services)
-* 
[Macros](https://newsboat.org/releases/2.45/docs/newsboat.html#_macro_support)
+    and [many 
more](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_newsboat_as_a_client_for_newsreading_services)
+* 
[Macros](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_macro_support)
     to execute sequences of actions with just two keystrokes
-* Rudimentary [podcast 
support](https://newsboat.org/releases/2.45/docs/newsboat.html#_podcast_support)
+* Rudimentary [podcast 
support](https://newsboat.org/releases/2.45.1/docs/newsboat.html#_podcast_support)
 
 Downloading
 -----------
@@ -115,7 +115,7 @@
   strict confinement; if we disabled it, the snap would be no better than
   a distribution's package;
 
-  [snap-browser]: 
https://newsboat.org/releases/2.45/docs/faq.html#_with_snap_i_cant_start_browserbookmarking_scriptexecfilterrun_program_from_macro
+  [snap-browser]: 
https://newsboat.org/releases/2.45.1/docs/faq.html#_with_snap_i_cant_start_browserbookmarking_scriptexecfilterrun_program_from_macro
 
 - [build from source with Docker](doc/docker.md). Note that the resulting 
binary
     might not run outside of that same Docker container if your system doesn't
@@ -154,8 +154,8 @@
 -------
 
 * Check out our
-  [documentation](https://newsboat.org/releases/2.45/docs/newsboat.html) and
-  [FAQ](https://newsboat.org/releases/2.45/docs/faq.html)
+  [documentation](https://newsboat.org/releases/2.45.1/docs/newsboat.html) and
+  [FAQ](https://newsboat.org/releases/2.45.1/docs/faq.html)
 * Report security vulnerabilities to [email protected]. Please encrypt 
your emails to
   [OpenPGP key 4ED6CD61932B9EBE](https://newsboat.org/newsboat.pgp) if you can.
 * Report bugs and ask questions on
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/include/utils.h 
new/newsboat-2.45.1/include/utils.h
--- old/newsboat-2.45/include/utils.h   2026-10-04 12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/include/utils.h 2026-11-05 16:46:02.000000000 +0100
@@ -35,6 +35,7 @@
 
 std::string strip_comments(const std::string& line);
 bool contains_control_characters(std::string_view str);
+std::string replace_newlines(std::string_view str, char replacement = '_');
 std::string replace_control_characters(std::string_view str,
        char replacement = '_');
 std::vector<std::string> tokenize(const std::string& str,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/rust/libnewsboat/Cargo.toml 
new/newsboat-2.45.1/rust/libnewsboat/Cargo.toml
--- old/newsboat-2.45/rust/libnewsboat/Cargo.toml       2026-10-04 
12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/rust/libnewsboat/Cargo.toml     2026-11-05 
16:46:02.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "libnewsboat"
-version = "2.45.0"
+version = "2.45.1"
 authors = ["Alexander Batischev <[email protected]>"]
 edition = "2024"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/newsboat-2.45/rust/libnewsboat/proptest-regressions/utils.txt 
new/newsboat-2.45.1/rust/libnewsboat/proptest-regressions/utils.txt
--- old/newsboat-2.45/rust/libnewsboat/proptest-regressions/utils.txt   
1970-01-01 01:00:00.000000000 +0100
+++ new/newsboat-2.45.1/rust/libnewsboat/proptest-regressions/utils.txt 
2026-11-05 16:46:02.000000000 +0100
@@ -0,0 +1,7 @@
+# Seeds for failure cases proptest has generated in the past. It is
+# automatically read and these particular cases re-run before any
+# novel cases are generated.
+#
+# It is recommended to check this file in to source control so that
+# everyone who runs the test benefits from these saved cases.
+cc 0313ef86a079ca9b252b4812c078a62ba49035eea6e5ce77736ca7b2e1503b4d # shrinks 
to ref input = "\\"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/rust/libnewsboat/src/utils.rs 
new/newsboat-2.45.1/rust/libnewsboat/src/utils.rs
--- old/newsboat-2.45/rust/libnewsboat/src/utils.rs     2026-10-04 
12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/rust/libnewsboat/src/utils.rs   2026-11-05 
16:46:02.000000000 +0100
@@ -171,7 +171,7 @@
 }
 
 pub fn quote(input: &str) -> String {
-    let mut input = input.replace('\"', "\\\"");
+    let mut input = input.replace('\\', "\\\\").replace('\"', "\\\"");
     input.insert(0, '"');
     input.push('"');
     input
@@ -1375,6 +1375,10 @@
         assert_eq!(quote(""), "\"\"");
         assert_eq!(quote("Hello World!"), "\"Hello World!\"");
         assert_eq!(quote("\"Hello World!\""), "\"\\\"Hello World!\\\"\"");
+        assert_eq!(
+            quote(r#"Here's a stray backslash: \ <- Saw that?"#),
+            r#""Here's a stray backslash: \\ <- Saw that?""#
+        );
     }
 
     #[test]
@@ -2427,4 +2431,14 @@
             )
         );
     }
+
+    proptest::proptest! {
+        #[test]
+        fn t_quote_unquote(ref input in "\\PC*") {
+            let quoted = quote(input);
+            let unquoted = tokenize_quoted(&quoted, " \r\n\t");
+            assert_eq!(unquoted.len(), 1);
+            assert_eq!(&unquoted[0], input);
+        }
+    }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/rust/libnewsboat-ffi/Cargo.toml 
new/newsboat-2.45.1/rust/libnewsboat-ffi/Cargo.toml
--- old/newsboat-2.45/rust/libnewsboat-ffi/Cargo.toml   2026-10-04 
12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/rust/libnewsboat-ffi/Cargo.toml 2026-11-05 
16:46:02.000000000 +0100
@@ -1,6 +1,6 @@
 [package]
 name = "libnewsboat-ffi"
-version = "2.45.0"
+version = "2.45.1"
 authors = ["Alexander Batischev <[email protected]>"]
 edition = "2024"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/src/fileurlwriter.cpp 
new/newsboat-2.45.1/src/fileurlwriter.cpp
--- old/newsboat-2.45/src/fileurlwriter.cpp     2026-10-04 12:16:42.000000000 
+0200
+++ new/newsboat-2.45.1/src/fileurlwriter.cpp   2026-11-05 16:46:02.000000000 
+0100
@@ -21,9 +21,9 @@
        }
 
        for (auto& feed_url : feed_urls) {
-               f << utils::quote_if_necessary(feed_url.url);
+               f << 
utils::quote_if_necessary(utils::sanitize_url(feed_url.url));
                for (const auto& tag : feed_url.tags) {
-                       f << " \"" << tag << "\"";
+                       f << " " << utils::quote(utils::replace_newlines(tag));
                }
                f << std::endl;
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/src/utils.cpp 
new/newsboat-2.45.1/src/utils.cpp
--- old/newsboat-2.45/src/utils.cpp     2026-10-04 12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/src/utils.cpp   2026-11-05 16:46:02.000000000 +0100
@@ -59,6 +59,17 @@
        return false;
 }
 
+std::string utils::replace_newlines(std::string_view str, char replacement)
+{
+       std::string result(str);
+       for (char& c : result) {
+               if (c == '\n') {
+                       c = replacement;
+               }
+       }
+       return result;
+}
+
 std::string utils::replace_control_characters(std::string_view str,
        char replacement)
 {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/newsboat-2.45/test/data/with_escaped_newline_in_nested_outlines.opml 
new/newsboat-2.45.1/test/data/with_escaped_newline_in_nested_outlines.opml
--- old/newsboat-2.45/test/data/with_escaped_newline_in_nested_outlines.opml    
1970-01-01 01:00:00.000000000 +0100
+++ new/newsboat-2.45.1/test/data/with_escaped_newline_in_nested_outlines.opml  
2026-11-05 16:46:02.000000000 +0100
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="1.0">
+    <head>
+        <title>Example OPML with a hidden newline in the nested 
outlines</title>
+    </head>
+
+    <body>
+        <outline text="one&#10;exec:echo${IFS}foobar">
+            <outline text="three&#10;exec:echo${IFS}bazquux">
+                <outline type="rss"
+                         xmlUrl="http://example.org/feed2.xml";
+                         text="Nothing special about this feed"/>
+            </outline>
+        </outline>
+    </body>
+</opml>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/newsboat-2.45/test/data/with_escaped_newline_in_text_field.opml 
new/newsboat-2.45.1/test/data/with_escaped_newline_in_text_field.opml
--- old/newsboat-2.45/test/data/with_escaped_newline_in_text_field.opml 
1970-01-01 01:00:00.000000000 +0100
+++ new/newsboat-2.45.1/test/data/with_escaped_newline_in_text_field.opml       
2026-11-05 16:46:02.000000000 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="1.0">
+    <head>
+        <title>Example OPML with a hidden newline in the `text` field</title>
+    </head>
+
+    <body>
+    <outline type="rss"
+             xmlUrl="http://example.org/feed1.xml";
+             text="demo&#10;exec:echo${IFS}boo"/>
+    </body>
+</opml>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/newsboat-2.45/test/data/with_escaped_newline_in_title_field.opml 
new/newsboat-2.45.1/test/data/with_escaped_newline_in_title_field.opml
--- old/newsboat-2.45/test/data/with_escaped_newline_in_title_field.opml        
1970-01-01 01:00:00.000000000 +0100
+++ new/newsboat-2.45.1/test/data/with_escaped_newline_in_title_field.opml      
2026-11-05 16:46:02.000000000 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="1.0">
+    <head>
+        <title>Example OPML with a hidden newline in the `title` field</title>
+    </head>
+
+    <body>
+    <outline type="rss"
+             xmlUrl="http://example.org/feed2.xml";
+             title="demo&#10;exec:echo${IFS}oops"/>
+    </body>
+</opml>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/newsboat-2.45/test/data/with_escaped_newline_in_xmlurl_field.opml 
new/newsboat-2.45.1/test/data/with_escaped_newline_in_xmlurl_field.opml
--- old/newsboat-2.45/test/data/with_escaped_newline_in_xmlurl_field.opml       
1970-01-01 01:00:00.000000000 +0100
+++ new/newsboat-2.45.1/test/data/with_escaped_newline_in_xmlurl_field.opml     
2026-11-05 16:46:02.000000000 +0100
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<opml version="1.0">
+    <head>
+        <title>Example OPML with a hidden newline in the `xmlUrl` field</title>
+    </head>
+
+    <body>
+    <outline type="rss"
+             xmlUrl="http://example.org/feed1.xml&#10;exec:echo${IFS}boo";
+             text="A normal site"/>
+    </body>
+</opml>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/test/fileurlwriter.cpp 
new/newsboat-2.45.1/test/fileurlwriter.cpp
--- old/newsboat-2.45/test/fileurlwriter.cpp    2026-10-04 12:16:42.000000000 
+0200
+++ new/newsboat-2.45.1/test/fileurlwriter.cpp  2026-11-05 16:46:02.000000000 
+0100
@@ -109,3 +109,132 @@
                }
        }
 }
+
+TEST_CASE("FileUrlWriter percent-encodes URLs", "[FileUrlWriter]")
+{
+       test_helpers::TempFile file;
+
+       const auto get_feed_origin = []() -> FeedOrigin {
+               static std::size_t file_origin;
+               FeedOrigin ret;
+               ret.file_origin = { file_origin++ };
+               return ret;
+       };
+       const std::vector<std::string> no_tags;
+       const std::vector<UrlReader::FeedUrl> urls {
+               {
+                       "https://example.com/feed.xml\nexec:echo boo",
+                       get_feed_origin(),
+                       no_tags
+               },
+
+               {
+                       "https://example.com/another_feed.xml\rexec:echo\tboo";,
+                       get_feed_origin(),
+                       no_tags
+               }
+       };
+
+       FileUrlWriter::write_urls(urls, file.get_path());
+
+       const auto result = test_helpers::file_contents(file.get_path());
+       const std::vector<std::string> expected_result {
+               R"("https://example.com/feed.xml%0Aexec:echo boo")",
+               R"(https://example.com/another_feed.xml%0Dexec:echo%09boo)",
+               ""
+       };
+       REQUIRE(result == expected_result);
+}
+
+TEST_CASE("FileUrlWriter replaces newlines in tags with underscore",
+       "[FileUrlWriter]")
+{
+       test_helpers::TempFile file;
+
+       const auto get_feed_origin = []() -> FeedOrigin {
+               static std::size_t file_origin;
+               FeedOrigin ret;
+               ret.file_origin = { file_origin++ };
+               return ret;
+       };
+       const std::vector<std::string> no_tags;
+       const std::vector<UrlReader::FeedUrl> urls {
+               {
+                       "https://example.org/feed2.xml";,
+                       get_feed_origin(),
+                       { "sneaky tag\nexec:echo foo", "weird\tag" }
+               }
+       };
+
+       FileUrlWriter::write_urls(urls, file.get_path());
+
+       const auto result = test_helpers::file_contents(file.get_path());
+       const std::vector<std::string> expected_result {
+               R"(https://example.org/feed2.xml "sneaky tag_exec:echo foo" 
"weird      ag")",
+               ""
+       };
+       REQUIRE(result == expected_result);
+}
+
+TEST_CASE("FileUrlWriter puts tags in double quotes", "[FileUrlWriter]")
+{
+       test_helpers::TempFile file;
+
+       const auto get_feed_origin = []() -> FeedOrigin {
+               static std::size_t file_origin;
+               FeedOrigin ret;
+               ret.file_origin = { file_origin++ };
+               return ret;
+       };
+       const std::vector<UrlReader::FeedUrl> urls {
+               {
+                       "https://example.com/news.atom";,
+                       get_feed_origin(),
+                       { "tag1", "tag two", "tag \"three\"" }
+               },
+
+               {
+                       "https://example.com/feed.xml";,
+                       get_feed_origin(),
+                       { "the quick", "brown fox \"jumps", "tag1", "the lazy", 
"tag two" }
+               },
+
+               {
+                       "https://example.com/feed2.xml";,
+                       get_feed_origin(),
+                       { "tricky tag\\", "that extends" }
+               }
+       };
+
+       FileUrlWriter::write_urls(urls, file.get_path());
+
+       FileUrlReader reader(file.get_path());
+       reader.reload();
+
+       const auto into_map = [](const std::vector<UrlReader::FeedUrl>& urls)
+       -> std::map<std::string, std::vector<std::string>> {
+               std::map<std::string, std::vector<std::string>> ret;
+               for (const auto& url : urls)
+               {
+                       ret[url.url] = url.tags;
+               }
+               return ret;
+       };
+       const auto actual_urls = into_map(reader.get_urls());
+       for (const auto& url : urls) {
+               auto it = actual_urls.find(url.url);
+               REQUIRE(it != std::end(actual_urls));
+               REQUIRE(it->second == url.tags);
+       }
+
+       const std::set<std::string> expected_alltags {
+               "tag1", "tag two", "tag \"three\"",
+               "the quick", "brown fox \"jumps", "the lazy",
+               "tricky tag\\", "that extends"
+       };
+       const auto actual_alltags = reader.get_alltags();
+       const std::set<std::string> actual_alltags_set {
+               actual_alltags.begin(), actual_alltags.end()
+       };
+       REQUIRE(actual_alltags_set == expected_alltags);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/newsboat-2.45/test/opml.cpp 
new/newsboat-2.45.1/test/opml.cpp
--- old/newsboat-2.45/test/opml.cpp     2026-10-04 12:16:42.000000000 +0200
+++ new/newsboat-2.45.1/test/opml.cpp   2026-11-05 16:46:02.000000000 +0100
@@ -460,6 +460,101 @@
        REQUIRE(urlcfg.get_alltags().empty());
 }
 
+TEST_CASE("import() replaces newlines with underscores in text attribute", 
"[Opml]")
+{
+       test_helpers::TempFile urlsFile;
+
+       FileUrlReader urlcfg(urlsFile.get_path());
+       urlcfg.reload();
+
+       const auto path =
+               "file:/"_path // `Filepath` will append an extra slash
+               .join(utils::getcwd())
+               .join("data/with_escaped_newline_in_text_field.opml"_path);
+       REQUIRE_NOTHROW(opml::import(path, urlcfg));
+
+       urlcfg.reload();
+       const auto urls = urlcfg.get_urls();
+       REQUIRE(urls.size() == 1);
+       REQUIRE(urls[0].url == "http://example.org/feed1.xml";);
+       std::vector<std::string> expected_tags({ "~demo_exec:echo${IFS}boo" });
+       REQUIRE(urls[0].tags == expected_tags);
+       REQUIRE(urlcfg.get_alltags().empty());
+}
+
+TEST_CASE("import() replaces newlines with underscores in title attribute", 
"[Opml]")
+{
+       test_helpers::TempFile urlsFile;
+
+       FileUrlReader urlcfg(urlsFile.get_path());
+       urlcfg.reload();
+
+       const auto path =
+               "file:/"_path // `Filepath` will append an extra slash
+               .join(utils::getcwd())
+               .join("data/with_escaped_newline_in_title_field.opml"_path);
+       REQUIRE_NOTHROW(opml::import(path, urlcfg));
+
+       urlcfg.reload();
+       const auto urls = urlcfg.get_urls();
+       REQUIRE(urls.size() == 1);
+       REQUIRE(urls[0].url == "http://example.org/feed2.xml";);
+       std::vector<std::string> expected_tags({ "~demo_exec:echo${IFS}oops" });
+       REQUIRE(urls[0].tags == expected_tags);
+       REQUIRE(urlcfg.get_alltags().empty());
+}
+
+TEST_CASE("import() percent-encodes the URL", "[Opml]")
+{
+       test_helpers::TempFile urlsFile;
+
+       FileUrlReader urlcfg(urlsFile.get_path());
+       urlcfg.reload();
+
+       const auto path =
+               "file:/"_path // `Filepath` will append an extra slash
+               .join(utils::getcwd())
+               .join("data/with_escaped_newline_in_xmlurl_field.opml"_path);
+       REQUIRE_NOTHROW(opml::import(path, urlcfg));
+
+       urlcfg.reload();
+       const auto urls = urlcfg.get_urls();
+       REQUIRE(urls.size() == 1);
+       REQUIRE(urls[0].url == 
"http://example.org/feed1.xml%0Aexec:echo${IFS}boo";);
+       std::vector<std::string> expected_tags({ "~A normal site" });
+       REQUIRE(urls[0].tags == expected_tags);
+       REQUIRE(urlcfg.get_alltags().empty());
+}
+
+TEST_CASE("import() replaces newlines with underscores in tags (nested OPML 
outlines)",
+       "[Opml]")
+{
+       test_helpers::TempFile urlsFile;
+
+       FileUrlReader urlcfg(urlsFile.get_path());
+       urlcfg.reload();
+
+       const auto path =
+               "file:/"_path // `Filepath` will append an extra slash
+               .join(utils::getcwd())
+               .join("data/with_escaped_newline_in_nested_outlines.opml"_path);
+       REQUIRE_NOTHROW(opml::import(path, urlcfg));
+
+       urlcfg.reload();
+       const auto urls = urlcfg.get_urls();
+       REQUIRE(urls.size() == 1);
+       REQUIRE(urls[0].url == "http://example.org/feed2.xml";);
+       std::vector<std::string> expected_tags({
+               "~Nothing special about this feed",
+               "one_exec:echo${IFS}foobar/three_exec:echo${IFS}bazquux"
+       });
+       REQUIRE(urls[0].tags == expected_tags);
+       std::vector<std::string> expected_alltags({
+               "one_exec:echo${IFS}foobar/three_exec:echo${IFS}bazquux"
+       });
+       REQUIRE(urlcfg.get_alltags() == expected_alltags);
+}
+
 // falls back to "url" if "xmlUrl" is absent
 
 // skips an entry if xmlUrl/url is absent


++++++ vendor.tar.xz ++++++
/work/SRC/openSUSE:Factory/newsboat/vendor.tar.xz 
/work/SRC/openSUSE:Factory/.newsboat.new.3759290/vendor.tar.xz differ: char 15, 
line 1

Reply via email to