public inbox for cygwin-apps@cygwin.com
 help / color / mirror / Atom feed
From: Jon Turney <jon.turney@dronecode.org.uk>
To: cygwin-apps@cygwin.com
Cc: Jon Turney <jon.turney@dronecode.org.uk>
Subject: [PATCH setup 07/16] Split out URL fetching progress reporting
Date: Fri,  8 Mar 2024 18:34:26 +0000	[thread overview]
Message-ID: <20240308183440.4263-8-jon.turney@dronecode.org.uk> (raw)
In-Reply-To: <20240308183440.4263-1-jon.turney@dronecode.org.uk>

Rename IniParseFeedback.h to Feedback.h

Do URL fetching progress reporting via an interface defined by the
methods added to the interface defined by the virtual base class
Feedback, which can be implemented for GUI (via ThreeBar) or CLI feedback.

This is all a bit ad-hoc at the moment, based on the existing reporting
points, rather than a studied design.

Ultimately this Feedback class will grow to contain all the
download/hash/install/uninstall reporting.

Future work: The fact that we do extra key fetching inside the guts of
verify_ini_file_sig() (and so need to report progress from there) is
pretty disgusting.  We should probably fetch them up-front and hand them
down to there...
---
 Feedback.h                                    |  54 ++++++
 IniDBBuilderPackage.cc                        |   4 +-
 IniDBBuilderPackage.h                         |   6 +-
 IniParseFeedback.h                            |  38 ----
 Makefile.am                                   |   9 +-
 CliParseFeedback.h => cli/CliFeedback.h       |  31 +++-
 cli/CliGetUrlFeedback.cc                      |  91 ++++++++++
 .../CliParseFeedback.cc                       |  28 ++-
 crypto.cc                                     |  18 +-
 crypto.h                                      |   9 +-
 download.cc                                   |  17 +-
 fromcwd.cc                                    |   1 -
 geturl.cc                                     | 130 +++-----------
 geturl.h                                      |  13 +-
 gui/GuiFeedback.h                             |  64 +++++++
 gui/GuiGetUrlFeedback.cc                      | 119 +++++++++++++
 gui/GuiParseFeedback.cc                       | 164 ++++++++++--------
 gui/SitePage.cc                               |  19 +-
 ini.cc                                        |  36 ++--
 ini.h                                         |   7 +-
 inilex.ll                                     |   6 +-
 inilintmain.cc                                |  10 +-
 22 files changed, 572 insertions(+), 302 deletions(-)
 create mode 100644 Feedback.h
 delete mode 100644 IniParseFeedback.h
 rename CliParseFeedback.h => cli/CliFeedback.h (52%)
 create mode 100644 cli/CliGetUrlFeedback.cc
 rename CliParseFeedback.cc => cli/CliParseFeedback.cc (58%)
 create mode 100644 gui/GuiFeedback.h
 create mode 100644 gui/GuiGetUrlFeedback.cc

diff --git a/Feedback.h b/Feedback.h
new file mode 100644
index 0000000..8f603a6
--- /dev/null
+++ b/Feedback.h
@@ -0,0 +1,54 @@
+/*
+ *     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.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ */
+
+#ifndef SETUP_FEEDBACK_H
+#define SETUP_FEEDBACK_H
+
+#include "win32.h"
+#include <string>
+
+/* Interface for feedback from ini parsing and URL fetching.
+ *
+ * Used to send feedback that users need but that should not interrupt
+ * processing.
+ *
+ * Fatal errors are (may be) thrown as exceptions.
+ */
+
+class Feedback
+{
+public:
+  // IniParsing
+  virtual void parse_init () = 0;
+  virtual void parse_finish () = 0;
+  virtual void progress (unsigned long const, unsigned long const) = 0;
+  virtual void iniName (const std::string& ) = 0;
+  virtual void babble (const std::string& ) const = 0;
+  virtual void warning (const std::string& ) const = 0;
+  virtual void show_errors () const = 0;
+  virtual void note_error(int lineno, const std::string &error) = 0;
+  virtual bool has_errors () const = 0;
+
+  // URL fetching
+  virtual void fetch_progress_disable (bool) = 0;
+  virtual void fetch_init (const std::string &url, int length) = 0;
+  virtual void fetch_set_length(int length) = 0;
+  virtual void fetch_set_total_length(long long int total_length) = 0;
+  virtual void fetch_progress (int bytes) = 0;
+  virtual void fetch_total_progress () = 0;
+  virtual void fetch_finish (int total_bytes) = 0;
+  virtual void fetch_fatal (const char *filename, const char *err) = 0;
+
+  //
+  virtual HWND owner () = 0;
+};
+
+#endif /* SETUP_FEEDBACK_H */
diff --git a/IniDBBuilderPackage.cc b/IniDBBuilderPackage.cc
index 039404b..aa6dec7 100644
--- a/IniDBBuilderPackage.cc
+++ b/IniDBBuilderPackage.cc
@@ -19,7 +19,7 @@
 
 #include "setup_version.h"
 
-#include "IniParseFeedback.h"
+#include "Feedback.h"
 #include "package_db.h"
 #include "package_meta.h"
 #include "ini.h"
@@ -29,7 +29,7 @@
 #include "PackageSpecification.h"
 #include <algorithm>
 
-IniDBBuilderPackage::IniDBBuilderPackage (IniParseFeedback const &aFeedback) :
+IniDBBuilderPackage::IniDBBuilderPackage (Feedback const &aFeedback) :
   currentSpec (0), _feedback (aFeedback), minimum_version_checked(FALSE) {}
 
 IniDBBuilderPackage::~IniDBBuilderPackage()
diff --git a/IniDBBuilderPackage.h b/IniDBBuilderPackage.h
index 3e3a9e4..0f59257 100644
--- a/IniDBBuilderPackage.h
+++ b/IniDBBuilderPackage.h
@@ -24,13 +24,13 @@
 #include "String++.h"
 #include "libsolv.h"
 
-class IniParseFeedback;
+class Feedback;
 class packagesource;
 
 class IniDBBuilderPackage:public IniDBBuilder
 {
 public:
-  IniDBBuilderPackage (IniParseFeedback const &);
+  IniDBBuilderPackage (Feedback const &);
   ~IniDBBuilderPackage ();
 
   void buildTimestamp (const std::string& );
@@ -88,7 +88,7 @@ private:
   SolverPool::addPackageData cbpv;
   std::set <std::string> replace_versions;
 
-  IniParseFeedback const &_feedback;
+  Feedback const &_feedback;
   bool minimum_version_checked;
 };
 
diff --git a/IniParseFeedback.h b/IniParseFeedback.h
deleted file mode 100644
index c3c7803..0000000
--- a/IniParseFeedback.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2002 Robert Collins.
- *
- *     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.
- *
- *     A copy of the GNU General Public License can be found at
- *     http://www.gnu.org/
- *
- * Written by Robert Collins <robertc@hotmail.com>
- *
- */
-
-#ifndef SETUP_INIPARSEFEEDBACK_H
-#define SETUP_INIPARSEFEEDBACK_H
-
-
-#include <string>
-/* Strategy for feedback from IniParsing.
- * Used by the builder or parsing classes to send feedback that users need
- * but that should not interrupt parsing.
- * Fatal errors are thrown as exceptions.
- */
-class IniParseFeedback
-{
-public:
-  virtual void progress (unsigned long const, unsigned long const) = 0;
-  virtual void iniName (const std::string& ) = 0;
-  virtual void babble (const std::string& ) const = 0;
-  virtual void warning (const std::string& ) const = 0;
-  virtual void show_errors () const = 0;
-  virtual void note_error(int lineno, const std::string &error) = 0;
-  virtual bool has_errors () const = 0;
-};
-
-#endif /* SETUP_INIPARSEFEEDBACK_H */
diff --git a/Makefile.am b/Makefile.am
index f753961..de066b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -65,8 +65,9 @@ inilint_LDADD = \
 inilint_SOURCES = \
 	filemanip.cc \
 	filemanip.h \
-	CliParseFeedback.cc \
-	CliParseFeedback.h \
+	cli/CliParseFeedback.cc \
+	cli/CliGetUrlFeedback.cc \
+	cli/CliFeedback.h \
 	LogSingleton.cc \
 	LogSingleton.h \
 	IniDBBuilder.h \
@@ -181,6 +182,8 @@ endif
 	gpg-packet.cc \
 	gpg-packet.h \
 	gui/GuiParseFeedback.cc \
+	gui/GuiGetUrlFeedback.cc \
+	gui/GuiFeedback.h \
 	ini.cc \
 	ini.h \
 	IniDBBuilder.h \
@@ -188,7 +191,7 @@ endif
 	IniDBBuilderPackage.h \
 	inilex.ll \
 	iniparse.yy \
-	IniParseFeedback.h \
+	Feedback.h \
 	install.cc \
 	io_stream.cc \
 	io_stream.h \
diff --git a/CliParseFeedback.h b/cli/CliFeedback.h
similarity index 52%
rename from CliParseFeedback.h
rename to cli/CliFeedback.h
index a19659e..3bcc23c 100644
--- a/CliParseFeedback.h
+++ b/cli/CliFeedback.h
@@ -11,11 +11,14 @@
  *
  */
 
-#include "IniParseFeedback.h"
+#include "Feedback.h"
 
-class CliParseFeedback : public IniParseFeedback
+class CliFeedback : public Feedback
 {
+  // ini parse
 public:
+  virtual void parse_init ();
+  virtual void parse_finish ();
   virtual void progress (unsigned long const pos, unsigned long const max);
   virtual void iniName (const std::string& name);
   virtual void babble (const std::string& message) const;
@@ -25,4 +28,28 @@ public:
   virtual bool has_errors () const;
 private:
   int error_count = 0;
+
+  // URL fetch
+public:
+  void fetch_progress_disable (bool);
+  void fetch_init (const std::string &url, int length);
+  void fetch_set_length(int length);
+  void fetch_set_total_length(long long int total_length);
+  void fetch_progress (int bytes);
+  void fetch_total_progress ();
+  void fetch_finish (int total_bytes);
+  void fetch_fatal (const char *filename, const char *err);
+
+private:
+  int max_bytes;
+  long long int total_download_bytes = 0; // meaning ???
+  long long int total_download_bytes_sofar = 0;
+
+  unsigned int last_tics;
+  unsigned int start_tics;
+
+  // owner
+public:
+  HWND owner () { return NULL; }
+
 };
diff --git a/cli/CliGetUrlFeedback.cc b/cli/CliGetUrlFeedback.cc
new file mode 100644
index 0000000..1256118
--- /dev/null
+++ b/cli/CliGetUrlFeedback.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2024 Jon Turney
+ *
+ *     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.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ */
+
+#include "cli/CliFeedback.h"
+#include "msg.h"
+#include "resource.h"
+#include <stdio.h>
+
+void
+CliFeedback::fetch_progress_disable(bool disable)
+{
+}
+
+void
+CliFeedback::fetch_init (const std::string &url, int length)
+{
+  max_bytes = length;
+  printf("Fetching: %s\n", url.c_str());
+  start_tics = GetTickCount ();
+}
+
+void
+CliFeedback::fetch_set_length(int length)
+{
+  max_bytes = length;
+}
+
+void
+CliFeedback::fetch_set_total_length(long long int total_length)
+{
+  total_download_bytes = total_length;
+  total_download_bytes_sofar = 0;
+}
+
+void
+CliFeedback::fetch_progress (int bytes)
+{
+  DWORD tics = GetTickCount ();
+  if (tics == start_tics)       // to prevent division by zero
+    return;
+  if (tics < last_tics + 200)   // to prevent flickering updates
+    return;
+  last_tics = tics;
+
+  double kbps = ((double)bytes) / (double)(tics - start_tics);
+
+  if (max_bytes > 0)
+    {
+      int perc = (int)(100.0 * ((double)bytes) / (double)max_bytes);
+      printf ("%d %%  (%dk/%dk)  %03.1f kB/s",
+              perc, bytes / 1000, max_bytes / 1000, kbps);
+
+    }
+  else
+    printf("%d  %2.1f kB/s", bytes, kbps);
+
+  if (total_download_bytes > 0)
+    {
+      int total_perc = (int)(100.0 * ((double)total_download_bytes_sofar + bytes/
+                                      (double)total_download_bytes));
+      printf("%d %%", total_perc);
+    }
+  printf("\n");
+}
+
+void
+CliFeedback::fetch_total_progress ()
+{
+}
+
+void
+CliFeedback::fetch_finish (int total_bytes)
+{
+  total_download_bytes_sofar += total_bytes;
+}
+
+void
+CliFeedback::fetch_fatal (const char *filename, const char *err)
+{
+  ::fatal (NULL, IDS_ERR_OPEN_WRITE, filename, err);
+}
diff --git a/CliParseFeedback.cc b/cli/CliParseFeedback.cc
similarity index 58%
rename from CliParseFeedback.cc
rename to cli/CliParseFeedback.cc
index 6dc48ba..a58ee5a 100644
--- a/CliParseFeedback.cc
+++ b/cli/CliParseFeedback.cc
@@ -11,35 +11,45 @@
  *
  */
 
-#include "CliParseFeedback.h"
+#include "cli/CliFeedback.h"
 #include "LogSingleton.h"
 #include <sstream>
 #include <iostream>
 
-void CliParseFeedback::progress (unsigned long const pos, unsigned long const max)
+void
+CliFeedback::parse_init()
 {
-  std::cout << pos << "/" << max << std::endl;
 }
 
-void CliParseFeedback::iniName (const std::string& name)
+void
+CliFeedback::parse_finish()
 {
 }
 
-void CliParseFeedback::babble (const std::string& message) const
+void CliFeedback::progress (unsigned long const pos, unsigned long const max)
+{
+  std::cout << pos << "/" << max << "\r";
+}
+
+void CliFeedback::iniName (const std::string& name)
+{
+}
+
+void CliFeedback::babble (const std::string& message) const
 {
   Log (LOG_BABBLE) << message << endLog;
 }
 
-void CliParseFeedback::warning (const std::string& message) const
+void CliFeedback::warning (const std::string& message) const
 {
   std::cout << "Warning: " << message << std::endl;
 }
 
-void CliParseFeedback::show_errors () const
+void CliFeedback::show_errors () const
 {
 }
 
-void CliParseFeedback::note_error(int lineno, const std::string &s)
+void CliFeedback::note_error(int lineno, const std::string &s)
 {
   std::ostringstream buf;
   buf << "line " << lineno << ": ";
@@ -48,7 +58,7 @@ void CliParseFeedback::note_error(int lineno, const std::string &s)
   error_count++;
 }
 
-bool CliParseFeedback::has_errors () const
+bool CliFeedback::has_errors () const
 {
   return (error_count > 0);
 }
diff --git a/crypto.cc b/crypto.cc
index a837f8d..96c5e60 100644
--- a/crypto.cc
+++ b/crypto.cc
@@ -18,6 +18,7 @@
 #include <unistd.h>
 #include <vector>
 #include "io_stream.h"
+#include "win32.h"
 #include "crypto.h"
 #include "compress.h"
 #include "gcrypt.h"
@@ -29,6 +30,7 @@
 #include "KeysSetting.h"
 #include "gpg-packet.h"
 #include "geturl.h"
+#include "Feedback.h"
 
 #ifndef CRYPTODEBUGGING
 #define CRYPTODEBUGGING         (0)
@@ -649,7 +651,7 @@ gcrypt_log_adaptor(void *priv, int level, const char *fmt, va_list args)
 
 /*  Verify the signature on an ini file.  Takes care of all key-handling.  */
 bool
-verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
+verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, Feedback &feedback)
 {
   /*  Data returned from packet walker.  */
   struct sig_data sigdat;
@@ -674,7 +676,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
       gcry_check_version (NULL);
 
       if ((rv = gcry_control (GCRYCTL_SELFTEST)) != GPG_ERR_NO_ERROR)
-        ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "libgcrypt selftest failed");
+        ERRKIND (feedback.owner(), IDS_CRYPTO_ERROR, rv, "libgcrypt selftest failed");
 
 #if CRYPTODEBUGGING
       gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
@@ -687,7 +689,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
   rv = gcry_sexp_new (&cygwin_key, cygwin_pubkey_sexpr, strlen (cygwin_pubkey_sexpr), 1);
   if (rv != GPG_ERR_NO_ERROR)
     {
-      ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating pubkey s-expr.");
+      ERRKIND (feedback.owner(), IDS_CRYPTO_ERROR, rv, "while creating pubkey s-expr.");
     }
   else
     {
@@ -707,7 +709,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
       rv = gcry_sexp_new (&cygwin_old_key, cygwin_old_pubkey_sexpr, strlen (cygwin_old_pubkey_sexpr), 1);
       if (rv != GPG_ERR_NO_ERROR)
         {
-          ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating old pubkey s-expr.");
+          ERRKIND (feedback.owner(), IDS_CRYPTO_ERROR, rv, "while creating old pubkey s-expr.");
         }
       else
         {
@@ -791,7 +793,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
 	}
       else
 	{
-	  ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "invalid command-line pubkey s-expr.");
+	  ERRKIND (feedback.owner(), IDS_CRYPTO_ERROR, rv, "invalid command-line pubkey s-expr.");
 	}
     }
 
@@ -801,11 +803,11 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
 					= ExtraKeysFiles.begin ();
 		it != ExtraKeysFiles.end (); ++it)
     {
-      io_stream *keys = get_url_to_membuf (*it, owner);
+      io_stream *keys = get_url_to_membuf (*it, feedback);
       if (keys)
 	{
 	  struct key_data kdat;
-	  pkt_walk_packets (keys, key_file_walker, owner, 0, keys->get_size (), &kdat);
+	  pkt_walk_packets (keys, key_file_walker, feedback.owner(), 0, keys->get_size (), &kdat);
 	  // We now have a vector of (some/any?) keys returned from
 	  // the walker; add them to the list to try.
 	  while (!kdat.keys.empty ())
@@ -835,7 +837,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
   sigdat.sign_data = ini_file;
   sigdat.keys_to_try = &keys_to_try;
 
-  pkt_walk_packets (ini_sig_file, sig_file_walker, owner, 0,
+  pkt_walk_packets (ini_sig_file, sig_file_walker, feedback.owner(), 0,
                     ini_sig_file->get_size (), &sigdat);
 
   sig_ok = sigdat.valid;
diff --git a/crypto.h b/crypto.h
index 661d86d..17389e4 100644
--- a/crypto.h
+++ b/crypto.h
@@ -17,20 +17,19 @@
 #define SETUP_CRYPTO_H
 
 /* This module uses libgcrypt functionality to verify signatures
- * on downloaded setup.ini or setup.bz2 files.
+ * on downloaded (compressed) setup.ini files.
  */
 
-/* for HWND */
-#include "win32.h" 
+class Feedback;
 class io_stream;
 
 /*  This is currently the only public API exported by the module; it
-  takes the contents of setup.ini or setup.bz2 in one (memory-based,
+  takes the contents of (compressed) setup.ini in one (memory-based,
   for preference) io_stream, and the contents of the related signature
   file in another.  It is called from ini.cc/do_remote_ini() and returns
   true if the signature verified OK; if it returns false, you MUST NOT
   use the failed ini file - doubly so if it's a compressed stream!  */
-extern bool verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner);
+bool verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, Feedback &feedback);
 
 /*
 5.2.2.  Version 3 Signature Packet Format
diff --git a/download.cc b/download.cc
index 5bfcebf..02fd484 100644
--- a/download.cc
+++ b/download.cc
@@ -42,6 +42,7 @@
 #include "package_source.h"
 
 #include "threebar.h"
+#include "gui/GuiFeedback.h"
 
 #include "Exception.h"
 
@@ -146,11 +147,11 @@ check_for_cached (packagesource & pkgsource, HWND owner, bool mirror_mode,
 
 /* download a file from a mirror site to the local cache. */
 static int
-download_one (packagesource & pkgsource, HWND owner)
+download_one (packagesource & pkgsource, Feedback &feedback)
 {
   try
     {
-      if (check_for_cached (pkgsource, owner))
+      if (check_for_cached (pkgsource, feedback.owner()))
         return 0;
     }
   catch (Exception * e)
@@ -158,7 +159,7 @@ download_one (packagesource & pkgsource, HWND owner)
       // We know what to do with these..
       if (e->errNo() == APPERR_CORRUPT_PACKAGE)
 	{
-	  fatal (owner, IDS_CORRUPT_PACKAGE, pkgsource.Canonical());
+	  fatal (feedback.owner(), IDS_CORRUPT_PACKAGE, pkgsource.Canonical());
     	  return 1;
 	}
       // Unexpected exception.
@@ -176,7 +177,7 @@ download_one (packagesource & pkgsource, HWND owner)
       io_stream::mkpath_p (PATH_TO_FILE, "file://" + local, 0);
 
       if (get_url_to_file(n->key + pkgsource.Canonical (),
-			  local + ".tmp", pkgsource.size, owner))
+			  local + ".tmp", pkgsource.size, feedback))
 	{
 	  /* FIXME: note new source ? */
 	  continue;
@@ -274,8 +275,6 @@ static int
 do_download_thread (HINSTANCE h, HWND owner)
 {
   int errors = 0;
-  total_download_bytes = 0;
-  total_download_bytes_sofar = 0;
   download_failures.clear ();
 
   Progress.SetText1 (IDS_PROGRESS_CHECKING);
@@ -286,6 +285,7 @@ do_download_thread (HINSTANCE h, HWND owner)
   const SolverTransactionList &t = db.solution.transactions();
 
   /* calculate the total size of the download */
+  long long int total_download_bytes = 0;
   for (SolverTransactionList::const_iterator i = t.begin (); i != t.end (); ++i)
     {
       if (i->type != SolverTransaction::transInstall)
@@ -308,6 +308,9 @@ do_download_thread (HINSTANCE h, HWND owner)
       Progress.SetBar2(std::distance(t.begin(), i) + 1, t.size());
     }
 
+  GuiFeedback feedback(owner);
+  feedback.fetch_set_total_length(total_download_bytes);
+
   /* and do the download. FIXME: This here we assign a new name for the cached version
    * and check that above.
    */
@@ -319,7 +322,7 @@ do_download_thread (HINSTANCE h, HWND owner)
 
 	{
 	  int e = 0;
-          e += download_one (*version.source(), owner);
+          e += download_one (*version.source(), feedback);
 	  errors += e;
 	  if (e)
 	    download_failures.push_back (version);
diff --git a/fromcwd.cc b/fromcwd.cc
index 3e77ad3..f58e955 100644
--- a/fromcwd.cc
+++ b/fromcwd.cc
@@ -32,7 +32,6 @@
 
 #include "FindVisitor.h"
 #include "IniDBBuilderPackage.h"
-#include "IniParseFeedback.h"
 
 class SetupFindVisitor : public FindVisitor
 {
diff --git a/geturl.cc b/geturl.cc
index 679e468..c4187a6 100644
--- a/geturl.cc
+++ b/geturl.cc
@@ -15,12 +15,10 @@
  *
  */
 
-/* The purpose of this file is to act as a pretty interface to
-   netio.cc.  We add a progress dialog and some convenience functions
-   (like collect to string or file */
+/* The purpose of this file is to act as a pretty interface to netio.cc.  We add
+   a progress reporting and some convenience functions (like collect to string
+   or file) */
 
-#include "win32.h"
-#include "commctrl.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -30,87 +28,24 @@
 #include "geturl.h"
 #include "resource.h"
 #include "netio.h"
-#include "msg.h"
 #include "io_stream.h"
 #include "io_stream_memory.h"
 #include "state.h"
-#include "diskfull.h"
-#include "mount.h"
 #include "filemanip.h"
-
-#include "threebar.h"
+#include "String++.h"
 
 #include "Exception.h"
 
 #include "LogSingleton.h"
-
-extern ThreeBarProgressPage Progress;
-
-static int max_bytes = 0;
-static int is_local_install = 0;
-
-long long int total_download_bytes = 0;
-long long int total_download_bytes_sofar = 0;
-
-static DWORD start_tics;
+#include "Feedback.h"
 
 static void
-init_dialog (const std::string &url, int length)
+getUrlToStream (const std::string &_url, io_stream *output, Feedback &feedback)
 {
-  if (is_local_install)
-    return;
-
-  std::string::size_type divide = url.find_last_of('/');
-  max_bytes = length;
-  Progress.SetText1(IDS_PROGRESS_DOWNLOADING);
-  std::wstring fmt = LoadStringW(IDS_PROGRESS_DOWNLOADING_FROM);
-  std::wstring s = format(fmt,
-                          url.substr(divide + 1).c_str(),
-                          url.substr(0, divide).c_str());
-  Progress.SetText2(s.c_str());
-  Progress.SetText3(IDS_PROGRESS_CONNECTING);
-  Progress.SetBar1(0);
-  start_tics = GetTickCount ();
-}
+  // we turn off this feedback for local files
+  feedback.fetch_progress_disable((source == IDC_SOURCE_LOCALDIR));
 
-
-static void
-progress (int bytes)
-{
-  if (is_local_install)
-    return;
-  static char buf[100];
-  double kbps;
-  static unsigned int last_tics = 0;
-  DWORD tics = GetTickCount ();
-  if (tics == start_tics)	// to prevent division by zero
-    return;
-  if (tics < last_tics + 200)	// to prevent flickering updates
-    return;
-  last_tics = tics;
-
-  kbps = ((double)bytes) / (double)(tics - start_tics);
-  if (max_bytes > 0)
-    {
-      int perc = (int)(100.0 * ((double)bytes) / (double)max_bytes);
-      Progress.SetBar1(bytes, max_bytes);
-      sprintf (buf, "%d %%  (%dk/%dk)  %03.1f kB/s",
-	       perc, bytes / 1000, max_bytes / 1000, kbps);
-      if (total_download_bytes > 0)
-     	  Progress.SetBar2(total_download_bytes_sofar + bytes,
-			   total_download_bytes);
-    }
-  else
-    sprintf (buf, "%d  %2.1f kB/s", bytes, kbps);
-
-  Progress.SetText3(buf);
-}
-
-static void
-getUrlToStream (const std::string &_url, io_stream *output)
-{
-  is_local_install = (source == IDC_SOURCE_LOCALDIR);
-  init_dialog (_url, 0);
+  feedback.fetch_init (_url, 0);
   NetIO *n = NetIO::open (_url.c_str(), true);
   if (!n || !n->ok ())
     {
@@ -119,10 +54,10 @@ getUrlToStream (const std::string &_url, io_stream *output)
     }
 
   if (n->file_size)
-    max_bytes = n->file_size;
+    feedback.fetch_set_length(n->file_size);
 
   int total_bytes = 0;
-  progress (0);
+  feedback.fetch_progress (0);
   while (1)
     {
       char buf[2048];
@@ -135,7 +70,7 @@ getUrlToStream (const std::string &_url, io_stream *output)
 	    /* FIXME: Show an error message */
 	    break;
 	  total_bytes += rlen;
-	  progress (total_bytes);
+	  feedback.fetch_progress (total_bytes);
 	}
       else
 	break;
@@ -148,13 +83,13 @@ getUrlToStream (const std::string &_url, io_stream *output)
 }
 
 io_stream *
-get_url_to_membuf (const std::string &_url, HWND owner)
+get_url_to_membuf (const std::string &_url, Feedback &feedback)
 {
   io_stream_memory *membuf = new io_stream_memory ();
-  try 
+  try
     {
-      getUrlToStream (_url, membuf);
-      
+      getUrlToStream (_url, membuf, feedback);
+
       if (membuf->seek (0, IO_SEEK_SET))
     	{
     	  if (membuf)
@@ -175,9 +110,9 @@ get_url_to_membuf (const std::string &_url, HWND owner)
 
 // predicate: url has no '\0''s in it.
 std::string
-get_url_to_string (const std::string &_url, HWND owner)
+get_url_to_string (const std::string &_url, Feedback &feedback)
 {
-  io_stream *stream = get_url_to_membuf (_url, owner);
+  io_stream *stream = get_url_to_membuf (_url, feedback);
   if (!stream)
     return std::string();
   size_t bytes = stream->get_size ();
@@ -200,15 +135,11 @@ int
 get_url_to_file (const std::string &_url,
                  const std::string &_filename,
                  int expected_length,
-		 HWND owner)
+                 Feedback &feedback)
 {
   Log (LOG_BABBLE) << "get_url_to_file " << _url << " " << _filename << endLog;
-  if (total_download_bytes > 0)
-    {
-      int df = diskfull (get_root_dir ().c_str());
-      Progress.SetBar3(df);
-    }
-  init_dialog (_url, expected_length);
+  feedback.fetch_total_progress();
+  feedback.fetch_init(_url, expected_length);
 
   remove (_filename.c_str());		/* but ignore errors */
 
@@ -225,14 +156,14 @@ get_url_to_file (const std::string &_url,
       const char *err = strerror (errno);
       if (!err)
 	err = "(unknown error)";
-      fatal (owner, IDS_ERR_OPEN_WRITE, _filename.c_str(), err);
+      feedback.fetch_fatal (_filename.c_str(), err);
     }
 
   if (n->file_size)
-    max_bytes = n->file_size;
+    feedback.fetch_set_length(n->file_size);
 
   int total_bytes = 0;
-  progress (0);
+  feedback.fetch_progress(0);
   while (1)
     {
       char buf[8192];
@@ -242,22 +173,15 @@ get_url_to_file (const std::string &_url,
 	break;
       fwrite (buf, 1, count, f);
       total_bytes += count;
-      progress (total_bytes);
+      feedback.fetch_progress (total_bytes);
     }
 
-  total_download_bytes_sofar += total_bytes;
-
   fclose (f);
   if (n)
     delete n;
 
-  if (total_download_bytes > 0)
-    {
-      int df = diskfull (get_root_dir ().c_str());
-	  Progress.SetBar3(df);
-    }
-  Progress.SetText3("");
+  feedback.fetch_total_progress();
+  feedback.fetch_finish(total_bytes);
 
   return 0;
 }
-
diff --git a/geturl.h b/geturl.h
index f4e963e..d917543 100644
--- a/geturl.h
+++ b/geturl.h
@@ -16,19 +16,16 @@
 #ifndef SETUP_GETURL_H
 #define SETUP_GETURL_H
 
-/* Download files from the Internet.  These pop up a progress dialog;
-   don't forget to dismiss it when you're done downloading for a while */
+/* Download files from the Internet. */
 
 #include <string>
 
-extern long long int total_download_bytes;
-extern long long int total_download_bytes_sofar;
-
 class io_stream;
+class Feedback;
 
-io_stream *get_url_to_membuf (const std::string &_url, HWND owner);
-std::string get_url_to_string (const std::string &_url, HWND owner);
+io_stream *get_url_to_membuf (const std::string &_url, Feedback &feedback);
+std::string get_url_to_string (const std::string &_url, Feedback &feedback);
 int get_url_to_file (const std::string &_url, const std::string &_filename,
-                     int expected_size, HWND owner);
+                     int expected_size, Feedback &feedback);
 
 #endif /* SETUP_GETURL_H */
diff --git a/gui/GuiFeedback.h b/gui/GuiFeedback.h
new file mode 100644
index 0000000..1dcd42f
--- /dev/null
+++ b/gui/GuiFeedback.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2024 Jon Turney
+ *
+ *     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.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ */
+
+#include "Feedback.h"
+
+class GuiFeedback : public Feedback
+{
+  // constructor
+public:
+  GuiFeedback(HWND hwnd) : owner_window(hwnd) { };
+
+  // ini parse
+public:
+  void parse_init ();
+  void parse_finish ();
+  void progress (unsigned long const, unsigned long const);
+  void iniName (const std::string& );
+  void babble (const std::string& ) const;
+  void warning (const std::string& ) const;
+  void show_errors () const;
+  void note_error(int lineno, const std::string &error);
+  bool has_errors () const;
+
+private:
+  unsigned int lastpct;
+  std::string filename;
+  std::string yyerror_messages;
+  int yyerror_count;
+
+  // URL fetch
+public:
+  void fetch_progress_disable (bool);
+  void fetch_init (const std::string &url, int length);
+  void fetch_set_length(int length);
+  void fetch_set_total_length(long long int total_length);
+  void fetch_progress (int bytes);
+  void fetch_total_progress ();
+  void fetch_finish (int total_bytes);
+  void fetch_fatal (const char *filename, const char *err);
+
+private:
+  int is_local_install = 0;
+  int max_bytes = 0;
+  long long int total_download_bytes = 0;
+  long long int total_download_bytes_sofar = 0;
+  DWORD start_tics;
+
+public:
+  // owner
+  HWND owner () { return owner_window; }
+
+private:
+  HWND owner_window;
+};
diff --git a/gui/GuiGetUrlFeedback.cc b/gui/GuiGetUrlFeedback.cc
new file mode 100644
index 0000000..1b5ce9a
--- /dev/null
+++ b/gui/GuiGetUrlFeedback.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2024 Jon Turney
+ *
+ *     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.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ */
+
+#include "win32.h"
+#include "commctrl.h"
+#include "resource.h"
+#include "diskfull.h"
+#include "mount.h"
+#include "threebar.h"
+#include "msg.h"
+#include "String++.h"
+
+#include "gui/GuiFeedback.h"
+
+extern ThreeBarProgressPage Progress;
+
+void
+GuiFeedback::fetch_set_total_length(long long int total_length)
+{
+  total_download_bytes = total_length;
+  total_download_bytes_sofar = 0;
+}
+
+void
+GuiFeedback::fetch_progress_disable(bool disable)
+{
+  is_local_install = disable;
+}
+
+void
+GuiFeedback::fetch_init (const std::string &url, int length)
+{
+  if (is_local_install)
+    return;
+
+  std::string::size_type divide = url.find_last_of('/');
+  max_bytes = length;
+  Progress.SetText1(IDS_PROGRESS_DOWNLOADING);
+  std::wstring fmt = LoadStringW(IDS_PROGRESS_DOWNLOADING_FROM);
+  std::wstring s = format(fmt,
+                          url.substr(divide + 1).c_str(),
+                          url.substr(0, divide).c_str());
+  Progress.SetText2(s.c_str());
+  Progress.SetText3(IDS_PROGRESS_CONNECTING);
+  Progress.SetBar1(0);
+  start_tics = GetTickCount ();
+}
+
+void
+GuiFeedback::fetch_set_length(int length)
+{
+  max_bytes = length;
+}
+
+void
+GuiFeedback::fetch_progress (int bytes)
+{
+  if (is_local_install)
+    return;
+
+  static char buf[100];
+  double kbps;
+  static unsigned int last_tics = 0;
+  DWORD tics = GetTickCount ();
+  if (tics == start_tics)       // to prevent division by zero
+    return;
+  if (tics < last_tics + 200)   // to prevent flickering updates
+    return;
+  last_tics = tics;
+
+  kbps = ((double)bytes) / (double)(tics - start_tics);
+  if (max_bytes > 0)
+    {
+      int perc = (int)(100.0 * ((double)bytes) / (double)max_bytes);
+      Progress.SetBar1(bytes, max_bytes);
+      sprintf (buf, "%d %%  (%dk/%dk)  %03.1f kB/s",
+               perc, bytes / 1000, max_bytes / 1000, kbps);
+      if (total_download_bytes > 0)
+          Progress.SetBar2(total_download_bytes_sofar + bytes,
+                           total_download_bytes);
+    }
+  else
+    sprintf (buf, "%d  %2.1f kB/s", bytes, kbps);
+
+  Progress.SetText3(buf);
+}
+
+void
+GuiFeedback::fetch_total_progress ()
+{
+  if (total_download_bytes > 0)
+    {
+      int df = diskfull (get_root_dir ().c_str());
+      Progress.SetBar3(df);
+    }
+}
+
+void
+GuiFeedback::fetch_finish (int total_bytes)
+{
+  total_download_bytes_sofar += total_bytes;
+  Progress.SetText3("");
+}
+
+void
+GuiFeedback::fetch_fatal (const char *filename, const char *err)
+{
+  ::fatal (owner_window, IDS_ERR_OPEN_WRITE, filename, err);
+}
diff --git a/gui/GuiParseFeedback.cc b/gui/GuiParseFeedback.cc
index 263fae1..6a2b7bc 100644
--- a/gui/GuiParseFeedback.cc
+++ b/gui/GuiParseFeedback.cc
@@ -14,7 +14,8 @@
  */
 
 #include "Exception.h"
-#include "IniParseFeedback.h"
+#include "gui/GuiFeedback.h"
+
 #include "ini.h"
 #include "msg.h"
 #include "resource.h"
@@ -23,87 +24,96 @@
 
 extern ThreeBarProgressPage Progress;
 
-class GuiParseFeedback : public IniParseFeedback
+void
+GuiFeedback::parse_init ()
 {
-public:
-  GuiParseFeedback () : lastpct (0)
-    {
-      Progress.SetText1 (IDS_PROGRESS_PARSING);
-      Progress.SetText2 ("");
-      Progress.SetText3 ("");
-      Progress.SetText4 (IDS_PROGRESS_PROGRESS);
+  Progress.SetText1 (IDS_PROGRESS_PARSING);
+  Progress.SetText2 ("");
+  Progress.SetText3 ("");
+  Progress.SetText4 (IDS_PROGRESS_PROGRESS);
+
+  lastpct = 0;
+  yyerror_count = 0;
+  yyerror_messages.clear ();
+}
 
-      yyerror_count = 0;
-      yyerror_messages.clear ();
-    }
-  virtual void progress (unsigned long const pos, unsigned long const max)
-    {
-      if (!max)
-        /* length not known or eof */
-        return;
-      if (lastpct == 100)
-        /* rounding down should mean this only ever fires once */
-        lastpct = 0;
-      if (pos * 100 / max > lastpct)
-        {
-          lastpct = pos * 100 / max;
-          /* Log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
-            << " bytes of ini file read)" << endLog; */
-        }
-      Progress.SetBar1 (pos, max);
-
-      static char buf[100];
-      sprintf (buf, "%d %%  (%ldk/%ldk)", lastpct, pos/1000, max/1000);
-      Progress.SetText3 (buf);
-    }
-  virtual void iniName (const std::string& name)
-    {
-      Progress.SetText2 (name.c_str ());
-      Progress.SetText3 ("");
-      filename = name;
-    }
-  virtual void babble (const std::string& message)const
-    {
-      Log (LOG_BABBLE) << message << endLog;
-    }
-  virtual void warning (const std::string& message)const
+void
+GuiFeedback::parse_finish ()
+{
+  Progress.SetText2 ("");
+  Progress.SetText3 ("");
+  Progress.SetText4 (IDS_PROGRESS_PACKAGE);
+  Progress.SetBar1 (0);
+}
+
+void
+GuiFeedback::progress (unsigned long const pos, unsigned long const max)
+{
+  if (!max)
+    /* length not known or eof */
+    return;
+  if (lastpct == 100)
+    /* rounding down should mean this only ever fires once */
+    lastpct = 0;
+  if (pos * 100 / max > lastpct)
     {
-      mbox (Progress.GetHWND(), message.c_str (), "Warning", 0);
+      lastpct = pos * 100 / max;
+      /* Log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
+         << " bytes of ini file read)" << endLog; */
     }
-  virtual void note_error(int lineno, const std::string &error)
-    {
-      char tmp[16];
-      sprintf (tmp, "%d", lineno);
+  Progress.SetBar1 (pos, max);
 
-      std::string e = filename + " line " + tmp + ": " + error;
+  static char buf[100];
+  sprintf (buf, "%d %%  (%ldk/%ldk)", lastpct, pos/1000, max/1000);
+  Progress.SetText3 (buf);
+}
 
-      if (!yyerror_messages.empty ())
-        yyerror_messages += "\n";
+void
+GuiFeedback::iniName (const std::string& name)
+{
+  Progress.SetText2 (name.c_str ());
+  Progress.SetText3 ("");
+  filename = name;
+}
 
-      yyerror_messages += e;
-      yyerror_count++;
-    }
-  virtual bool has_errors () const
-    {
-      return (yyerror_count > 0);
-    }
-  virtual void show_errors () const
-    {
-      mbox (Progress.GetHWND(), yyerror_messages.c_str (), "Parse Errors", 0);
-    }
-  virtual ~ GuiParseFeedback ()
-    {
-      Progress.SetText2 ("");
-      Progress.SetText3 ("");
-      Progress.SetText4 (IDS_PROGRESS_PACKAGE);
-      Progress.SetBar1 (0);
-    }
-private:
-  unsigned int lastpct;
-  std::string filename;
-  std::string yyerror_messages;
-  int yyerror_count;
-};
+void
+GuiFeedback::babble (const std::string& message)const
+{
+  Log (LOG_BABBLE) << message << endLog;
+}
+
+void
+GuiFeedback::warning (const std::string& message)const
+{
+  mbox (Progress.GetHWND(), message.c_str (), "Warning", 0);
+}
+
+void
+GuiFeedback::note_error(int lineno, const std::string &error)
+{
+  char tmp[16];
+  sprintf (tmp, "%d", lineno);
+
+  std::string e = filename + " line " + tmp + ": " + error;
+
+  if (!yyerror_messages.empty ())
+    yyerror_messages += "\n";
+
+  yyerror_messages += e;
+  yyerror_count++;
+}
+
+bool
+GuiFeedback::has_errors () const
+{
+  return (yyerror_count > 0);
+}
+
+void
+GuiFeedback::show_errors () const
+{
+  mbox (Progress.GetHWND(), yyerror_messages.c_str (), "Parse Errors", 0);
+}
 
 static DWORD WINAPI
 do_ini_thread_reflector (void* p)
@@ -115,8 +125,8 @@ do_ini_thread_reflector (void* p)
 
   try
   {
-    GuiParseFeedback feedback;
-    bool succeeded = do_ini_thread ((HINSTANCE)context[0], (HWND)context[1], feedback);
+    GuiFeedback feedback((HWND)context[1]);
+    bool succeeded = do_ini_thread(feedback);
 
     // Tell the progress page that we're done downloading
     Progress.PostMessageNow (WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
diff --git a/gui/SitePage.cc b/gui/SitePage.cc
index 69bac1d..1cdb1bf 100644
--- a/gui/SitePage.cc
+++ b/gui/SitePage.cc
@@ -39,6 +39,7 @@
 #include "ControlAdjuster.h"
 #include "Exception.h"
 #include "String++.h"
+#include "gui/GuiFeedback.h"
 
 #define MIRROR_LIST_URL "https://cygwin.com/mirrors.lst"
 
@@ -200,7 +201,7 @@ migrate_selected_site_list()
 }
 
 static int
-get_site_list (HINSTANCE h, HWND owner)
+get_site_list (Feedback &feedback)
 {
   char *theMirrorString, *theCachedString;
 
@@ -220,7 +221,7 @@ get_site_list (HINSTANCE h, HWND owner)
       cached_mirrors = "";
     }
 
-  std::string mirrors = OnlySiteOption ? std::string ("") : get_url_to_string (MIRROR_LIST_URL, owner);
+  std::string mirrors = OnlySiteOption ? std::string ("") : get_url_to_string (MIRROR_LIST_URL, feedback);
   if (mirrors.size())
     cache_needs_writing = true;
   else
@@ -228,7 +229,7 @@ get_site_list (HINSTANCE h, HWND owner)
       if (!cached_mirrors[0])
         {
           if (!OnlySiteOption)
-            note(owner, IDS_NO_MIRROR_LST);
+            note(feedback.owner(), IDS_NO_MIRROR_LST);
           Log (LOG_BABBLE) << "Defaulting to empty mirror list" << endLog;
         }
       else
@@ -257,27 +258,25 @@ static DWORD WINAPI
 do_download_site_info_thread (void *p)
 {
   HANDLE *context;
-  HINSTANCE hinst;
-  HWND h;
   context = (HANDLE *) p;
 
   SetThreadUILanguage(langid);
 
   try
   {
-    hinst = (HINSTANCE) (context[0]);
-    h = (HWND) (context[1]);
+    GuiFeedback feedback((HWND)(context[1]));
+
     static bool downloaded = false;
-    if (!downloaded && get_site_list (hinst, h))
+    if (!downloaded && get_site_list(feedback))
     {
       // Error: Couldn't download the site info.
       // Go back to the Net setup page.
-      mbox (h, IDS_GET_SITELIST_ERROR, MB_OK);
+      mbox (feedback.owner(), IDS_GET_SITELIST_ERROR, MB_OK);
 
       // Tell the progress page that we're done downloading
       Progress.PostMessageNow (WM_APP_SITE_INFO_DOWNLOAD_COMPLETE, 0, IDD_NET);
     }
-    else 
+    else
     {
       downloaded = true;
       // Everything worked, go to the site select page
diff --git a/ini.cc b/ini.cc
index 3d3cbde..09dda13 100644
--- a/ini.cc
+++ b/ini.cc
@@ -38,7 +38,7 @@
 #include "mount.h"
 #include "SiteSetting.h"
 #include "find.h"
-#include "IniParseFeedback.h"
+#include "Feedback.h"
 
 #include "io_stream.h"
 #include "io_stream_memory.h"
@@ -111,7 +111,7 @@ decompress_ini (io_stream *ini_file, std::string &current_ini_name)
 
 static io_stream*
 check_ini_sig (io_stream* ini_file, io_stream* ini_sig_file,
-	       bool& sig_fail, const char* site, const char* sig_name, HWND owner)
+	       bool& sig_fail, const char* site, const char* sig_name, Feedback &feedback)
 {
   /* Unless the NoVerifyOption is set, check the signature for the
      current setup and record the result.  On a failed signature check
@@ -125,15 +125,15 @@ check_ini_sig (io_stream* ini_file, io_stream* ini_sig_file,
 	// TODO: download the ini + signature file instead
 	if (casecompare (site, "localdir"))
 	  {
-	    note (owner, IDS_SETUPINI_MISSING, sig_name, site);
+	    note (feedback.owner(), IDS_SETUPINI_MISSING, sig_name, site);
 	    delete ini_file;
 	    ini_file = NULL;
 	    sig_fail = true;
 	  }
       }
-      else if (!verify_ini_file_sig (ini_file, ini_sig_file, owner))
+      else if (!verify_ini_file_sig (ini_file, ini_sig_file, feedback))
 	{
-	  note (owner, IDS_SIG_INVALID, sig_name, site);
+	  note (feedback.owner(), IDS_SIG_INVALID, sig_name, site);
 	  delete ini_sig_file;
 	  ini_sig_file = NULL;
 	  delete ini_file;
@@ -145,7 +145,7 @@ check_ini_sig (io_stream* ini_file, io_stream* ini_sig_file,
 }
 
 static bool
-do_local_ini (HWND owner, IniParseFeedback &myFeedback)
+do_local_ini (Feedback &myFeedback)
 {
   bool ini_error = false;
   io_stream *ini_file, *ini_sig_file;
@@ -163,13 +163,13 @@ do_local_ini (HWND owner, IniParseFeedback &myFeedback)
       ini_sig_file = io_stream::open ("file://" + current_ini_sig_name, "rb", 0);
       ini_file = io_stream::open ("file://" + current_ini_name, "rb", 0);
       ini_file = check_ini_sig (ini_file, ini_sig_file, sig_fail,
-				"localdir", current_ini_sig_name.c_str (), owner);
+				"localdir", current_ini_sig_name.c_str (), myFeedback);
       if (ini_file)
 	ini_file = decompress_ini (ini_file, current_ini_name);
       if (!ini_file || sig_fail)
 	{
 	  // no setup found or signature invalid
-	  note (owner, IDS_SETUPINI_MISSING, SetupBaseName.c_str (),
+	  note (myFeedback.owner(), IDS_SETUPINI_MISSING, SetupBaseName.c_str (),
 		"localdir");
 	  ini_error = true;
 	}
@@ -203,7 +203,7 @@ do_local_ini (HWND owner, IniParseFeedback &myFeedback)
 }
 
 static bool
-do_remote_ini (HWND owner, IniParseFeedback &myFeedback)
+do_remote_ini (Feedback &myFeedback)
 {
   bool ini_error = false;
   io_stream *ini_file = NULL, *ini_sig_file;
@@ -226,10 +226,10 @@ do_remote_ini (HWND owner, IniParseFeedback &myFeedback)
 	  current_ini_ext = *ext;
 	  current_ini_name = n->url + SetupIniDir + SetupBaseName + "." + current_ini_ext;
 	  current_ini_sig_name = current_ini_name + ".sig";
-	  ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
-	  ini_file = get_url_to_membuf (current_ini_name, owner);
+	  ini_sig_file = get_url_to_membuf (current_ini_sig_name, myFeedback);
+	  ini_file = get_url_to_membuf (current_ini_name, myFeedback);
 	  ini_file = check_ini_sig (ini_file, ini_sig_file, sig_fail,
-				    n->url.c_str (), current_ini_sig_name.c_str (), owner);
+				    n->url.c_str (), current_ini_sig_name.c_str (), myFeedback);
 	  // stop searching as soon as we find a setup file
 	  if (ini_file)
 	    break;
@@ -239,7 +239,7 @@ do_remote_ini (HWND owner, IniParseFeedback &myFeedback)
       if (!ini_file || sig_fail)
 	{
 	  // no setup found or signature invalid
-	  note (owner, IDS_SETUPINI_MISSING, SetupBaseName.c_str (), n->url.c_str ());
+	  note (myFeedback.owner(), IDS_SETUPINI_MISSING, SetupBaseName.c_str (), n->url.c_str ());
 	  ini_error = true;
 	}
       else
@@ -282,7 +282,7 @@ do_remote_ini (HWND owner, IniParseFeedback &myFeedback)
 }
 
 bool
-do_ini_thread (HINSTANCE h, HWND owner, IniParseFeedback &feedback)
+do_ini_thread (Feedback &feedback)
 {
   packagedb db;
   db.init();
@@ -290,9 +290,9 @@ do_ini_thread (HINSTANCE h, HWND owner, IniParseFeedback &feedback)
   bool ini_error = true;
 
   if (source == IDC_SOURCE_LOCALDIR)
-    ini_error = do_local_ini (owner, feedback);
+    ini_error = do_local_ini (feedback);
   else
-    ini_error = do_remote_ini (owner, feedback);
+    ini_error = do_remote_ini (feedback);
 
   if (ini_error)
     return false;
@@ -314,7 +314,7 @@ do_ini_thread (HINSTANCE h, HWND owner, IniParseFeedback &feedback)
 	  if (old_timestamp && setup_timestamp
 	      && (old_timestamp > setup_timestamp))
 	    {
-	      int yn = yesno (owner, IDS_OLD_SETUPINI);
+	      int yn = yesno (feedback.owner(), IDS_OLD_SETUPINI);
 	      if (yn == IDNO)
 		Logger ().exit (1);
 	    }
@@ -340,7 +340,7 @@ do_ini_thread (HINSTANCE h, HWND owner, IniParseFeedback &feedback)
     {
       if ((version_compare (setup_version, ini_setup_version) < 0)
           && !NoVersionCheckOption)
-	note (owner, IDS_OLD_SETUP_VERSION, setup_version,
+	note (feedback.owner(), IDS_OLD_SETUP_VERSION, setup_version,
 	      ini_setup_version.c_str ());
     }
 
diff --git a/ini.h b/ini.h
index 6b24211..f1788e2 100644
--- a/ini.h
+++ b/ini.h
@@ -31,9 +31,10 @@ extern std::string SetupBaseName;
 
 class io_stream;
 class IniDBBuilder;
-class IniParseFeedback;
-void ini_init (io_stream *, IniDBBuilder *, IniParseFeedback &);
-bool do_ini_thread (HINSTANCE h, HWND owner, IniParseFeedback &feedback);
+class Feedback;
+
+void ini_init (io_stream *, IniDBBuilder *, Feedback &);
+bool do_ini_thread (Feedback &feedback);
 
 #define YYSTYPE char *
 
diff --git a/inilex.ll b/inilex.ll
index e25abf2..8ee9293 100644
--- a/inilex.ll
+++ b/inilex.ll
@@ -25,7 +25,7 @@
 #include "ini.h"
 #include "iniparse.hh"
 #include "String++.h"
-#include "IniParseFeedback.h"
+#include "Feedback.h"
 #include "sha2.h"
 
 #define YY_READ_BUF_SIZE 65536
@@ -167,10 +167,10 @@ B64	[a-zA-Z0-9_-]
 
 static io_stream *input_stream = 0;
 extern IniDBBuilder *iniBuilder;
-static IniParseFeedback *iniFeedback;
+static Feedback *iniFeedback;
 
 void
-ini_init(io_stream *stream, IniDBBuilder *aBuilder, IniParseFeedback &aFeedback)
+ini_init(io_stream *stream, IniDBBuilder *aBuilder, Feedback &aFeedback)
 {
   input_stream = stream;
   iniBuilder = aBuilder;
diff --git a/inilintmain.cc b/inilintmain.cc
index 886c152..9b3b0b3 100644
--- a/inilintmain.cc
+++ b/inilintmain.cc
@@ -15,7 +15,7 @@
 
 #include "io_stream.h"
 #include "IniDBBuilderLint.h"
-#include "CliParseFeedback.h"
+#include "cli/CliFeedback.h"
 #include "ini.h"
 #include <iostream>
 #include <sstream>
@@ -46,7 +46,7 @@ main (int argc, char **argv)
       return 1;
     }
 
-  CliParseFeedback feedback;
+  CliFeedback feedback;
   IniDBBuilderLint builder;
   ini_init(ini_file, &builder, feedback);
 
@@ -63,3 +63,9 @@ get_root_dir ()
   static std::string empty;
   return empty;
 }
+
+void
+fatal (HWND owner, int id, ...)
+{
+  exit(1);
+}
-- 
2.43.0


  parent reply	other threads:[~2024-03-08 18:35 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-08 18:34 [PATCH setup 00/16] Groundwork for a GUI-less installation tool Jon Turney
2024-03-08 18:34 ` [PATCH setup 01/16] Drop forward declaration of non-existent class IniState Jon Turney
2024-03-08 18:34 ` [PATCH setup 02/16] Move setup_exts[] to the only place it's used Jon Turney
2024-03-08 18:34 ` [PATCH setup 03/16] Split GuiParseFeedback out from ini fetcher Jon Turney
2024-03-08 18:34 ` [PATCH setup 04/16] Split out site into SiteSettings and SitePage Jon Turney
2024-03-08 18:34 ` [PATCH setup 05/16] Don't call Antivirus::AtExit() directly from Logger::exit() Jon Turney
2024-03-08 18:34 ` [PATCH setup 06/16] Simplify invocation of UserSettings::open_settings() Jon Turney
2024-03-08 18:34 ` Jon Turney [this message]
2024-03-08 18:34 ` [PATCH setup 08/16] Instantiate found_ini_list in ini.cc Jon Turney
2024-03-08 18:34 ` [PATCH setup 09/16] Move is_64bit to state Jon Turney
2024-03-08 18:34 ` [PATCH setup 10/16] Move setup.ini pathame components to ini.cc Jon Turney
2024-03-08 18:34 ` [PATCH setup 11/16] Drop hinstance global Jon Turney
2024-03-08 18:34 ` [PATCH setup 12/16] Spit out GetNetAuth from NetIO Jon Turney
2024-03-08 18:34 ` [PATCH setup 13/16] Split out hash checking progress reporting Jon Turney
2024-03-08 18:34 ` [PATCH setup 14/16] Push check_for_cached into package_source Jon Turney
2024-03-08 18:34 ` [PATCH setup 15/16] Put various shared subcomponents into a convenience library Jon Turney
2024-03-08 18:34 ` [PATCH setup 16/16] Add beginnings of a command line installation tool Jon Turney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240308183440.4263-8-jon.turney@dronecode.org.uk \
    --to=jon.turney@dronecode.org.uk \
    --cc=cygwin-apps@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).