Partial fix for #5537 default tip
authorJ. Ali Harlow <ali@juiblex.co.uk>
Tue Apr 25 17:41:00 2023 +0100 (2023-04-25)
changeset 1092947214c450e
parent 108 b3d8e196dac8
Partial fix for #5537
app-manager/Makefile.am
app-manager/app-manager.c
app-manager/app-manager.ui
app-manager/localdistributions.c
app-manager/localdistributions.h
app-manager/packagelist.c
app-manager/resources.rc.in
configure.ac
plover-gtk/packagestore.c
plover/Makefile.am
plover/exception-handler.cpp
plover/import-yum.c
plover/log.c
plover/packageset.c
plover/packageset.h
plover/plover.h
plover/plover.pc.in
plover/repository.c
plover/util.c
plover/yumrepository.c
plover/yumrepository.h
pre-inst/pre-inst.c
     1.1 --- a/app-manager/Makefile.am	Tue Jun 29 10:09:34 2021 +0100
     1.2 +++ b/app-manager/Makefile.am	Tue Apr 25 17:41:00 2023 +0100
     1.3 @@ -3,14 +3,15 @@
     1.4  
     1.5  bin_PROGRAMS=app-manager fetch
     1.6  app_manager_SOURCES=app-manager.c app-manager.h packagelist.c applications.c \
     1.7 -	localmedia.c localmedia.h setup.c update.c default_action.c
     1.8 +	localmedia.c localmedia.h setup.c update.c default_action.c \
     1.9 +	localdistributions.c localdistributions.h
    1.10  fetch_SOURCES=fetch.c
    1.11  fetch_LDADD=$(LDADD) $(FETCH_LIBS)
    1.12  if HAVE_WINDRES
    1.13  app_manager_SOURCES+=resources.rc app-manager.exe.manifest
    1.14  endif
    1.15  if PLOVER_MINGW
    1.16 -app_manager_LDFLAGS=-mwindows
    1.17 +#app_manager_LDFLAGS=-mwindows
    1.18  endif
    1.19  uidir=$(pkgdatadir)
    1.20  ui_DATA=app-manager.ui
     2.1 --- a/app-manager/app-manager.c	Tue Jun 29 10:09:34 2021 +0100
     2.2 +++ b/app-manager/app-manager.c	Tue Apr 25 17:41:00 2023 +0100
     2.3 @@ -32,6 +32,7 @@
     2.4  #include <plover-gtk/stockicons.h>
     2.5  #include "app-manager.h"
     2.6  #include "localmedia.h"
     2.7 +#include "localdistributions.h"
     2.8  
     2.9  LUALIB_API int luaopen_posix(lua_State *L);
    2.10  
    2.11 @@ -302,6 +303,17 @@
    2.12  #ifdef WIN32
    2.13      prefix=g_win32_get_package_installation_directory_of_module(NULL);
    2.14  #endif
    2.15 +    if (prefix)
    2.16 +    {
    2.17 +	/*
    2.18 +	 * Note that this won't generally work if the application is stored
    2.19 +	 * on a removable device. If you need the logfile, copy it to the
    2.20 +	 * harddisk first.
    2.21 +	 */
    2.22 +	s=g_strconcat(prefix,"/var/log/init",NULL);
    2.23 +	plover_log_open(s);
    2.24 +	g_free(s);
    2.25 +    }
    2.26      install_icons();
    2.27      ui=gtk_builder_new();
    2.28      if (!g_file_get_contents("app-manager.ui",&contents,&len,&err) &&
    2.29 @@ -384,15 +396,21 @@
    2.30  	    w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles"));
    2.31  	    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),TRUE);
    2.32  	}
    2.33 +	g_clear_object(&set);
    2.34  	applications=plover_applications_model_new(installed);
    2.35  	set_package_model(applications);
    2.36  	w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
    2.37 +	if (prefix)
    2.38 +	{
    2.39 +	    s=g_strconcat(prefix,"/var/log/interactive",NULL);
    2.40 +	    plover_log_open(s);
    2.41 +	    g_free(s);
    2.42 +	}
    2.43  	gtk_widget_show(w);
    2.44  	started=TRUE;
    2.45      }
    2.46      if (started)
    2.47  	gtk_main();
    2.48 -    g_clear_object(&set);
    2.49      objects=gtk_builder_get_objects(ui);
    2.50      for(lnk=objects;lnk;lnk=lnk->next)
    2.51  	if (GTK_IS_WIDGET(lnk->data) &&
    2.52 @@ -454,6 +472,108 @@
    2.53  	set_package_model(location);
    2.54  }
    2.55  
    2.56 +gboolean open_database(const char *uri,const char *destination,GError **err)
    2.57 +{
    2.58 +    gboolean retval;
    2.59 +    GSList *sets,*lnk;
    2.60 +    GtkWidget *w;
    2.61 +    PloverPackageSet *set;
    2.62 +    if (!g_strcmp0(uri,razor_get_database_uri()))
    2.63 +	return TRUE;
    2.64 +    if (relocations)
    2.65 +    {
    2.66 +	razor_relocations_destroy(relocations);
    2.67 +	relocations=NULL;
    2.68 +    }
    2.69 +    razor_set_database_uri(uri);
    2.70 +    if (destination)
    2.71 +    {
    2.72 +	relocations=razor_relocations_create();
    2.73 +	razor_relocations_add(relocations,"/usr",destination);
    2.74 +    }
    2.75 +    sets=plover_package_store_get_sets(PLOVER_PACKAGE_STORE(installed));
    2.76 +    sets=g_slist_copy(sets);
    2.77 +    for(lnk=sets;lnk;lnk=lnk->next)
    2.78 +    {
    2.79 +	set=lnk->data;
    2.80 +	plover_package_store_remove_set(PLOVER_PACKAGE_STORE(installed),set);
    2.81 +    }
    2.82 +    g_slist_free(sets);
    2.83 +    set=plover_package_set_new();
    2.84 +    retval=plover_package_set_open(set,"",TRUE,err);
    2.85 +    plover_package_store_add_set(PLOVER_PACKAGE_STORE(installed),set);
    2.86 +    g_object_unref(set);
    2.87 +    w=GTK_WIDGET(gtk_builder_get_object(ui,"ViewFiles"));
    2.88 +    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
    2.89 +      !!plover_package_set_get_no_details(set));
    2.90 +    return retval;
    2.91 +}
    2.92 +
    2.93 +G_MODULE_EXPORT void on_open_database(GtkWidget *widget)
    2.94 +{
    2.95 +    gboolean have_local_distributions;
    2.96 +    const char *database_uri;
    2.97 +    gchar *uri,*s;
    2.98 +    GList *cells;
    2.99 +    GtkWidget *w,*radio_global,*radio_local,*combo,*dialog;
   2.100 +    GtkCellRenderer *cell;
   2.101 +    GtkTreeModel *local;
   2.102 +    GtkTreeIter iter;
   2.103 +    dialog=GTK_WIDGET(gtk_builder_get_object(ui,"OpenDatabase"));
   2.104 +    local=GTK_TREE_MODEL(plover_local_distributions_new());
   2.105 +    have_local_distributions=!!gtk_tree_model_iter_n_children(local,NULL);
   2.106 +    radio_global=GTK_WIDGET(gtk_builder_get_object(ui,"distribution_global"));
   2.107 +    radio_local=GTK_WIDGET(gtk_builder_get_object(ui,"distribution_local"));
   2.108 +    gtk_widget_set_sensitive(radio_local,have_local_distributions);
   2.109 +    w=GTK_WIDGET(gtk_builder_get_object(ui,"local_databases_label"));
   2.110 +    gtk_widget_set_sensitive(w,have_local_distributions);
   2.111 +    combo=GTK_WIDGET(gtk_builder_get_object(ui,"local_databases"));
   2.112 +    gtk_combo_box_set_model(GTK_COMBO_BOX(combo),local);
   2.113 +    gtk_widget_set_sensitive(w,have_local_distributions);
   2.114 +    database_uri=razor_get_database_uri();
   2.115 +    gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),NULL);
   2.116 +    if (gtk_tree_model_get_iter_first(local,&iter))
   2.117 +	do
   2.118 +	{
   2.119 +	    gtk_tree_model_get(local,&iter,
   2.120 +	      PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN,&s,-1);
   2.121 +	    if (!g_strcmp0(s,database_uri))
   2.122 +		gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),&iter);
   2.123 +	    g_free(s);
   2.124 +	} while(gtk_tree_model_iter_next(local,&iter));
   2.125 +    if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo),&iter))
   2.126 +	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_local),TRUE);
   2.127 +    else
   2.128 +	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio_global),TRUE);
   2.129 +    cells=gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(combo));
   2.130 +    if (cells)
   2.131 +	g_list_free(cells);
   2.132 +    else
   2.133 +    {
   2.134 +	cell=gtk_cell_renderer_text_new();
   2.135 +	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo),cell,TRUE);
   2.136 +	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo),cell,"text",
   2.137 +	  PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN);
   2.138 +    }
   2.139 +    if (gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_ACCEPT)
   2.140 +    {
   2.141 +	show_busy_cursor(TRUE);
   2.142 +	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio_global)))
   2.143 +	    open_database(NULL,prefix,NULL);
   2.144 +	else if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo),&iter))
   2.145 +	{
   2.146 +	    gtk_tree_model_get(local,&iter,
   2.147 +	      PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN,&uri,
   2.148 +	      PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN,&s,-1);
   2.149 +	    open_database(uri,s,NULL);
   2.150 +	    g_free(uri);
   2.151 +	    g_free(s);
   2.152 +	}
   2.153 +	show_busy_cursor(FALSE);
   2.154 +    }
   2.155 +    gtk_widget_hide(dialog);
   2.156 +}
   2.157 +
   2.158  G_MODULE_EXPORT void on_open_location(GtkWidget *widget)
   2.159  {
   2.160      GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
   2.161 @@ -546,6 +666,86 @@
   2.162      show_busy_cursor(FALSE);
   2.163  }
   2.164  
   2.165 +G_MODULE_EXPORT void on_open_archive(GtkWidget *widget)
   2.166 +{
   2.167 +    GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
   2.168 +    GtkWidget *dialog;
   2.169 +    GFile *file,*parent;
   2.170 +    GFileInfo *fi;
   2.171 +    GMount *mount;
   2.172 +    gchar *path,*name;
   2.173 +    PloverPackageSet *set;
   2.174 +    GSList *sets;
   2.175 +    GError *err=NULL;
   2.176 +    dialog=gtk_file_chooser_dialog_new("Open Achive",GTK_WINDOW(w),
   2.177 +      GTK_FILE_CHOOSER_ACTION_OPEN,GTK_STOCK_CANCEL,
   2.178 +      GTK_RESPONSE_CANCEL,GTK_STOCK_OPEN,GTK_RESPONSE_ACCEPT,NULL);
   2.179 +    if (gtk_dialog_run(GTK_DIALOG(dialog))==GTK_RESPONSE_ACCEPT)
   2.180 +    {
   2.181 +	show_busy_cursor(TRUE);
   2.182 +	path=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
   2.183 +	set=plover_package_set_new_from_yum(path,relocations,&err);
   2.184 +	if (set)
   2.185 +	{
   2.186 +	    if (!location)
   2.187 +		location=GTK_TREE_MODEL(plover_package_store_new());
   2.188 +	    while((sets=
   2.189 +	      plover_package_store_get_sets(PLOVER_PACKAGE_STORE(location))))
   2.190 +		plover_package_store_remove_set(PLOVER_PACKAGE_STORE(location),
   2.191 +		  PLOVER_PACKAGE_SET(sets->data));
   2.192 +	    plover_package_store_add_set(PLOVER_PACKAGE_STORE(location),set);
   2.193 +	    g_object_unref(set);
   2.194 +	    w=GTK_WIDGET(gtk_builder_get_object(ui,"LocationButton"));
   2.195 +	    file=g_file_new_for_path(path);
   2.196 +	    parent=g_file_get_parent(file);
   2.197 +	    if (parent)
   2.198 +	    {
   2.199 +		g_object_unref(parent);
   2.200 +		mount=NULL;
   2.201 +	    }
   2.202 +	    else
   2.203 +		mount=g_file_find_enclosing_mount(file,NULL,NULL);
   2.204 +	    if (mount)
   2.205 +	    {
   2.206 +		name=g_mount_get_name(mount);
   2.207 +		g_object_unref(mount);
   2.208 +	    }
   2.209 +	    else
   2.210 +	    {
   2.211 +		fi=g_file_query_info(file,
   2.212 +		  G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
   2.213 +		  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,NULL,NULL);
   2.214 +		if (fi)
   2.215 +		{
   2.216 +		    name=g_strdup(g_file_info_get_display_name(fi));
   2.217 +		    g_object_unref(fi);
   2.218 +		}
   2.219 +		else
   2.220 +		    name=g_filename_display_basename(path);
   2.221 +		g_object_unref(file);
   2.222 +	    }
   2.223 +	    gtk_tool_button_set_label(GTK_TOOL_BUTTON(w),name);
   2.224 +	    g_free(name);
   2.225 +	    gtk_widget_show(w);
   2.226 +	    gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(w),TRUE);
   2.227 +	}
   2.228 +	else
   2.229 +	{
   2.230 +	    gtk_widget_destroy(dialog);
   2.231 +	    dialog=gtk_message_dialog_new(GTK_WINDOW(w),
   2.232 +	      GTK_DIALOG_DESTROY_WITH_PARENT,GTK_MESSAGE_ERROR,
   2.233 +	      GTK_BUTTONS_CLOSE,"Error loading repository '%s'",path);
   2.234 +	    gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
   2.235 +	      "%s",err->message);
   2.236 +	    gtk_dialog_run(GTK_DIALOG(dialog));
   2.237 +	    g_error_free(err);
   2.238 +	}
   2.239 +	g_free(path);
   2.240 +	show_busy_cursor(FALSE);
   2.241 +    }
   2.242 +    gtk_widget_destroy(dialog);
   2.243 +}
   2.244 +
   2.245  G_MODULE_EXPORT void on_help_about(GtkWidget *widget)
   2.246  {
   2.247      GtkWidget *w=GTK_WIDGET(gtk_builder_get_object(ui,"MainWindow"));
     3.1 --- a/app-manager/app-manager.ui	Tue Jun 29 10:09:34 2021 +0100
     3.2 +++ b/app-manager/app-manager.ui	Tue Apr 25 17:41:00 2023 +0100
     3.3 @@ -1,61 +1,76 @@
     3.4 -<?xml version="1.0"?>
     3.5 +<?xml version="1.0" encoding="UTF-8"?>
     3.6  <interface>
     3.7    <requires lib="gtk+" version="2.16"/>
     3.8    <!-- interface-naming-policy project-wide -->
     3.9 +  <object class="GtkTextBuffer" id="description"/>
    3.10 +  <object class="GtkImage" id="image1">
    3.11 +    <property name="visible">True</property>
    3.12 +    <property name="can_focus">False</property>
    3.13 +    <property name="stock">gtk-open</property>
    3.14 +  </object>
    3.15 +  <object class="GtkImage" id="image2">
    3.16 +    <property name="visible">True</property>
    3.17 +    <property name="can_focus">False</property>
    3.18 +    <property name="stock">gtk-cdrom</property>
    3.19 +  </object>
    3.20 +  <object class="GtkImage" id="image3">
    3.21 +    <property name="visible">True</property>
    3.22 +    <property name="can_focus">False</property>
    3.23 +    <property name="stock">gtk-file</property>
    3.24 +  </object>
    3.25 +  <object class="GtkImage" id="image4">
    3.26 +    <property name="visible">True</property>
    3.27 +    <property name="can_focus">False</property>
    3.28 +    <property name="stock">gtk-open</property>
    3.29 +  </object>
    3.30    <object class="GtkWindow" id="MainWindow">
    3.31 +    <property name="can_focus">False</property>
    3.32      <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.33      <property name="title" translatable="yes">Application Manager</property>
    3.34      <property name="default_width">600</property>
    3.35      <property name="default_height">400</property>
    3.36 -    <signal name="delete_event" handler="gtk_main_quit"/>
    3.37 +    <signal name="delete-event" handler="gtk_main_quit" swapped="no"/>
    3.38      <child>
    3.39        <object class="GtkVBox" id="vbox1">
    3.40          <property name="visible">True</property>
    3.41 +        <property name="can_focus">False</property>
    3.42          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.43 -        <property name="orientation">vertical</property>
    3.44          <property name="spacing">6</property>
    3.45          <child>
    3.46            <object class="GtkMenuBar" id="menubar1">
    3.47              <property name="visible">True</property>
    3.48 +            <property name="can_focus">False</property>
    3.49              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.50              <child>
    3.51                <object class="GtkMenuItem" id="menuitem1">
    3.52                  <property name="visible">True</property>
    3.53 +                <property name="can_focus">False</property>
    3.54                  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.55 -                <property name="label" translatable="yes">_Package</property>
    3.56 +                <property name="label" translatable="yes">_Database</property>
    3.57                  <property name="use_underline">True</property>
    3.58                  <child type="submenu">
    3.59 -                  <object class="GtkMenu" id="menu1">
    3.60 +                  <object class="GtkMenu" id="menu4">
    3.61                      <property name="visible">True</property>
    3.62 +                    <property name="can_focus">False</property>
    3.63                      <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.64                      <child>
    3.65 -                      <object class="GtkImageMenuItem" id="imagemenuitem1">
    3.66 -                        <property name="label">Open _Location...</property>
    3.67 +                      <object class="GtkImageMenuItem" id="imagemenuitem3">
    3.68 +                        <property name="label">_Open...</property>
    3.69                          <property name="visible">True</property>
    3.70 +                        <property name="can_focus">False</property>
    3.71                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.72 -                        <property name="tooltip_text" translatable="yes">Open a package repository at a known location</property>
    3.73 +                        <property name="tooltip_text" translatable="yes">Open an existing package database</property>
    3.74                          <property name="use_underline">True</property>
    3.75 -                        <property name="image">image1</property>
    3.76 +                        <property name="image">image4</property>
    3.77                          <property name="use_stock">False</property>
    3.78 -                        <accelerator key="l" signal="activate" modifiers="GDK_CONTROL_MASK"/>
    3.79 -                        <signal name="activate" handler="on_open_location"/>
    3.80 -                      </object>
    3.81 -                    </child>
    3.82 -                    <child>
    3.83 -                      <object class="GtkImageMenuItem" id="menuitem5">
    3.84 -                        <property name="label" translatable="yes">_Scan local media</property>
    3.85 -                        <property name="visible">True</property>
    3.86 -                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
    3.87 -                        <property name="tooltip_text" translatable="yes">Scan local media for package repositories</property>
    3.88 -                        <property name="use_underline">True</property>
    3.89 -                        <property name="image">image2</property>
    3.90 -                        <property name="use_stock">False</property>
    3.91 -                        <signal name="activate" handler="on_scan_local_media"/>
    3.92 +                        <accelerator key="o" signal="activate" modifiers="GDK_CONTROL_MASK"/>
    3.93 +                        <signal name="activate" handler="on_open_database" swapped="no"/>
    3.94                        </object>
    3.95                      </child>
    3.96                      <child>
    3.97                        <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
    3.98                          <property name="visible">True</property>
    3.99 +                        <property name="can_focus">False</property>
   3.100                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.101                        </object>
   3.102                      </child>
   3.103 @@ -63,12 +78,70 @@
   3.104                        <object class="GtkImageMenuItem" id="imagemenuitem5">
   3.105                          <property name="label">gtk-quit</property>
   3.106                          <property name="visible">True</property>
   3.107 +                        <property name="can_focus">False</property>
   3.108                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.109                          <property name="tooltip_text" translatable="yes">Quit the application manager</property>
   3.110                          <property name="use_underline">True</property>
   3.111                          <property name="use_stock">True</property>
   3.112                          <accelerator key="q" signal="activate" modifiers="GDK_CONTROL_MASK"/>
   3.113 -                        <signal name="activate" handler="gtk_main_quit"/>
   3.114 +                        <signal name="activate" handler="gtk_main_quit" swapped="no"/>
   3.115 +                      </object>
   3.116 +                    </child>
   3.117 +                  </object>
   3.118 +                </child>
   3.119 +              </object>
   3.120 +            </child>
   3.121 +            <child>
   3.122 +              <object class="GtkMenuItem" id="menuitem2">
   3.123 +                <property name="visible">True</property>
   3.124 +                <property name="can_focus">False</property>
   3.125 +                <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.126 +                <property name="label" translatable="yes">_Repository</property>
   3.127 +                <property name="use_underline">True</property>
   3.128 +                <child type="submenu">
   3.129 +                  <object class="GtkMenu" id="menu1">
   3.130 +                    <property name="visible">True</property>
   3.131 +                    <property name="can_focus">False</property>
   3.132 +                    <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.133 +                    <child>
   3.134 +                      <object class="GtkImageMenuItem" id="imagemenuitem1">
   3.135 +                        <property name="label">Open _Location...</property>
   3.136 +                        <property name="visible">True</property>
   3.137 +                        <property name="can_focus">False</property>
   3.138 +                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.139 +                        <property name="tooltip_text" translatable="yes">Open a package repository at a known location</property>
   3.140 +                        <property name="use_underline">True</property>
   3.141 +                        <property name="image">image1</property>
   3.142 +                        <property name="use_stock">False</property>
   3.143 +                        <accelerator key="l" signal="activate" modifiers="GDK_CONTROL_MASK"/>
   3.144 +                        <signal name="activate" handler="on_open_location" swapped="no"/>
   3.145 +                      </object>
   3.146 +                    </child>
   3.147 +                    <child>
   3.148 +                      <object class="GtkImageMenuItem" id="menuitem5">
   3.149 +                        <property name="label" translatable="yes">_Scan local media</property>
   3.150 +                        <property name="visible">True</property>
   3.151 +                        <property name="can_focus">False</property>
   3.152 +                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.153 +                        <property name="tooltip_text" translatable="yes">Scan local media for package repositories</property>
   3.154 +                        <property name="use_underline">True</property>
   3.155 +                        <property name="image">image2</property>
   3.156 +                        <property name="use_stock">False</property>
   3.157 +                        <signal name="activate" handler="on_scan_local_media" swapped="no"/>
   3.158 +                      </object>
   3.159 +                    </child>
   3.160 +                    <child>
   3.161 +                      <object class="GtkImageMenuItem" id="imagemenuitem2">
   3.162 +                        <property name="label">Open _Archive...</property>
   3.163 +                        <property name="visible">True</property>
   3.164 +                        <property name="can_focus">False</property>
   3.165 +                        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.166 +                        <property name="tooltip_text" translatable="yes">Open an archived package repository</property>
   3.167 +                        <property name="use_underline">True</property>
   3.168 +                        <property name="image">image3</property>
   3.169 +                        <property name="use_stock">False</property>
   3.170 +                        <accelerator key="a" signal="activate" modifiers="GDK_CONTROL_MASK"/>
   3.171 +                        <signal name="activate" handler="on_open_archive" swapped="no"/>
   3.172                        </object>
   3.173                      </child>
   3.174                    </object>
   3.175 @@ -78,34 +151,38 @@
   3.176              <child>
   3.177                <object class="GtkMenuItem" id="menuitem3">
   3.178                  <property name="visible">True</property>
   3.179 +                <property name="can_focus">False</property>
   3.180                  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.181                  <property name="label" translatable="yes">_View</property>
   3.182                  <property name="use_underline">True</property>
   3.183                  <child type="submenu">
   3.184                    <object class="GtkMenu" id="menu2">
   3.185                      <property name="visible">True</property>
   3.186 +                    <property name="can_focus">False</property>
   3.187                      <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.188                      <child>
   3.189                        <object class="GtkRadioMenuItem" id="ViewFiles">
   3.190                          <property name="visible">True</property>
   3.191 +                        <property name="can_focus">False</property>
   3.192                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.193                          <property name="tooltip_text" translatable="yes">Show a list of files owned by the selected package</property>
   3.194                          <property name="label" translatable="yes">_File list</property>
   3.195                          <property name="use_underline">True</property>
   3.196                          <property name="draw_as_radio">True</property>
   3.197 -                        <signal name="toggled" handler="on_view_files_toggled"/>
   3.198 +                        <signal name="toggled" handler="on_view_files_toggled" swapped="no"/>
   3.199                        </object>
   3.200                      </child>
   3.201                      <child>
   3.202                        <object class="GtkRadioMenuItem" id="menuitem6">
   3.203                          <property name="visible">True</property>
   3.204 +                        <property name="can_focus">False</property>
   3.205                          <property name="tooltip_text" translatable="yes">Show the description etc., of the selected package</property>
   3.206                          <property name="label" translatable="yes">Package _details</property>
   3.207                          <property name="use_underline">True</property>
   3.208                          <property name="active">True</property>
   3.209                          <property name="draw_as_radio">True</property>
   3.210                          <property name="group">ViewFiles</property>
   3.211 -                        <signal name="toggled" handler="on_view_details_toggled"/>
   3.212 +                        <signal name="toggled" handler="on_view_details_toggled" swapped="no"/>
   3.213                        </object>
   3.214                      </child>
   3.215                    </object>
   3.216 @@ -115,22 +192,25 @@
   3.217              <child>
   3.218                <object class="GtkMenuItem" id="menuitem4">
   3.219                  <property name="visible">True</property>
   3.220 +                <property name="can_focus">False</property>
   3.221                  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.222                  <property name="label" translatable="yes">_Help</property>
   3.223                  <property name="use_underline">True</property>
   3.224                  <child type="submenu">
   3.225                    <object class="GtkMenu" id="menu3">
   3.226                      <property name="visible">True</property>
   3.227 +                    <property name="can_focus">False</property>
   3.228                      <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.229                      <child>
   3.230                        <object class="GtkImageMenuItem" id="imagemenuitem10">
   3.231                          <property name="label">gtk-about</property>
   3.232                          <property name="visible">True</property>
   3.233 +                        <property name="can_focus">False</property>
   3.234                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.235                          <property name="tooltip_text" translatable="yes">Display details about the application manager</property>
   3.236                          <property name="use_underline">True</property>
   3.237                          <property name="use_stock">True</property>
   3.238 -                        <signal name="activate" handler="on_help_about"/>
   3.239 +                        <signal name="activate" handler="on_help_about" swapped="no"/>
   3.240                        </object>
   3.241                      </child>
   3.242                    </object>
   3.243 @@ -140,6 +220,7 @@
   3.244            </object>
   3.245            <packing>
   3.246              <property name="expand">False</property>
   3.247 +            <property name="fill">True</property>
   3.248              <property name="position">0</property>
   3.249            </packing>
   3.250          </child>
   3.251 @@ -147,12 +228,12 @@
   3.252            <object class="GtkVPaned" id="vpaned2">
   3.253              <property name="visible">True</property>
   3.254              <property name="can_focus">True</property>
   3.255 -            <property name="orientation">vertical</property>
   3.256              <property name="position">215</property>
   3.257              <property name="position_set">True</property>
   3.258              <child>
   3.259                <object class="GtkAlignment" id="alignment1">
   3.260                  <property name="visible">True</property>
   3.261 +                <property name="can_focus">False</property>
   3.262                  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.263                  <property name="left_padding">6</property>
   3.264                  <property name="right_padding">6</property>
   3.265 @@ -165,12 +246,13 @@
   3.266                      <child>
   3.267                        <object class="GtkVBox" id="vbox2">
   3.268                          <property name="visible">True</property>
   3.269 +                        <property name="can_focus">False</property>
   3.270                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.271 -                        <property name="orientation">vertical</property>
   3.272                          <property name="spacing">6</property>
   3.273                          <child>
   3.274                            <object class="GtkHBox" id="hbox1">
   3.275                              <property name="visible">True</property>
   3.276 +                            <property name="can_focus">False</property>
   3.277                              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.278                              <property name="spacing">6</property>
   3.279                              <child>
   3.280 @@ -178,12 +260,18 @@
   3.281                                  <property name="visible">True</property>
   3.282                                  <property name="can_focus">True</property>
   3.283                                  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.284 -                                <property name="invisible_char">&#x25CF;</property>
   3.285 +                                <property name="invisible_char">●</property>
   3.286                                  <property name="activates_default">True</property>
   3.287                                  <property name="width_chars">10</property>
   3.288                                  <property name="caps_lock_warning">False</property>
   3.289 +                                <property name="primary_icon_activatable">False</property>
   3.290 +                                <property name="secondary_icon_activatable">False</property>
   3.291 +                                <property name="primary_icon_sensitive">True</property>
   3.292 +                                <property name="secondary_icon_sensitive">True</property>
   3.293                                </object>
   3.294                                <packing>
   3.295 +                                <property name="expand">True</property>
   3.296 +                                <property name="fill">True</property>
   3.297                                  <property name="position">0</property>
   3.298                                </packing>
   3.299                              </child>
   3.300 @@ -197,7 +285,7 @@
   3.301                                  <property name="receives_default">True</property>
   3.302                                  <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.303                                  <property name="use_stock">True</property>
   3.304 -                                <signal name="clicked" handler="on_find_clicked"/>
   3.305 +                                <signal name="clicked" handler="on_find_clicked" swapped="no"/>
   3.306                                </object>
   3.307                                <packing>
   3.308                                  <property name="expand">False</property>
   3.309 @@ -215,31 +303,35 @@
   3.310                          <child>
   3.311                            <object class="GtkHBox" id="hbox4">
   3.312                              <property name="visible">True</property>
   3.313 +                            <property name="can_focus">False</property>
   3.314                              <child>
   3.315                                <object class="GtkVSeparator" id="vseparator1">
   3.316                                  <property name="visible">True</property>
   3.317 -                                <property name="orientation">vertical</property>
   3.318 +                                <property name="can_focus">False</property>
   3.319                                </object>
   3.320                                <packing>
   3.321                                  <property name="expand">False</property>
   3.322 +                                <property name="fill">True</property>
   3.323                                  <property name="position">0</property>
   3.324                                </packing>
   3.325                              </child>
   3.326                              <child>
   3.327                                <object class="GtkToolbar" id="toolbar1">
   3.328                                  <property name="visible">True</property>
   3.329 +                                <property name="can_focus">False</property>
   3.330                                  <property name="orientation">vertical</property>
   3.331                                  <property name="icon_size">2</property>
   3.332                                  <property name="icon_size_set">True</property>
   3.333                                  <child>
   3.334                                    <object class="GtkRadioToolButton" id="toolbutton1">
   3.335                                      <property name="visible">True</property>
   3.336 +                                    <property name="can_focus">False</property>
   3.337                                      <property name="tooltip_text" translatable="yes">Show installed applications</property>
   3.338                                      <property name="label" translatable="yes">_Applications</property>
   3.339                                      <property name="use_underline">True</property>
   3.340                                      <property name="stock_id">plover-applications</property>
   3.341                                      <property name="active">True</property>
   3.342 -                                    <signal name="toggled" handler="on_applications_toggled"/>
   3.343 +                                    <signal name="toggled" handler="on_applications_toggled" swapped="no"/>
   3.344                                    </object>
   3.345                                    <packing>
   3.346                                      <property name="expand">False</property>
   3.347 @@ -249,12 +341,13 @@
   3.348                                  <child>
   3.349                                    <object class="GtkRadioToolButton" id="toolbutton2">
   3.350                                      <property name="visible">True</property>
   3.351 +                                    <property name="can_focus">False</property>
   3.352                                      <property name="tooltip_text" translatable="yes">Show all installed packages</property>
   3.353                                      <property name="label" translatable="yes">A_ll Packages</property>
   3.354                                      <property name="use_underline">True</property>
   3.355                                      <property name="stock_id">gtk-index</property>
   3.356                                      <property name="group">toolbutton1</property>
   3.357 -                                    <signal name="toggled" handler="on_all_packages_toggled"/>
   3.358 +                                    <signal name="toggled" handler="on_all_packages_toggled" swapped="no"/>
   3.359                                    </object>
   3.360                                    <packing>
   3.361                                      <property name="expand">False</property>
   3.362 @@ -264,6 +357,7 @@
   3.363                                  <child>
   3.364                                    <object class="GtkSeparatorToolItem" id="toolbutton3">
   3.365                                      <property name="visible">True</property>
   3.366 +                                    <property name="can_focus">False</property>
   3.367                                    </object>
   3.368                                    <packing>
   3.369                                      <property name="expand">False</property>
   3.370 @@ -273,12 +367,13 @@
   3.371                                  <child>
   3.372                                    <object class="GtkRadioToolButton" id="toolbutton5">
   3.373                                      <property name="visible">True</property>
   3.374 +                                    <property name="can_focus">False</property>
   3.375                                      <property name="tooltip_text" translatable="yes">Show packages in repositories on local media</property>
   3.376                                      <property name="label" translatable="yes">Local _Media</property>
   3.377                                      <property name="use_underline">True</property>
   3.378                                      <property name="stock_id">gtk-cdrom</property>
   3.379                                      <property name="group">toolbutton1</property>
   3.380 -                                    <signal name="toggled" handler="on_local_media_toggled"/>
   3.381 +                                    <signal name="toggled" handler="on_local_media_toggled" swapped="no"/>
   3.382                                    </object>
   3.383                                    <packing>
   3.384                                      <property name="expand">False</property>
   3.385 @@ -287,11 +382,12 @@
   3.386                                  </child>
   3.387                                  <child>
   3.388                                    <object class="GtkRadioToolButton" id="LocationButton">
   3.389 +                                    <property name="can_focus">False</property>
   3.390                                      <property name="label" translatable="yes">Location</property>
   3.391                                      <property name="use_underline">True</property>
   3.392                                      <property name="stock_id">gtk-directory</property>
   3.393                                      <property name="group">toolbutton1</property>
   3.394 -                                    <signal name="toggled" handler="on_location_toggled"/>
   3.395 +                                    <signal name="toggled" handler="on_location_toggled" swapped="no"/>
   3.396                                    </object>
   3.397                                    <packing>
   3.398                                      <property name="expand">False</property>
   3.399 @@ -300,6 +396,7 @@
   3.400                                  </child>
   3.401                                  <child>
   3.402                                    <object class="GtkRadioToolButton" id="toolbutton4">
   3.403 +                                    <property name="can_focus">False</property>
   3.404                                      <property name="tooltip_text" translatable="yes">Show updates available for installed packages</property>
   3.405                                      <property name="label" translatable="yes">_Updates</property>
   3.406                                      <property name="use_underline">True</property>
   3.407 @@ -313,21 +410,26 @@
   3.408                                  </child>
   3.409                                </object>
   3.410                                <packing>
   3.411 +                                <property name="expand">True</property>
   3.412 +                                <property name="fill">True</property>
   3.413                                  <property name="position">1</property>
   3.414                                </packing>
   3.415                              </child>
   3.416                              <child>
   3.417                                <object class="GtkVSeparator" id="vseparator2">
   3.418                                  <property name="visible">True</property>
   3.419 -                                <property name="orientation">vertical</property>
   3.420 +                                <property name="can_focus">False</property>
   3.421                                </object>
   3.422                                <packing>
   3.423                                  <property name="expand">False</property>
   3.424 +                                <property name="fill">True</property>
   3.425                                  <property name="position">2</property>
   3.426                                </packing>
   3.427                              </child>
   3.428                            </object>
   3.429                            <packing>
   3.430 +                            <property name="expand">True</property>
   3.431 +                            <property name="fill">True</property>
   3.432                              <property name="position">1</property>
   3.433                            </packing>
   3.434                          </child>
   3.435 @@ -369,11 +471,13 @@
   3.436              <child>
   3.437                <object class="GtkAlignment" id="alignment3">
   3.438                  <property name="visible">True</property>
   3.439 +                <property name="can_focus">False</property>
   3.440                  <property name="left_padding">6</property>
   3.441                  <property name="right_padding">6</property>
   3.442                  <child>
   3.443                    <object class="GtkHBox" id="ActivePackage">
   3.444                      <property name="visible">True</property>
   3.445 +                    <property name="can_focus">False</property>
   3.446                      <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.447                      <property name="spacing">6</property>
   3.448                      <child>
   3.449 @@ -391,6 +495,8 @@
   3.450                          </child>
   3.451                        </object>
   3.452                        <packing>
   3.453 +                        <property name="expand">True</property>
   3.454 +                        <property name="fill">True</property>
   3.455                          <property name="position">0</property>
   3.456                        </packing>
   3.457                      </child>
   3.458 @@ -417,27 +523,33 @@
   3.459                          </child>
   3.460                        </object>
   3.461                        <packing>
   3.462 +                        <property name="expand">True</property>
   3.463 +                        <property name="fill">True</property>
   3.464                          <property name="position">1</property>
   3.465                        </packing>
   3.466                      </child>
   3.467                      <child>
   3.468                        <object class="GtkVBox" id="PackageDetails">
   3.469                          <property name="visible">True</property>
   3.470 -                        <property name="orientation">vertical</property>
   3.471 +                        <property name="can_focus">False</property>
   3.472                          <child>
   3.473                            <object class="GtkAlignment" id="HomepageBox">
   3.474                              <property name="visible">True</property>
   3.475 +                            <property name="can_focus">False</property>
   3.476                              <property name="xscale">0</property>
   3.477                              <property name="yscale">0</property>
   3.478                              <child>
   3.479                                <object class="GtkHBox" id="hbox3">
   3.480                                  <property name="visible">True</property>
   3.481 +                                <property name="can_focus">False</property>
   3.482                                  <child>
   3.483                                    <object class="GtkImage" id="HomeImage">
   3.484                                      <property name="visible">True</property>
   3.485 +                                    <property name="can_focus">False</property>
   3.486                                      <property name="stock">gtk-home</property>
   3.487                                    </object>
   3.488                                    <packing>
   3.489 +                                    <property name="expand">True</property>
   3.490                                      <property name="fill">False</property>
   3.491                                      <property name="position">0</property>
   3.492                                    </packing>
   3.493 @@ -453,6 +565,7 @@
   3.494                                      <property name="uri">http://www.city-occupational.co.uk/</property>
   3.495                                    </object>
   3.496                                    <packing>
   3.497 +                                    <property name="expand">True</property>
   3.498                                      <property name="fill">False</property>
   3.499                                      <property name="position">1</property>
   3.500                                    </packing>
   3.501 @@ -462,6 +575,7 @@
   3.502                            </object>
   3.503                            <packing>
   3.504                              <property name="expand">False</property>
   3.505 +                            <property name="fill">True</property>
   3.506                              <property name="position">0</property>
   3.507                            </packing>
   3.508                          </child>
   3.509 @@ -474,15 +588,18 @@
   3.510                              <child>
   3.511                                <object class="GtkViewport" id="DetailsViewport">
   3.512                                  <property name="visible">True</property>
   3.513 +                                <property name="can_focus">False</property>
   3.514                                  <property name="resize_mode">queue</property>
   3.515                                  <child>
   3.516                                    <object class="GtkAlignment" id="DetailsAlignment">
   3.517                                      <property name="visible">True</property>
   3.518 +                                    <property name="can_focus">False</property>
   3.519                                      <property name="yalign">0</property>
   3.520                                      <property name="yscale">0</property>
   3.521                                      <child>
   3.522                                        <object class="GtkTable" id="Details">
   3.523                                          <property name="visible">True</property>
   3.524 +                                        <property name="can_focus">False</property>
   3.525                                          <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.526                                          <property name="border_width">6</property>
   3.527                                          <property name="n_rows">2</property>
   3.528 @@ -492,6 +609,7 @@
   3.529                                          <child>
   3.530                                            <object class="GtkLabel" id="label6">
   3.531                                              <property name="visible">True</property>
   3.532 +                                            <property name="can_focus">False</property>
   3.533                                              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.534                                              <property name="xalign">0</property>
   3.535                                              <property name="label" translatable="yes">Architecture:</property>
   3.536 @@ -499,12 +617,13 @@
   3.537                                            </object>
   3.538                                            <packing>
   3.539                                              <property name="x_options">GTK_FILL</property>
   3.540 -                                            <property name="y_options"></property>
   3.541 +                                            <property name="y_options"/>
   3.542                                            </packing>
   3.543                                          </child>
   3.544                                          <child>
   3.545                                            <object class="GtkLabel" id="Architecture">
   3.546                                              <property name="visible">True</property>
   3.547 +                                            <property name="can_focus">False</property>
   3.548                                              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.549                                              <property name="xalign">0</property>
   3.550                                              <property name="label" translatable="yes">i386</property>
   3.551 @@ -515,12 +634,13 @@
   3.552                                              <property name="left_attach">1</property>
   3.553                                              <property name="right_attach">2</property>
   3.554                                              <property name="x_options">GTK_FILL</property>
   3.555 -                                            <property name="y_options"></property>
   3.556 +                                            <property name="y_options"/>
   3.557                                            </packing>
   3.558                                          </child>
   3.559                                          <child>
   3.560                                            <object class="GtkLabel" id="label4">
   3.561                                              <property name="visible">True</property>
   3.562 +                                            <property name="can_focus">False</property>
   3.563                                              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.564                                              <property name="xalign">0</property>
   3.565                                              <property name="label" translatable="yes">License:</property>
   3.566 @@ -530,12 +650,13 @@
   3.567                                              <property name="top_attach">1</property>
   3.568                                              <property name="bottom_attach">2</property>
   3.569                                              <property name="x_options">GTK_FILL</property>
   3.570 -                                            <property name="y_options"></property>
   3.571 +                                            <property name="y_options"/>
   3.572                                            </packing>
   3.573                                          </child>
   3.574                                          <child>
   3.575                                            <object class="GtkLabel" id="License">
   3.576                                              <property name="visible">True</property>
   3.577 +                                            <property name="can_focus">False</property>
   3.578                                              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.579                                              <property name="xalign">0</property>
   3.580                                              <property name="label" translatable="yes">LGPL</property>
   3.581 @@ -548,7 +669,7 @@
   3.582                                              <property name="top_attach">1</property>
   3.583                                              <property name="bottom_attach">2</property>
   3.584                                              <property name="x_options">GTK_FILL</property>
   3.585 -                                            <property name="y_options"></property>
   3.586 +                                            <property name="y_options"/>
   3.587                                            </packing>
   3.588                                          </child>
   3.589                                        </object>
   3.590 @@ -559,12 +680,15 @@
   3.591                              </child>
   3.592                            </object>
   3.593                            <packing>
   3.594 +                            <property name="expand">True</property>
   3.595 +                            <property name="fill">True</property>
   3.596                              <property name="position">1</property>
   3.597                            </packing>
   3.598                          </child>
   3.599                        </object>
   3.600                        <packing>
   3.601                          <property name="expand">False</property>
   3.602 +                        <property name="fill">True</property>
   3.603                          <property name="pack_type">end</property>
   3.604                          <property name="position">2</property>
   3.605                        </packing>
   3.606 @@ -579,30 +703,194 @@
   3.607              </child>
   3.608            </object>
   3.609            <packing>
   3.610 +            <property name="expand">True</property>
   3.611 +            <property name="fill">True</property>
   3.612              <property name="position">1</property>
   3.613            </packing>
   3.614          </child>
   3.615          <child>
   3.616            <object class="GtkStatusbar" id="statusbar1">
   3.617              <property name="visible">True</property>
   3.618 +            <property name="can_focus">False</property>
   3.619              <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
   3.620              <property name="spacing">2</property>
   3.621            </object>
   3.622            <packing>
   3.623              <property name="expand">False</property>
   3.624 +            <property name="fill">True</property>
   3.625              <property name="position">2</property>
   3.626            </packing>
   3.627          </child>
   3.628        </object>
   3.629      </child>
   3.630    </object>
   3.631 -  <object class="GtkTextBuffer" id="description"/>
   3.632 -  <object class="GtkImage" id="image1">
   3.633 -    <property name="visible">True</property>
   3.634 -    <property name="stock">gtk-open</property>
   3.635 -  </object>
   3.636 -  <object class="GtkImage" id="image2">
   3.637 -    <property name="visible">True</property>
   3.638 -    <property name="stock">gtk-cdrom</property>
   3.639 +  <object class="GtkDialog" id="OpenDatabase">
   3.640 +    <property name="can_focus">False</property>
   3.641 +    <property name="border_width">5</property>
   3.642 +    <property name="title" translatable="yes">Open Database</property>
   3.643 +    <property name="type_hint">dialog</property>
   3.644 +    <property name="transient_for">MainWindow</property>
   3.645 +    <child internal-child="vbox">
   3.646 +      <object class="GtkVBox" id="dialog-vbox1">
   3.647 +        <property name="visible">True</property>
   3.648 +        <property name="can_focus">False</property>
   3.649 +        <property name="spacing">2</property>
   3.650 +        <child internal-child="action_area">
   3.651 +          <object class="GtkHButtonBox" id="dialog-action_area1">
   3.652 +            <property name="visible">True</property>
   3.653 +            <property name="can_focus">False</property>
   3.654 +            <property name="layout_style">end</property>
   3.655 +            <child>
   3.656 +              <object class="GtkButton" id="button2">
   3.657 +                <property name="label">gtk-cancel</property>
   3.658 +                <property name="visible">True</property>
   3.659 +                <property name="can_focus">True</property>
   3.660 +                <property name="receives_default">True</property>
   3.661 +                <property name="use_stock">True</property>
   3.662 +              </object>
   3.663 +              <packing>
   3.664 +                <property name="expand">False</property>
   3.665 +                <property name="fill">False</property>
   3.666 +                <property name="position">0</property>
   3.667 +              </packing>
   3.668 +            </child>
   3.669 +            <child>
   3.670 +              <object class="GtkButton" id="button3">
   3.671 +                <property name="label">gtk-open</property>
   3.672 +                <property name="visible">True</property>
   3.673 +                <property name="can_focus">True</property>
   3.674 +                <property name="receives_default">True</property>
   3.675 +                <property name="use_stock">True</property>
   3.676 +              </object>
   3.677 +              <packing>
   3.678 +                <property name="expand">False</property>
   3.679 +                <property name="fill">False</property>
   3.680 +                <property name="position">1</property>
   3.681 +              </packing>
   3.682 +            </child>
   3.683 +          </object>
   3.684 +          <packing>
   3.685 +            <property name="expand">True</property>
   3.686 +            <property name="fill">True</property>
   3.687 +            <property name="position">0</property>
   3.688 +          </packing>
   3.689 +        </child>
   3.690 +        <child>
   3.691 +          <object class="GtkVBox" id="vbox3">
   3.692 +            <property name="visible">True</property>
   3.693 +            <property name="can_focus">False</property>
   3.694 +            <property name="border_width">6</property>
   3.695 +            <child>
   3.696 +              <object class="GtkLabel" id="label1">
   3.697 +                <property name="visible">True</property>
   3.698 +                <property name="can_focus">False</property>
   3.699 +                <property name="xalign">0</property>
   3.700 +                <property name="label" translatable="yes">The primary package database for a system is known as the global
   3.701 +database. If a system needs to contain multiple package sets, then
   3.702 +additional ones may be configured as distribution-local databases.
   3.703 +This allows packages within each package set to be independent of
   3.704 +each other.
   3.705 +
   3.706 +If there are no distribution-local databases (or no global one), then
   3.707 +this option will not be available:</property>
   3.708 +              </object>
   3.709 +              <packing>
   3.710 +                <property name="expand">True</property>
   3.711 +                <property name="fill">True</property>
   3.712 +                <property name="position">0</property>
   3.713 +              </packing>
   3.714 +            </child>
   3.715 +            <child>
   3.716 +              <object class="GtkVBox" id="vbox4">
   3.717 +                <property name="visible">True</property>
   3.718 +                <property name="can_focus">False</property>
   3.719 +                <property name="border_width">6</property>
   3.720 +                <child>
   3.721 +                  <object class="GtkRadioButton" id="distribution_global">
   3.722 +                    <property name="label" translatable="yes">Global</property>
   3.723 +                    <property name="visible">True</property>
   3.724 +                    <property name="can_focus">True</property>
   3.725 +                    <property name="receives_default">False</property>
   3.726 +                    <property name="active">True</property>
   3.727 +                    <property name="draw_indicator">True</property>
   3.728 +                  </object>
   3.729 +                  <packing>
   3.730 +                    <property name="expand">True</property>
   3.731 +                    <property name="fill">True</property>
   3.732 +                    <property name="position">0</property>
   3.733 +                  </packing>
   3.734 +                </child>
   3.735 +                <child>
   3.736 +                  <object class="GtkRadioButton" id="distribution_local">
   3.737 +                    <property name="label" translatable="yes">Distribution-local</property>
   3.738 +                    <property name="visible">True</property>
   3.739 +                    <property name="can_focus">True</property>
   3.740 +                    <property name="receives_default">False</property>
   3.741 +                    <property name="active">True</property>
   3.742 +                    <property name="draw_indicator">True</property>
   3.743 +                    <property name="group">distribution_global</property>
   3.744 +                  </object>
   3.745 +                  <packing>
   3.746 +                    <property name="expand">True</property>
   3.747 +                    <property name="fill">True</property>
   3.748 +                    <property name="position">1</property>
   3.749 +                  </packing>
   3.750 +                </child>
   3.751 +              </object>
   3.752 +              <packing>
   3.753 +                <property name="expand">True</property>
   3.754 +                <property name="fill">True</property>
   3.755 +                <property name="position">1</property>
   3.756 +              </packing>
   3.757 +            </child>
   3.758 +            <child>
   3.759 +              <object class="GtkLabel" id="local_databases_label">
   3.760 +                <property name="visible">True</property>
   3.761 +                <property name="can_focus">False</property>
   3.762 +                <property name="xalign">0</property>
   3.763 +                <property name="label" translatable="yes">Each distribution-local database has an associated name and vendor:</property>
   3.764 +              </object>
   3.765 +              <packing>
   3.766 +                <property name="expand">True</property>
   3.767 +                <property name="fill">True</property>
   3.768 +                <property name="position">2</property>
   3.769 +              </packing>
   3.770 +            </child>
   3.771 +            <child>
   3.772 +              <object class="GtkVBox" id="vbox5">
   3.773 +                <property name="visible">True</property>
   3.774 +                <property name="can_focus">False</property>
   3.775 +                <property name="border_width">6</property>
   3.776 +                <child>
   3.777 +                  <object class="GtkComboBox" id="local_databases">
   3.778 +                    <property name="visible">True</property>
   3.779 +                    <property name="can_focus">False</property>
   3.780 +                  </object>
   3.781 +                  <packing>
   3.782 +                    <property name="expand">True</property>
   3.783 +                    <property name="fill">True</property>
   3.784 +                    <property name="position">0</property>
   3.785 +                  </packing>
   3.786 +                </child>
   3.787 +              </object>
   3.788 +              <packing>
   3.789 +                <property name="expand">True</property>
   3.790 +                <property name="fill">True</property>
   3.791 +                <property name="position">3</property>
   3.792 +              </packing>
   3.793 +            </child>
   3.794 +          </object>
   3.795 +          <packing>
   3.796 +            <property name="expand">True</property>
   3.797 +            <property name="fill">True</property>
   3.798 +            <property name="position">1</property>
   3.799 +          </packing>
   3.800 +        </child>
   3.801 +      </object>
   3.802 +    </child>
   3.803 +    <action-widgets>
   3.804 +      <action-widget response="-6">button2</action-widget>
   3.805 +      <action-widget response="-3">button3</action-widget>
   3.806 +    </action-widgets>
   3.807    </object>
   3.808  </interface>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/app-manager/localdistributions.c	Tue Apr 25 17:41:00 2023 +0100
     4.3 @@ -0,0 +1,372 @@
     4.4 +/*
     4.5 + * Copyright (C) 2000  Red Hat, Inc.,  Jonathan Blandford <jrb@redhat.com>
     4.6 + * Copyright (C) 2023  J. Ali Harlow <ali@juiblex.co.uk>
     4.7 + *
     4.8 + * This program is free software; you can redistribute it and/or modify
     4.9 + * it under the terms of the GNU General Public License as published by
    4.10 + * the Free Software Foundation; either version 2 of the License, or
    4.11 + * (at your option) any later version.
    4.12 + *
    4.13 + * This program is distributed in the hope that it will be useful,
    4.14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.16 + * GNU General Public License for more details.
    4.17 + *
    4.18 + * You should have received a copy of the GNU General Public License along
    4.19 + * with this program; if not, write to the Free Software Foundation, Inc.,
    4.20 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 + */
    4.22 +
    4.23 +#include "config.h"
    4.24 +#include <stdlib.h>
    4.25 +#include <string.h>
    4.26 +#include <glib-object.h>
    4.27 +#include <gtk/gtk.h>
    4.28 +#include <plover/plover.h>
    4.29 +#include "localdistributions.h"
    4.30 +
    4.31 +#define VALID_ITER(iter,local) ((iter) && (iter)->user_data && \
    4.32 +	PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local)->stamp==(iter)->stamp)
    4.33 +
    4.34 +static GType column_types[PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS];
    4.35 +
    4.36 +static void
    4.37 +  plover_local_distributions_tree_model_init(GtkTreeModelIface *iface);
    4.38 +
    4.39 +G_DEFINE_TYPE_WITH_CODE(PloverLocalDistributions,plover_local_distributions,
    4.40 +  G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE(GTK_TYPE_TREE_MODEL,
    4.41 +  plover_local_distributions_tree_model_init));
    4.42 +
    4.43 +typedef struct _PloverLocalDistribution {
    4.44 +    gchar *vendor,*distribution,*prefix,*user_friendly,*database_uri;
    4.45 +} PloverLocalDistribution;
    4.46 +
    4.47 +typedef struct _PloverLocalDistributionsPrivate {
    4.48 +    GList *distributions;
    4.49 +    int stamp;
    4.50 +} PloverLocalDistributionsPrivate;
    4.51 +
    4.52 +#define PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(obj)\
    4.53 +				G_TYPE_INSTANCE_GET_PRIVATE(obj,\
    4.54 +				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\
    4.55 +				  PloverLocalDistributionsPrivate)
    4.56 +
    4.57 +PloverLocalDistribution *plover_local_distribution_new(const char *vendor,
    4.58 +  const char *distribution)
    4.59 +{
    4.60 +    gchar *s;
    4.61 +    struct comps *comps;
    4.62 +    PloverLocalDistribution *ld;
    4.63 +    ld=g_new0(PloverLocalDistribution,1);
    4.64 +    ld->vendor=g_strdup(vendor);
    4.65 +    if (distribution)
    4.66 +    {
    4.67 +	ld->distribution=g_strdup(distribution);
    4.68 +	ld->user_friendly=g_strdup_printf("%s (%s)",distribution,vendor);
    4.69 +    }
    4.70 +    else
    4.71 +	ld->user_friendly=g_strdup(vendor);
    4.72 +    comps=plover_comps_new();
    4.73 +    plover_comps_set_vendor(comps,vendor);
    4.74 +    if (distribution)
    4.75 +	plover_comps_set_distribution(comps,distribution);
    4.76 +    ld->prefix=plover_comps_get_default_prefix(comps);
    4.77 +    plover_comps_free(comps);
    4.78 +    s=g_build_filename(ld->prefix,"var","lib","razor",NULL);
    4.79 +    ld->database_uri=razor_path_to_uri(s);
    4.80 +    g_free(s);
    4.81 +    return ld;
    4.82 +}
    4.83 +
    4.84 +void plover_local_distribution_free(PloverLocalDistribution *ld)
    4.85 +{
    4.86 +    if (ld)
    4.87 +    {
    4.88 +	g_free(ld->vendor);
    4.89 +	g_free(ld->distribution);
    4.90 +	g_free(ld->prefix);
    4.91 +	g_free(ld->user_friendly);
    4.92 +	g_free(ld->database_uri);
    4.93 +	g_free(ld);
    4.94 +    }
    4.95 +}
    4.96 +
    4.97 +static void plover_local_distributions_finalize(GObject *obj)
    4.98 +{
    4.99 +    PloverLocalDistributionsPrivate *priv;
   4.100 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(obj);
   4.101 +    g_list_foreach(priv->distributions,(GFunc)plover_local_distribution_free,
   4.102 +      NULL);
   4.103 +    g_list_free(priv->distributions);
   4.104 +    if (G_OBJECT_CLASS(plover_local_distributions_parent_class)->finalize)
   4.105 +	G_OBJECT_CLASS(plover_local_distributions_parent_class)->finalize(obj);
   4.106 +}
   4.107 +
   4.108 +static void
   4.109 +  plover_local_distributions_class_init(PloverLocalDistributionsClass *klass)
   4.110 +{
   4.111 +    GObjectClass *oclass=G_OBJECT_CLASS(klass);
   4.112 +    oclass->finalize=plover_local_distributions_finalize;
   4.113 +    g_type_class_add_private(klass,sizeof(PloverLocalDistributionsPrivate));
   4.114 +    column_types[PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN]=G_TYPE_STRING;
   4.115 +    column_types[PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN]=G_TYPE_STRING;
   4.116 +    column_types[PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN]=G_TYPE_STRING;
   4.117 +    column_types[PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN]=G_TYPE_STRING;
   4.118 +    column_types[PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN]=G_TYPE_STRING;
   4.119 +}
   4.120 +
   4.121 +static GtkTreeModelFlags
   4.122 +plover_local_distributions_get_flags(GtkTreeModel *tree_model)
   4.123 +{
   4.124 +    return GTK_TREE_MODEL_ITERS_PERSIST|GTK_TREE_MODEL_LIST_ONLY;
   4.125 +}
   4.126 +
   4.127 +static gint plover_local_distributions_get_n_columns(GtkTreeModel *tree_model)
   4.128 +{
   4.129 +    return PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS;
   4.130 +}
   4.131 +
   4.132 +static GType
   4.133 +  plover_local_distributions_get_column_type(GtkTreeModel *tree_model,gint indx)
   4.134 +{
   4.135 +    g_return_val_if_fail(indx>=0 && indx<PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS,
   4.136 +      G_TYPE_INVALID);
   4.137 +    return column_types[indx];
   4.138 +}
   4.139 +
   4.140 +static gboolean plover_local_distributions_get_iter(GtkTreeModel *tree_model,
   4.141 +  GtkTreeIter *iter,GtkTreePath *path)
   4.142 +{
   4.143 +    int i;
   4.144 +    PloverLocalDistributionsPrivate *priv;
   4.145 +    PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   4.146 +    PloverLocalDistribution *ld;
   4.147 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local);
   4.148 +    i=gtk_tree_path_get_indices(path)[0];
   4.149 +    ld=g_list_nth_data(priv->distributions,i);
   4.150 +    if (!ld)
   4.151 +	return FALSE;
   4.152 +    iter->stamp=priv->stamp;
   4.153 +    iter->user_data=ld;
   4.154 +    return TRUE;
   4.155 +}
   4.156 +
   4.157 +static GtkTreePath *
   4.158 +  plover_local_distributions_get_path(GtkTreeModel *tree_model,
   4.159 +  GtkTreeIter *iter)
   4.160 +{
   4.161 +    GtkTreePath *path;
   4.162 +    PloverLocalDistributionsPrivate *priv;
   4.163 +    PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   4.164 +    g_return_val_if_fail(VALID_ITER(iter,tree_model),NULL);
   4.165 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local);
   4.166 +    path=gtk_tree_path_new();
   4.167 +    gtk_tree_path_append_index(path,
   4.168 +      g_list_index(priv->distributions,iter->user_data));
   4.169 +    return path;
   4.170 +}
   4.171 +
   4.172 +static void plover_local_distributions_get_value(GtkTreeModel *tree_model,
   4.173 +  GtkTreeIter *iter,gint column,GValue *value)
   4.174 +{
   4.175 +    gchar *s;
   4.176 +    PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   4.177 +    PloverLocalDistribution *ld;
   4.178 +    g_return_if_fail(column>=0 && column<PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS);
   4.179 +    g_return_if_fail(VALID_ITER(iter,local));
   4.180 +    ld=iter->user_data;
   4.181 +    g_value_init(value,column_types[column]);
   4.182 +    switch((PloverLocalDistributionsColumn)column)
   4.183 +    {
   4.184 +	case PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN:
   4.185 +	    g_value_set_string(value,ld->vendor);
   4.186 +	    break;
   4.187 +	case PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN:
   4.188 +	    g_value_set_string(value,ld->distribution);
   4.189 +	    break;
   4.190 +	case PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN:
   4.191 +	    g_value_set_string(value,ld->prefix);
   4.192 +	    break;
   4.193 +	case PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN:
   4.194 +	    g_value_set_string(value,ld->user_friendly);
   4.195 +	    break;
   4.196 +	case PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN:
   4.197 +	    g_value_set_string(value,ld->database_uri);
   4.198 +	    break;
   4.199 +	case PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS:
   4.200 +	    /* Quieten compiler warning */
   4.201 +	    break;
   4.202 +    }
   4.203 +}
   4.204 +
   4.205 +static gboolean
   4.206 +  plover_local_distributions_iter_next(GtkTreeModel *tree_model,
   4.207 +  GtkTreeIter *iter)
   4.208 +{
   4.209 +    GList *lnk;
   4.210 +    PloverLocalDistributions *local=(PloverLocalDistributions *)tree_model;
   4.211 +    PloverLocalDistributionsPrivate *priv;
   4.212 +    g_return_val_if_fail(VALID_ITER(iter,tree_model),FALSE);
   4.213 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(local);
   4.214 +    lnk=g_list_find(priv->distributions,iter->user_data);
   4.215 +    iter->user_data=lnk->next?lnk->next->data:NULL;
   4.216 +    return !!iter->user_data;
   4.217 +}
   4.218 +
   4.219 +static gboolean
   4.220 +  plover_local_distributions_iter_children(GtkTreeModel *tree_model,
   4.221 +  GtkTreeIter *iter,GtkTreeIter *parent)
   4.222 +{
   4.223 +    PloverLocalDistributionsPrivate *priv;
   4.224 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   4.225 +    /* this is a list, nodes have no children */
   4.226 +    if (parent)
   4.227 +	return FALSE;
   4.228 +    if (priv->distributions)
   4.229 +    {
   4.230 +	iter->stamp=priv->stamp;
   4.231 +	iter->user_data=priv->distributions->data;
   4.232 +	return TRUE;
   4.233 +    }
   4.234 +    else
   4.235 +	return FALSE;
   4.236 +}
   4.237 +
   4.238 +static gboolean
   4.239 +  plover_local_distributions_iter_has_child(GtkTreeModel *tree_model,
   4.240 +  GtkTreeIter *iter)
   4.241 +{
   4.242 +    PloverLocalDistributionsPrivate *priv;
   4.243 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   4.244 +    return !!priv->distributions;
   4.245 +}
   4.246 +
   4.247 +static gint plover_local_distributions_iter_n_children(GtkTreeModel *tree_model,
   4.248 +  GtkTreeIter *iter)
   4.249 +{
   4.250 +    PloverLocalDistributionsPrivate *priv;
   4.251 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   4.252 +    if (!iter)
   4.253 +	return g_list_length(priv->distributions);
   4.254 +    g_return_val_if_fail(VALID_ITER(iter,tree_model),-1);
   4.255 +    return 0;
   4.256 +}
   4.257 +
   4.258 +static gboolean
   4.259 +  plover_local_distributions_iter_nth_child(GtkTreeModel *tree_model,
   4.260 +  GtkTreeIter *iter,GtkTreeIter *parent,gint n)
   4.261 +{
   4.262 +    GList *lnk;
   4.263 +    PloverLocalDistributionsPrivate *priv;
   4.264 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(tree_model);
   4.265 +    if (parent)
   4.266 +	return FALSE;
   4.267 +    lnk=g_list_nth(priv->distributions,n);
   4.268 +    if (!lnk)
   4.269 +	return FALSE;
   4.270 +    iter->stamp=priv->stamp;
   4.271 +    iter->user_data=lnk->data;
   4.272 +    return TRUE;
   4.273 +}
   4.274 +
   4.275 +static gboolean plover_local_distributions_iter_parent(GtkTreeModel *tree_model,
   4.276 +  GtkTreeIter *iter,GtkTreeIter *child)
   4.277 +{
   4.278 +    return FALSE;
   4.279 +}
   4.280 +
   4.281 +static void plover_local_distributions_tree_model_init(GtkTreeModelIface *iface)
   4.282 +{
   4.283 +    iface->get_flags=plover_local_distributions_get_flags;
   4.284 +    iface->get_n_columns=plover_local_distributions_get_n_columns;
   4.285 +    iface->get_column_type=plover_local_distributions_get_column_type;
   4.286 +    iface->get_iter=plover_local_distributions_get_iter;
   4.287 +    iface->get_path=plover_local_distributions_get_path;
   4.288 +    iface->get_value=plover_local_distributions_get_value;
   4.289 +    iface->iter_next=plover_local_distributions_iter_next;
   4.290 +    iface->iter_children=plover_local_distributions_iter_children;
   4.291 +    iface->iter_has_child=plover_local_distributions_iter_has_child;
   4.292 +    iface->iter_n_children=plover_local_distributions_iter_n_children;
   4.293 +    iface->iter_nth_child=plover_local_distributions_iter_nth_child;
   4.294 +    iface->iter_parent=plover_local_distributions_iter_parent;
   4.295 +}
   4.296 +
   4.297 +static void plover_local_distributions_init(PloverLocalDistributions *store)
   4.298 +{
   4.299 +    gchar *s;
   4.300 +    const char *vendor_prefix,*vendor,*distribution;
   4.301 +    GDir *vendor_dir,*distribution_dir,*database_dir;
   4.302 +    PloverLocalDistributionsPrivate *priv;
   4.303 +    PloverLocalDistribution *ld;
   4.304 +    priv=PLOVER_LOCAL_DISTRIBUTIONS_GET_PRIVATE(store);
   4.305 +    /*
   4.306 +     * local distribution databases may be found in
   4.307 +     * <vendor-prefix>/$VENDOR/$DISTRIBUTION/var/lib/razor and
   4.308 +     * <vendor-prefix>/$VENDOR/var/lib/razor
   4.309 +     */
   4.310 +    vendor_prefix=plover_get_vendor_prefix();
   4.311 +    g_message("Vendor prefix is %s",vendor_prefix);
   4.312 +    vendor_dir=g_dir_open(vendor_prefix,0,NULL);
   4.313 +    if (!vendor_dir)
   4.314 +    {
   4.315 +	g_warning("Failed to open %s",vendor_prefix);
   4.316 +	return;
   4.317 +    }
   4.318 +    while((vendor=g_dir_read_name(vendor_dir)))
   4.319 +    {
   4.320 +	g_message("Candidate for vendor is %s",vendor);
   4.321 +	s=g_build_filename(vendor_prefix,vendor,NULL);
   4.322 +	distribution_dir=g_dir_open(s,0,NULL);
   4.323 +	g_free(s);
   4.324 +	if (!distribution_dir)
   4.325 +	{
   4.326 +	    g_warning("Failed to open %s/%s",vendor_prefix,vendor);
   4.327 +	    continue;
   4.328 +	}
   4.329 +	while((distribution=g_dir_read_name(distribution_dir)))
   4.330 +	{
   4.331 +	    g_message("Candidate for distribution is %s",distribution);
   4.332 +	    if (!strcmp(distribution,"var"))
   4.333 +	    {
   4.334 +		s=g_build_filename(vendor_prefix,vendor,"var","lib","razor",
   4.335 +		  NULL);
   4.336 +		database_dir=g_dir_open(s,0,NULL);
   4.337 +		g_free(s);
   4.338 +		if (database_dir)
   4.339 +		{
   4.340 +		    ld=plover_local_distribution_new(vendor,NULL);
   4.341 +		    g_message("Found vendor-specific razor database at %s",
   4.342 +		      ld->database_uri);
   4.343 +		    priv->distributions=g_list_prepend(priv->distributions,ld);
   4.344 +		    g_dir_close(database_dir);
   4.345 +		}
   4.346 +		else
   4.347 +		    g_warning("Failed to open %s/%s/var/lib/razor",
   4.348 +		      vendor_prefix,vendor);
   4.349 +	    }
   4.350 +	    s=g_build_filename(vendor_prefix,vendor,distribution,
   4.351 +	      "var","lib","razor",NULL);
   4.352 +	    database_dir=g_dir_open(s,0,NULL);
   4.353 +	    g_free(s);
   4.354 +	    if (database_dir)
   4.355 +	    {
   4.356 +		ld=plover_local_distribution_new(vendor,distribution);
   4.357 +		g_message("Found local-distribution razor database at %s",
   4.358 +		  ld->database_uri);
   4.359 +		priv->distributions=g_list_prepend(priv->distributions,ld);
   4.360 +		g_dir_close(database_dir);
   4.361 +	    }
   4.362 +	    else
   4.363 +		g_warning("Failed to open %s/%s/%s/var/lib/razor",
   4.364 +		  vendor_prefix,vendor,distribution);
   4.365 +	}
   4.366 +	g_dir_close(distribution_dir);
   4.367 +    }
   4.368 +    g_dir_close(vendor_dir);
   4.369 +    priv->stamp=g_random_int();
   4.370 +}
   4.371 +
   4.372 +PloverLocalDistributions *plover_local_distributions_new(void)
   4.373 +{
   4.374 +    return g_object_new(PLOVER_TYPE_LOCAL_DISTRIBUTIONS,NULL);
   4.375 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/app-manager/localdistributions.h	Tue Apr 25 17:41:00 2023 +0100
     5.3 @@ -0,0 +1,52 @@
     5.4 +#ifndef __PLOVER_LOCAL_DISTRIBUTIONS_H__
     5.5 +#define __PLOVER_LOCAL_DISTRIBUTIONS_H__
     5.6 +
     5.7 +#include <glib-object.h>
     5.8 +
     5.9 +G_BEGIN_DECLS
    5.10 +
    5.11 +#define PLOVER_TYPE_LOCAL_DISTRIBUTIONS\
    5.12 +				plover_local_distributions_get_type()
    5.13 +#define PLOVER_LOCAL_DISTRIBUTIONS(obj)\
    5.14 +				G_TYPE_CHECK_INSTANCE_CAST(obj,\
    5.15 +				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\
    5.16 +				  PloverLocalDistributions)
    5.17 +#define PLOVER_LOCAL_DISTRIBUTIONS_CLASS(klass)\
    5.18 +				G_TYPE_CHECK_CLASS_CAST(klass,\
    5.19 +				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\
    5.20 +				  PloverLocalDistributionsClass)
    5.21 +#define PLOVER_IS_LOCAL_DISTRIBUTIONS(obj)\
    5.22 +				G_TYPE_CHECK_INSTANCE_TYPE(obj,\
    5.23 +				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS)
    5.24 +#define PLOVER_IS_LOCAL_DISTRIBUTIONS_CLASS(klass)\
    5.25 +				G_TYPE_CHECK_CLASS_TYPE(obj,\
    5.26 +				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS)
    5.27 +#define PLOVER_LOCAL_DISTRIBUTIONS_GET_CLASS(obj)\
    5.28 +				G_TYPE_INSTANCE_GET_CLASS(obj,\
    5.29 +				  PLOVER_TYPE_LOCAL_DISTRIBUTIONS,\
    5.30 +				  PloverLocalDistributionsClass)
    5.31 +
    5.32 +typedef enum
    5.33 +{
    5.34 +    PLOVER_LOCAL_DISTRIBUTIONS_VENDOR_COLUMN,
    5.35 +    PLOVER_LOCAL_DISTRIBUTIONS_DISTRIBUTION_COLUMN,
    5.36 +    PLOVER_LOCAL_DISTRIBUTIONS_PREFIX_COLUMN,
    5.37 +    PLOVER_LOCAL_DISTRIBUTIONS_USER_FRIENDLY_COLUMN,
    5.38 +    PLOVER_LOCAL_DISTRIBUTIONS_DATABASE_URI_COLUMN,
    5.39 +    PLOVER_LOCAL_DISTRIBUTIONS_NO_COLUMNS
    5.40 +} PloverLocalDistributionsColumn;
    5.41 +
    5.42 +typedef struct _PloverLocalDistributions {
    5.43 +    GObject parent_instance;
    5.44 +} PloverLocalDistributions;
    5.45 +
    5.46 +typedef struct _PloverLocalDistributionsClass {
    5.47 +    GObjectClass parent_class;
    5.48 +} PloverLocalDistributionsClass;
    5.49 +
    5.50 +GType plover_local_distributions_get_type(void) G_GNUC_CONST;
    5.51 +PloverLocalDistributions *plover_local_distributions_new(void);
    5.52 +
    5.53 +G_END_DECLS
    5.54 +
    5.55 +#endif /* __PLOVER_LOCAL_DISTRIBUTIONS_H__ */
     6.1 --- a/app-manager/packagelist.c	Tue Jun 29 10:09:34 2021 +0100
     6.2 +++ b/app-manager/packagelist.c	Tue Apr 25 17:41:00 2023 +0100
     6.3 @@ -20,8 +20,10 @@
     6.4  #include <stdlib.h>
     6.5  #include <string.h>
     6.6  #include <gtk/gtk.h>
     6.7 +#include <plover/plover.h>
     6.8  #include <plover/package.h>
     6.9  #include <plover/packageset.h>
    6.10 +#include <plover/yumrepository.h>
    6.11  #include <plover-gtk/packagestore.h>
    6.12  #include <plover-gtk/packagefilestore.h>
    6.13  #include "app-manager.h"
    6.14 @@ -32,11 +34,18 @@
    6.15  
    6.16  void package_present(PloverPackage *package)
    6.17  {
    6.18 -    gchar *s;
    6.19 +    gchar *s,*prefix,*prefix_path;
    6.20      const char *text,*t;
    6.21 +    char *multiple_prefixes="multiple";
    6.22 +    GError *tmp_err=NULL;
    6.23 +    GSList *sets,*repositories,*lnk;
    6.24      GtkWidget *w;
    6.25      GtkTextBuffer *buf;
    6.26 +    GtkTreeModel *model;
    6.27 +    struct comps *comps;
    6.28 +    PloverPackageSet *set;
    6.29      PloverPackageFileStore *store;
    6.30 +    PloverRepository *repository;
    6.31      buf=GTK_TEXT_BUFFER(gtk_builder_get_object(ui,"description"));
    6.32      if (package)
    6.33      {
    6.34 @@ -44,7 +53,99 @@
    6.35  	g_strdelimit(s,"\t\n",' ');
    6.36      }
    6.37      else
    6.38 -	s=g_strdup("");
    6.39 +    {
    6.40 +	model=gtk_tree_view_get_model(view);
    6.41 +	while(model &&
    6.42 +	  (GTK_IS_TREE_MODEL_FILTER(model) || GTK_IS_TREE_MODEL_SORT(model)))
    6.43 +	{
    6.44 +	    if (GTK_IS_TREE_MODEL_FILTER(model))
    6.45 +		model=
    6.46 +		  gtk_tree_model_filter_get_model(GTK_TREE_MODEL_FILTER(model));
    6.47 +	    else
    6.48 +		model=gtk_tree_model_sort_get_model(GTK_TREE_MODEL_SORT(model));
    6.49 +	}
    6.50 +	repositories=NULL;
    6.51 +	prefix=NULL;
    6.52 +	if (model && PLOVER_IS_PACKAGE_STORE(model))
    6.53 +	{
    6.54 +	    sets=plover_package_store_get_sets(PLOVER_PACKAGE_STORE(model));
    6.55 +	    for(lnk=sets;lnk;lnk=lnk->next)
    6.56 +	    {
    6.57 +		set=lnk->data;
    6.58 +		repository=plover_package_set_get_repository(set);
    6.59 +		if (repository && !g_slist_find(repositories,repository))
    6.60 +		    repositories=g_slist_prepend(repositories,repository);
    6.61 +		t=plover_package_set_guess_prefix(set,tmp_err?NULL:&tmp_err);
    6.62 +		if (!t)
    6.63 +		    continue;
    6.64 +		if (!prefix)
    6.65 +		    prefix=g_strdup(t);
    6.66 +		else if (prefix!=multiple_prefixes && strcmp(prefix,t))
    6.67 +		{
    6.68 +		    g_free(prefix);
    6.69 +		    prefix=multiple_prefixes;
    6.70 +		}
    6.71 +	    }
    6.72 +	    if (prefix==multiple_prefixes)
    6.73 +		s=g_strdup("Multiple install prefixes");
    6.74 +	    else if (repositories)
    6.75 +	    {
    6.76 +		if (prefix!=multiple_prefixes)
    6.77 +		    g_free(prefix);
    6.78 +		prefix=NULL;
    6.79 +		for(lnk=repositories;lnk;lnk=lnk->next)
    6.80 +		{
    6.81 +		    repository=lnk->data;
    6.82 +		    if (PLOVER_IS_YUM_REPOSITORY(repository))
    6.83 +		    {
    6.84 +			comps=plover_yum_repository_get_comps(
    6.85 +			  PLOVER_YUM_REPOSITORY(repository),NULL);
    6.86 +			t=plover_comps_get_default_prefix(comps);
    6.87 +			if (!prefix)
    6.88 +			    prefix=g_strdup(t);
    6.89 +			else if (prefix!=multiple_prefixes && strcmp(prefix,t))
    6.90 +			{
    6.91 +			    g_free(prefix);
    6.92 +			    prefix=multiple_prefixes;
    6.93 +			}
    6.94 +		    }
    6.95 +		}
    6.96 +		if (prefix==multiple_prefixes)
    6.97 +		    s=g_strdup("Repositories intended to be installed to "
    6.98 +		      "multiple destinations");
    6.99 +		else if (prefix)
   6.100 +		{
   6.101 +		    prefix_path=razor_path_from_uri(prefix,NULL);
   6.102 +		    s=g_strdup_printf("Repository intended to be installed to: "
   6.103 +		      "%s",prefix_path?prefix_path:prefix);
   6.104 +		    g_free(prefix_path);
   6.105 +		}
   6.106 +		else
   6.107 +		    s=g_strdup("Repository with no default "
   6.108 +		      "install destination");
   6.109 +	    }
   6.110 +	    else if (prefix)
   6.111 +	    {
   6.112 +		prefix_path=razor_path_from_uri(prefix,NULL);
   6.113 +		s=g_strdup_printf("Installed in: %s",
   6.114 +		  prefix_path?prefix_path:prefix);
   6.115 +		g_free(prefix_path);
   6.116 +	    }
   6.117 +	    else if (sets)
   6.118 +		s=g_strdup("No common installation destination found");
   6.119 +	    else
   6.120 +		s=g_strdup("Empty package store");
   6.121 +	    if (prefix!=multiple_prefixes)
   6.122 +		g_free(prefix);
   6.123 +	    g_slist_free(repositories);
   6.124 +	    g_clear_error(&tmp_err);
   6.125 +	}
   6.126 +	else if (model)
   6.127 +	    s=g_strdup_printf("Unsupported package list container (%s)",
   6.128 +	      G_OBJECT_TYPE_NAME(model));
   6.129 +	else
   6.130 +	    s=g_strdup("No Package list container");
   6.131 +    }
   6.132      gtk_text_buffer_set_text(buf,s,-1);
   6.133      g_free(s);
   6.134      w=GTK_WIDGET(gtk_builder_get_object(ui,"PackageDetails"));
   6.135 @@ -149,6 +250,33 @@
   6.136      }
   6.137  }
   6.138  
   6.139 +static void package_inserted(GtkTreeModel *tree_model,GtkTreePath *path,
   6.140 +  GtkTreeIter *iter,gpointer data)
   6.141 +{
   6.142 +    gchar *s;
   6.143 +    s=gtk_tree_path_to_string(path);
   6.144 +    g_message("package_inserted(%s): %sactive package",
   6.145 +      s,active?"":"no ");
   6.146 +    g_free(s);
   6.147 +    if (!active)
   6.148 +	package_present(NULL);
   6.149 +}
   6.150 +
   6.151 +static void package_deleted(GtkTreeModel *tree_model,GtkTreePath *path,
   6.152 +  gpointer data)
   6.153 +{
   6.154 +    /*
   6.155 +     * If the deleted package was the active one, then selection-changed
   6.156 +     * will be emitted which will handle that case.
   6.157 +     */
   6.158 +    gchar *s;
   6.159 +    s=gtk_tree_path_to_string(path);
   6.160 +    g_message("package_deleted(%s): %sactive package",s,active?"":"no ");
   6.161 +    g_free(s);
   6.162 +    if (!active)
   6.163 +	package_present(NULL);
   6.164 +}
   6.165 +
   6.166  static void package_cell_data_func(GtkTreeViewColumn *column,
   6.167    GtkCellRenderer *cell,GtkTreeModel *model,GtkTreeIter *iter,gpointer data)
   6.168  {
   6.169 @@ -169,9 +297,21 @@
   6.170  void set_package_model(GtkTreeModel *model)
   6.171  {
   6.172      GtkWidget *w;
   6.173 +    GtkTreeModel *old_model;
   6.174      GtkTreeViewColumn *column;
   6.175      GtkCellRenderer *renderer;
   6.176      GtkTreeSelection *selection;
   6.177 +    if (view)
   6.178 +    {
   6.179 +	old_model=gtk_tree_view_get_model(view);
   6.180 +	if (old_model)
   6.181 +	{
   6.182 +	    g_signal_handlers_disconnect_by_func(old_model,
   6.183 +	      G_CALLBACK(package_inserted),NULL);
   6.184 +	    g_signal_handlers_disconnect_by_func(old_model,
   6.185 +	      G_CALLBACK(package_deleted),NULL);
   6.186 +	}
   6.187 +    }
   6.188      if (!view)
   6.189      {
   6.190  	w=GTK_WIDGET(gtk_builder_get_object(ui,"Packages"));
   6.191 @@ -218,9 +358,18 @@
   6.192      }
   6.193      if (view)
   6.194      {
   6.195 +	g_warning("set_package_model: Calling gtk_tree_view_set_model()");
   6.196  	gtk_tree_view_set_model(view,model);
   6.197 +	g_warning("set_package_model: gtk_tree_view_set_model() returns");
   6.198  	gtk_tree_view_set_search_column(view,
   6.199  	  PLOVER_PACKAGE_STORE_NAME_COLUMN);
   6.200 +	if (model)
   6.201 +	{
   6.202 +	    g_signal_connect(model,"row-inserted",G_CALLBACK(package_inserted),
   6.203 +	      NULL);
   6.204 +	    g_signal_connect(model,"row-deleted",G_CALLBACK(package_deleted),
   6.205 +	      NULL);
   6.206 +	}
   6.207      }
   6.208      package_present(NULL);
   6.209  }
     7.1 --- a/app-manager/resources.rc.in	Tue Jun 29 10:09:34 2021 +0100
     7.2 +++ b/app-manager/resources.rc.in	Tue Apr 25 17:41:00 2023 +0100
     7.3 @@ -22,7 +22,7 @@
     7.4  		VALUE "FileVersion","@PACKAGE_VERSION@"
     7.5  		VALUE "InternalName","app-manager"
     7.6  		VALUE "LegalCopyright",
     7.7 -		  "Copyright © 2010 J. Ali Harlow et al"
     7.8 +		  "Copyright © 2010, 2023 J. Ali Harlow et al"
     7.9  		VALUE "OriginalFilename","app-manager.exe"
    7.10  		VALUE "ProductName","plover"
    7.11  		VALUE "ProductVersion","@PACKAGE_VERSION@"
     8.1 --- a/configure.ac	Tue Jun 29 10:09:34 2021 +0100
     8.2 +++ b/configure.ac	Tue Apr 25 17:41:00 2023 +0100
     8.3 @@ -65,9 +65,9 @@
     8.4  #   increment CURRENT and set AGE and REVISION to 0.
     8.5  # - If the interface is the same as the previous version, increment REVISION.
     8.6  #
     8.7 -lt_current=5
     8.8 +lt_current=6
     8.9  lt_revision=0
    8.10 -lt_age=2
    8.11 +lt_age=3
    8.12  LIBPLOVER_LT_VERSION_INFO="$lt_current:$lt_revision:$lt_age"
    8.13  AC_SUBST(LIBPLOVER_LT_VERSION_INFO)
    8.14  
    8.15 @@ -142,8 +142,10 @@
    8.16  PKG_CHECK_MODULES(GMODULE_EXPORT,[gmodule-export-2.0])
    8.17  LIBPLOVER_CFLAGS="$RAZOR_CFLAGS $EXPAT_CFLAGS $ZLIB_CFLAGS $GIO_CFLAGS"
    8.18  LIBPLOVER_LIBS="$RAZOR_LIBS $EXPAT_LIBS $ZLIB_LIBS $GIO_LIBS"
    8.19 +LIBPLOVER_REQUIREMENTS="razor expat zlib glib2"
    8.20  AC_SUBST(LIBPLOVER_CFLAGS)
    8.21  AC_SUBST(LIBPLOVER_LIBS)
    8.22 +AC_SUBST(LIBPLOVER_REQUIREMENTS)
    8.23  PLOVER_GTK_CFLAGS="$GTK_CFLAGS $RAZOR_CFLAGS"
    8.24  PLOVER_GTK_LIBS="$GTK_LIBS $RAZOR_LIBS"
    8.25  AC_SUBST(PLOVER_GTK_CFLAGS)
    8.26 @@ -155,12 +157,6 @@
    8.27  LIBS="$save_LIBS"
    8.28  AC_SUBST(LUA_POSIX_CFLAGS)
    8.29  AC_SUBST(LUA_POSIX_LIBS)
    8.30 -GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $WHELK_CFLAGS $PLOVER_GTK_CFLAGS \
    8.31 -  $LIBPLOVER_CFLAGS $LUA_POSIX_CFLAGS"
    8.32 -GUI_LIBS="$GMODULE_EXPORT_LIBS $WHELK_LIBS $PLOVER_GTK_LIBS \
    8.33 -  $LIBPLOVER_LIBS $LUA_POSIX_LIBS"
    8.34 -AC_SUBST(GUI_CFLAGS)
    8.35 -AC_SUBST(GUI_LIBS)
    8.36  save_PKG_CONFIG="$PKG_CONFIG"
    8.37  PKG_CONFIG="$PKG_CONFIG --static"
    8.38  PKG_CHECK_MODULES(SETUP,[whelk razor >= 0.5.4 expat >= 2.2 zlib gio-2.0],[:],
    8.39 @@ -201,13 +197,28 @@
    8.40        [have_breakpad="yes";REQUIREMENTS="$REQUIREMENTS x11"],[have_breakpad="no"])
    8.41      if test "$have_breakpad" = yes; then
    8.42  	AC_DEFINE([HAVE_BREAKPAD],[1],[Define if breakpad is available.])
    8.43 +	LIBPLOVER_PRIVATE_REQUIREMENTS="breakpad-client"
    8.44 +	# breakpad-client uses C++. This should probably go into
    8.45 +	# Libs.private in breakpad-client.pc
    8.46 +	AS_IF([test -n "$host_mingw"],[
    8.47 +	    static_stdcxx=`$CXX --print-file-name=libstdc++.a`
    8.48 +	    LIBPLOVER_PRIVATE_LIBS="-lversion -lgcc_eh $static_stdcxx"
    8.49 +	])
    8.50      elif test "$with_breakpad" = yes; then
    8.51  	AC_MSG_ERROR([$BREAKPAD_PKG_ERRORS])
    8.52      fi
    8.53  else
    8.54      have_breakpad="no"
    8.55  fi
    8.56 +AC_SUBST(LIBPLOVER_PRIVATE_REQUIREMENTS)
    8.57 +AC_SUBST(LIBPLOVER_PRIVATE_LIBS)
    8.58  AM_CONDITIONAL([HAVE_BREAKPAD],[test $have_breakpad = yes])
    8.59 +GUI_CFLAGS="$GMODULE_EXPORT_CFLAGS $WHELK_CFLAGS $PLOVER_GTK_CFLAGS \
    8.60 +  $LIBPLOVER_CFLAGS $LUA_POSIX_CFLAGS"
    8.61 +GUI_LIBS="$GMODULE_EXPORT_LIBS $WHELK_LIBS $PLOVER_GTK_LIBS \
    8.62 +  $LIBPLOVER_LIBS $LIBPLOVER_PRIVATE_LIBS $LUA_POSIX_LIBS"
    8.63 +AC_SUBST(GUI_CFLAGS)
    8.64 +AC_SUBST(GUI_LIBS)
    8.65  
    8.66  ##################################################
    8.67  # Checks for library functions.
     9.1 --- a/plover-gtk/packagestore.c	Tue Jun 29 10:09:34 2021 +0100
     9.2 +++ b/plover-gtk/packagestore.c	Tue Apr 25 17:41:00 2023 +0100
     9.3 @@ -298,35 +298,64 @@
     9.4      return strcmp(plover_package_get_name(pa),plover_package_get_name(pb));
     9.5  }
     9.6  
     9.7 +static gint
     9.8 +  plover__sequence_iter_compar(gconstpointer a,gconstpointer b)
     9.9 +{
    9.10 +    GSequenceIter *sia=(GSequenceIter *)a;
    9.11 +    GSequenceIter *sib=(GSequenceIter *)b;
    9.12 +    return g_sequence_iter_get_position(sia)-g_sequence_iter_get_position(sib);
    9.13 +}
    9.14 +
    9.15  void plover_package_store_add_set(PloverPackageStore *store,
    9.16    PloverPackageSet *set)
    9.17  {
    9.18 -    GSList *packages,*link;
    9.19 +    GSList *packages,*lnk;
    9.20      GSequenceIter *si;
    9.21      GtkTreeIter ti;
    9.22      GtkTreePath *path;
    9.23 -    gint *indices;
    9.24      PloverPackageStorePrivate *priv;
    9.25      g_return_if_fail(PLOVER_IS_PACKAGE_STORE(store));
    9.26      g_return_if_fail(PLOVER_IS_PACKAGE_SET(set));
    9.27      priv=PLOVER_PACKAGE_STORE_GET_PRIVATE(store);
    9.28      g_return_if_fail(g_slist_find(priv->sets,set) == NULL);
    9.29      g_object_ref(set);
    9.30 +    /*
    9.31 +     * This is a little complicated because we don't want to
    9.32 +     * emit row-inserted until we have actually added set to
    9.33 +     * the list of sets. On the other hand, we don't want to
    9.34 +     * add set to the list of sets until all the packages it
    9.35 +     * contains have been added to the sequence.
    9.36 +     * Thus, this two phase implementation.
    9.37 +     * However, this introduces an addition complication in
    9.38 +     * that the original row numbers are no longer valid as
    9.39 +     * we keep inserting rows. GSequenceIter should deal with
    9.40 +     * this, but it seems to be giving us problems. Just go
    9.41 +     * with the simple solution.
    9.42 +     * Finally, the positions of the result have to be
    9.43 +     * published in increasing order to avoid confusing
    9.44 +     * subscribers.
    9.45 +     */
    9.46 +    packages=plover_package_set_get_packages(set);
    9.47 +    for(lnk=packages;lnk;lnk=lnk->next)
    9.48 +	g_sequence_insert_sorted(priv->seq,lnk->data,
    9.49 +	  plover__package_compar,NULL);
    9.50 +    priv->sets=g_slist_prepend(priv->sets,set);
    9.51 +    priv->stamp++;
    9.52      path=gtk_tree_path_new();
    9.53      gtk_tree_path_append_index(path,0);
    9.54 -    indices=gtk_tree_path_get_indices(path);
    9.55 -    packages=plover_package_set_get_packages(set);
    9.56 -    for(link=packages;link;link=link->next)
    9.57 +    si=g_sequence_get_begin_iter(priv->seq);
    9.58 +    while(!g_sequence_iter_is_end(si))
    9.59      {
    9.60 -	si=g_sequence_insert_sorted(priv->seq,link->data,
    9.61 -	  plover__package_compar,NULL);
    9.62 -	*indices=g_sequence_iter_get_position(si);
    9.63 -	ti.stamp=priv->stamp;
    9.64 -	ti.user_data=si;
    9.65 -	gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti);
    9.66 +	if (g_slist_find(packages,g_sequence_get(si)))
    9.67 +	{
    9.68 +	    ti.stamp=priv->stamp;
    9.69 +	    ti.user_data=si;
    9.70 +	    gtk_tree_model_row_inserted(GTK_TREE_MODEL(store),path,&ti);
    9.71 +	}
    9.72 +	si=g_sequence_iter_next(si);
    9.73 +	gtk_tree_path_next(path);
    9.74      }
    9.75      gtk_tree_path_free(path);
    9.76 -    priv->sets=g_slist_prepend(priv->sets,set);
    9.77  }
    9.78  
    9.79  void plover_package_store_remove_set(PloverPackageStore *store,
    10.1 --- a/plover/Makefile.am	Tue Jun 29 10:09:34 2021 +0100
    10.2 +++ b/plover/Makefile.am	Tue Apr 25 17:41:00 2023 +0100
    10.3 @@ -1,18 +1,18 @@
    10.4 -AM_CFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS)
    10.5 -AM_CXXFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS)
    10.6 -LIBS=$(LIBPLOVER_LIBS)
    10.7 +AM_CFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS) $(BREAKPAD_CFLAGS)
    10.8 +AM_CXXFLAGS=-g $(LIBPLOVER_CFLAGS) $(CODE_COVERAGE_CFLAGS) $(BREAKPAD_CFLAGS)
    10.9 +LIBS=$(LIBPLOVER_LIBS) $(BREAKPAD_LIBS)
   10.10  INCLUDES=-I$(top_srcdir)
   10.11  AM_LDFLAGS=-no-undefined -version-info $(LIBPLOVER_LT_VERSION_INFO) \
   10.12    $(CODE_COVERAGE_LDFLAGS) -export-symbols-regex '^plover_[^_]'
   10.13  
   10.14  pkginclude_HEADERS=plover.h transaction.h package.h packageset.h repository.h \
   10.15 -	inputstream.h
   10.16 +	yumrepository.h inputstream.h
   10.17  
   10.18  lib_LTLIBRARIES=libplover.la
   10.19  libplover_la_SOURCES=$(pkginclude_HEADERS) util.c import-yum.c razor.c comps.c \
   10.20  	log.c vector.c transaction.c package.c packageset.c repository.c \
   10.21 -	uri-handler.c uri-handler.h inputstream.c exception-handler.cpp \
   10.22 -	ascii-ctype.h
   10.23 +	yumrepository.c uri-handler.c uri-handler.h inputstream.c \
   10.24 +	exception-handler.cpp ascii-ctype.h
   10.25  
   10.26  pkgconfigdir=$(libdir)/pkgconfig
   10.27  pkgconfig_DATA=plover.pc
    11.1 --- a/plover/exception-handler.cpp	Tue Jun 29 10:09:34 2021 +0100
    11.2 +++ b/plover/exception-handler.cpp	Tue Apr 25 17:41:00 2023 +0100
    11.3 @@ -17,6 +17,7 @@
    11.4   */
    11.5  
    11.6  #include <cstdlib>
    11.7 +#include "config.h"
    11.8  #include "plover/plover.h"
    11.9  #if defined(HAVE_BREAKPAD) && defined(WIN32)
   11.10  #include <breakpad/client/windows/crash_generation/crash_generation_client.h>
   11.11 @@ -42,7 +43,7 @@
   11.12  	plover_exception_handler=new
   11.13  	  google_breakpad::ExceptionHandler(dump_path,NULL,NULL,NULL,
   11.14  	  google_breakpad::ExceptionHandler::HANDLER_ALL,MiniDumpWithDataSegs,
   11.15 -	  NULL,NULL);
   11.16 +	  (WCHAR *)NULL,NULL);
   11.17  	g_free(dump_path);
   11.18      }
   11.19  #endif	/* HAVE_BREAKPAD && WIN32 */
    12.1 --- a/plover/import-yum.c	Tue Jun 29 10:09:34 2021 +0100
    12.2 +++ b/plover/import-yum.c	Tue Apr 25 17:41:00 2023 +0100
    12.3 @@ -18,454 +18,25 @@
    12.4   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    12.5   */
    12.6  
    12.7 -#define _GNU_SOURCE
    12.8 -
    12.9 -#include <string.h>
   12.10 -#include <stdio.h>
   12.11 -#include <stdint.h>
   12.12 -#include <sys/stat.h>
   12.13 -#include <unistd.h>
   12.14 -#include <fcntl.h>
   12.15 -#include <errno.h>
   12.16 -
   12.17  #include <glib.h>
   12.18 -#include <expat.h>
   12.19 -#include <zlib.h>
   12.20  #include <razor.h>
   12.21 -#include "plover/plover.h"
   12.22 -#include "plover/uri-handler.h"
   12.23 -#include "plover/inputstream.h"
   12.24 +#include <plover/plover.h>
   12.25 +#include <plover/uri-handler.h>
   12.26 +#include "plover/yumrepository.h"
   12.27  
   12.28  /* Import a yum filelist as a razor package set. */
   12.29  
   12.30 -enum {
   12.31 -	YUM_STATE_BEGIN,
   12.32 -	YUM_STATE_PACKAGE_NAME,
   12.33 -	YUM_STATE_PACKAGE_ARCH,
   12.34 -	YUM_STATE_SUMMARY,
   12.35 -	YUM_STATE_DESCRIPTION,
   12.36 -	YUM_STATE_URL,
   12.37 -	YUM_STATE_LICENSE,
   12.38 -	YUM_STATE_CHECKSUM,
   12.39 -	YUM_STATE_REQUIRES,
   12.40 -	YUM_STATE_PROVIDES,
   12.41 -	YUM_STATE_OBSOLETES,
   12.42 -	YUM_STATE_CONFLICTS,
   12.43 -	YUM_STATE_SKIPPING_PACKAGE,
   12.44 -	YUM_STATE_FILE
   12.45 -};
   12.46 -
   12.47 -struct yum_context {
   12.48 -	XML_Parser primary_parser;
   12.49 -	XML_Parser filelists_parser;
   12.50 -	XML_Parser current_parser;
   12.51 -
   12.52 -	struct razor_importer *importer;
   12.53 -	struct import_property_context *current_property_context;
   12.54 -	const char *base_uri;
   12.55 -	GTree *uris;
   12.56 -	char name[256], arch[64], summary[512], description[4096];
   12.57 -	char url[256], license[64], buffer[512], *p;
   12.58 -	char pkgid[128], evr[128];
   12.59 -	uint32_t property_type;
   12.60 -	int state;
   12.61 -
   12.62 -	int total, current;
   12.63 -};
   12.64 -
   12.65 -static uint32_t
   12.66 -yum_to_razor_relation (const char *flags)
   12.67 -{
   12.68 -	if (flags[0] == 'L') {
   12.69 -		if (flags[1] == 'T')
   12.70 -			return RAZOR_PROPERTY_LESS;
   12.71 -		else
   12.72 -			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
   12.73 -	} else if (flags[0] == 'G') {
   12.74 -		if (flags[1] == 'T')
   12.75 -			return RAZOR_PROPERTY_GREATER;
   12.76 -		else
   12.77 -			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
   12.78 -	} else
   12.79 -		return RAZOR_PROPERTY_EQUAL;
   12.80 -}
   12.81 -
   12.82 -static void
   12.83 -yum_primary_start_element(void *data, const char *name, const char **atts)
   12.84 -{
   12.85 -	struct yum_context *ctx = data;
   12.86 -	const char *n, *epoch, *version, *release;
   12.87 -	char buffer[128];
   12.88 -	char *s;
   12.89 -	gchar *nevra;
   12.90 -	uint32_t pre, relation, flags;
   12.91 -	int i;
   12.92 -
   12.93 -	if (ctx->state == YUM_STATE_SKIPPING_PACKAGE)
   12.94 -		return;
   12.95 -
   12.96 -	if (strcmp(name, "metadata") == 0) {
   12.97 -		for (i = 0; atts[i]; i += 2) {
   12.98 -			if (strcmp(atts[i], "packages") == 0)
   12.99 -				ctx->total = atoi(atts[i + 1]);
  12.100 -		}
  12.101 -	} else if (strcmp(name, "package") == 0) {
  12.102 -		*ctx->name=*ctx->arch=*ctx->summary=*ctx->description='\0';
  12.103 -		*ctx->url=*ctx->license='\0';
  12.104 -	} else if (strcmp(name, "name") == 0) {
  12.105 -		ctx->state = YUM_STATE_PACKAGE_NAME;
  12.106 -		ctx->p = ctx->name;
  12.107 -	} else if (strcmp(name, "arch") == 0) {
  12.108 -		ctx->state = YUM_STATE_PACKAGE_ARCH;
  12.109 -		ctx->p = ctx->arch;
  12.110 -	} else if (strcmp(name, "version") == 0) {
  12.111 -		epoch = NULL;
  12.112 -		version = NULL;
  12.113 -		release = NULL;
  12.114 -		for (i = 0; atts[i]; i += 2) {
  12.115 -			if (strcmp(atts[i], "epoch") == 0)
  12.116 -				epoch = atts[i + 1];
  12.117 -			else if (strcmp(atts[i], "ver") == 0)
  12.118 -				version = atts[i + 1];
  12.119 -			else if (strcmp(atts[i], "rel") == 0)
  12.120 -				release = atts[i + 1];
  12.121 -		}
  12.122 -		if (version == NULL || release == NULL) {
  12.123 -			fprintf(stderr, "invalid version tag, "
  12.124 -				"missing version or  release attribute\n");
  12.125 -			return;
  12.126 -		}
  12.127 -
  12.128 -		razor_build_evr(ctx->evr, sizeof ctx->evr, epoch, version,
  12.129 -				release);
  12.130 -		if (!strcmp(ctx->arch, "noarch") ||
  12.131 -		    !strcmp(ctx->arch, razor_system_arch())) {
  12.132 -			razor_importer_begin_package(ctx->importer, ctx->name,
  12.133 -						     ctx->evr, ctx->arch);
  12.134 -		} else
  12.135 -			ctx->state = YUM_STATE_SKIPPING_PACKAGE;
  12.136 -	} else if (strcmp(name, "summary") == 0) {
  12.137 -		ctx->p = ctx->summary;
  12.138 -		ctx->state = YUM_STATE_SUMMARY;
  12.139 -	} else if (strcmp(name, "description") == 0) {
  12.140 -		ctx->p = ctx->description;
  12.141 -		ctx->state = YUM_STATE_DESCRIPTION;
  12.142 -	} else if (strcmp(name, "url") == 0) {
  12.143 -		ctx->p = ctx->url;
  12.144 -		ctx->state = YUM_STATE_URL;
  12.145 -	} else if (strcmp(name, "checksum") == 0) {
  12.146 -		ctx->p = ctx->pkgid;
  12.147 -		ctx->state = YUM_STATE_CHECKSUM;
  12.148 -	} else if (strcmp(name, "location") == 0) {
  12.149 -		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) {
  12.150 -		    for (i = 0; atts[i]; i += 2)
  12.151 -			if (strcmp(atts[i], "href") == 0) {
  12.152 -			    nevra=g_strconcat(ctx->name,"-",ctx->evr,".",
  12.153 -			      ctx->arch,NULL);
  12.154 -			    s=razor_path_relative_to_uri(ctx->base_uri,
  12.155 -			      atts[i + 1],NULL);
  12.156 -			    g_tree_insert(ctx->uris,nevra,g_strdup(s));
  12.157 -			    free(s);
  12.158 -			    break;
  12.159 -			}
  12.160 -		}
  12.161 -	} else if (strcmp(name, "rpm:license") == 0) {
  12.162 -		ctx->p = ctx->license;
  12.163 -		ctx->state = YUM_STATE_LICENSE;
  12.164 -	} else if (strcmp(name, "rpm:requires") == 0) {
  12.165 -		ctx->state = YUM_STATE_REQUIRES;
  12.166 -		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
  12.167 -	} else if (strcmp(name, "rpm:provides") == 0) {
  12.168 -		ctx->state = YUM_STATE_PROVIDES;
  12.169 -		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
  12.170 -	} else if (strcmp(name, "rpm:obsoletes") == 0) {
  12.171 -		ctx->state = YUM_STATE_OBSOLETES;
  12.172 -		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
  12.173 -	} else if (strcmp(name, "rpm:conflicts") == 0) {
  12.174 -		ctx->state = YUM_STATE_CONFLICTS;
  12.175 -		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
  12.176 -	} else if (strcmp(name, "rpm:entry") == 0 &&
  12.177 -		   ctx->state != YUM_STATE_BEGIN) {
  12.178 -		n = NULL;
  12.179 -		epoch = NULL;
  12.180 -		version = NULL;
  12.181 -		release = NULL;
  12.182 -		relation = RAZOR_PROPERTY_EQUAL;
  12.183 -		pre = 0;
  12.184 -		for (i = 0; atts[i]; i += 2) {
  12.185 -			if (strcmp(atts[i], "name") == 0)
  12.186 -				n = atts[i + 1];
  12.187 -			else if (strcmp(atts[i], "epoch") == 0)
  12.188 -				epoch = atts[i + 1];
  12.189 -			else if (strcmp(atts[i], "ver") == 0)
  12.190 -				version = atts[i + 1];
  12.191 -			else if (strcmp(atts[i], "rel") == 0)
  12.192 -				release = atts[i + 1];
  12.193 -			else if (strcmp(atts[i], "flags") == 0)
  12.194 -				relation = yum_to_razor_relation(atts[i + 1]);
  12.195 -			else if (strcmp(atts[i], "pre") == 0)
  12.196 -				pre = RAZOR_PROPERTY_PRE;
  12.197 -		}
  12.198 -
  12.199 -		if (n == NULL) {
  12.200 -			fprintf(stderr, "invalid rpm:entry, "
  12.201 -				"missing name or version attributes\n");
  12.202 -			return;
  12.203 -		}
  12.204 -
  12.205 -		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
  12.206 -		flags = ctx->property_type | relation | pre;
  12.207 -		razor_importer_add_property(ctx->importer, n, flags, buffer);
  12.208 -	}
  12.209 -}
  12.210 -
  12.211 -static void
  12.212 -yum_primary_end_element (void *data, const char *name)
  12.213 -{
  12.214 -	struct yum_context *ctx = data;
  12.215 -
  12.216 -	switch (ctx->state) {
  12.217 -	case YUM_STATE_PACKAGE_NAME:
  12.218 -	case YUM_STATE_PACKAGE_ARCH:
  12.219 -	case YUM_STATE_SUMMARY:
  12.220 -	case YUM_STATE_DESCRIPTION:
  12.221 -	case YUM_STATE_URL:
  12.222 -	case YUM_STATE_LICENSE:
  12.223 -	case YUM_STATE_CHECKSUM:
  12.224 -	case YUM_STATE_FILE:
  12.225 -		ctx->state = YUM_STATE_BEGIN;
  12.226 -		break;
  12.227 -	}
  12.228 -
  12.229 -	if (strcmp(name, "package") == 0) {
  12.230 -		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  12.231 -			razor_importer_add_details(ctx->importer, ctx->summary,
  12.232 -						   ctx->description, ctx->url,
  12.233 -						   ctx->license);
  12.234 -
  12.235 -		XML_StopParser(ctx->current_parser, XML_TRUE);
  12.236 -		ctx->current_parser = ctx->filelists_parser;
  12.237 -	}
  12.238 -}
  12.239 -
  12.240 -static void
  12.241 -yum_character_data (void *data, const XML_Char *s, int len)
  12.242 -{
  12.243 -	struct yum_context *ctx = data;
  12.244 -
  12.245 -	switch (ctx->state) {
  12.246 -	case YUM_STATE_PACKAGE_NAME:
  12.247 -	case YUM_STATE_PACKAGE_ARCH:
  12.248 -	case YUM_STATE_SUMMARY:
  12.249 -	case YUM_STATE_DESCRIPTION:
  12.250 -	case YUM_STATE_URL:
  12.251 -	case YUM_STATE_LICENSE:
  12.252 -	case YUM_STATE_CHECKSUM:
  12.253 -	case YUM_STATE_FILE:
  12.254 -		memcpy(ctx->p, s, len);
  12.255 -		ctx->p += len;
  12.256 -		*ctx->p = '\0';
  12.257 -		break;
  12.258 -	}
  12.259 -}
  12.260 -
  12.261 -static void
  12.262 -yum_filelists_start_element(void *data, const char *name, const char **atts)
  12.263 -{
  12.264 -	struct yum_context *ctx = data;
  12.265 -	const char *pkg, *pkgid;
  12.266 -	int i;
  12.267 -
  12.268 -	if (strcmp(name, "package") == 0 &&
  12.269 -	    ctx->state != YUM_STATE_SKIPPING_PACKAGE) {
  12.270 -		pkg = NULL;
  12.271 -		pkgid = NULL;
  12.272 -		for (i = 0; atts[i]; i += 2) {
  12.273 -			if (strcmp(atts[i], "name") == 0)
  12.274 -				pkg = atts[i + 1];
  12.275 -			else if (strcmp(atts[i], "pkgid") == 0)
  12.276 -				pkgid = atts[i + 1];
  12.277 -		}
  12.278 -		if (strcmp(pkgid, ctx->pkgid) != 0)
  12.279 -			fprintf(stderr, "primary.xml and filelists.xml "
  12.280 -				"mismatch for %s: %s vs %s",
  12.281 -				pkg, pkgid, ctx->pkgid);
  12.282 -	} else if (strcmp(name, "file") == 0) {
  12.283 -		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  12.284 -			ctx->state = YUM_STATE_FILE;
  12.285 -		ctx->p = ctx->buffer;
  12.286 -	}
  12.287 -}
  12.288 -
  12.289 -static void
  12.290 -yum_filelists_end_element (void *data, const char *name)
  12.291 -{
  12.292 -	struct yum_context *ctx = data;
  12.293 -
  12.294 -	if (strcmp(name, "package") == 0) {
  12.295 -		XML_StopParser(ctx->current_parser, XML_TRUE);
  12.296 -		ctx->current_parser = ctx->primary_parser;
  12.297 -		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  12.298 -			razor_importer_finish_package(ctx->importer);
  12.299 -		ctx->state = YUM_STATE_BEGIN;
  12.300 -	} else if (strcmp(name, "file") == 0) {
  12.301 -		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  12.302 -			razor_importer_add_file(ctx->importer, ctx->buffer);
  12.303 -	}
  12.304 -	if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  12.305 -		ctx->state = YUM_STATE_BEGIN;
  12.306 -}
  12.307 -
  12.308 -static int plover_system_arch_is_x86(void)
  12.309 -{
  12.310 -    const char *arch=razor_system_arch();
  12.311 -    if (!arch || arch[0]!='i' || arch[1]<'3' || arch[1]>'6')
  12.312 -	return 0;
  12.313 -    else
  12.314 -	return !strcmp(arch+2,"86");
  12.315 -}
  12.316 -
  12.317 -#define XML_BUFFER_SIZE 4096
  12.318 -
  12.319 -PloverRepository *plover_repository_new_from_yum_uri(const char *base_uri,
  12.320 -  GError **error)
  12.321 -{
  12.322 -    struct yum_context ctx;
  12.323 -    gchar *s,**rpm_uris;
  12.324 -    GPtrArray *uris;
  12.325 -    char *uri;
  12.326 -    const char *name,*version,*arch;
  12.327 -    void *buf;
  12.328 -    gssize len;
  12.329 -    GInputStream *stream;
  12.330 -    GInputStream *primary,*filelists;
  12.331 -    GZlibDecompressor *decompressor;
  12.332 -    XML_ParsingStatus status;
  12.333 -    struct razor_set *razor;
  12.334 -    struct razor_package_iterator *iter;
  12.335 -    struct razor_package *pkg;
  12.336 -    PloverPackageSet *set;
  12.337 -    PloverRepository *repository;
  12.338 -    g_return_val_if_fail(plover__uri_validate(base_uri),NULL);
  12.339 -    plover__uri_handler_init();
  12.340 -    ctx.importer=razor_importer_create();
  12.341 -    ctx.state=YUM_STATE_BEGIN;
  12.342 -    ctx.base_uri=base_uri;
  12.343 -    ctx.primary_parser=XML_ParserCreate(NULL);
  12.344 -    XML_SetUserData(ctx.primary_parser,&ctx);
  12.345 -    XML_SetElementHandler(ctx.primary_parser,yum_primary_start_element,
  12.346 -      yum_primary_end_element);
  12.347 -    XML_SetCharacterDataHandler(ctx.primary_parser,yum_character_data);
  12.348 -    ctx.filelists_parser=XML_ParserCreate(NULL);
  12.349 -    XML_SetUserData(ctx.filelists_parser,&ctx);
  12.350 -    XML_SetElementHandler(ctx.filelists_parser,yum_filelists_start_element,
  12.351 -      yum_filelists_end_element);
  12.352 -    XML_SetCharacterDataHandler(ctx.filelists_parser,yum_character_data);
  12.353 -    uri=razor_path_relative_to_uri(base_uri,"repodata/primary.xml.gz",NULL);
  12.354 -    stream=plover_razor_input_stream_new(uri,error);
  12.355 -    free(uri);
  12.356 -    if (!stream) {
  12.357 -	XML_ParserFree(ctx.primary_parser);
  12.358 -	XML_ParserFree(ctx.filelists_parser);
  12.359 -	return NULL;
  12.360 -    }
  12.361 -    decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
  12.362 -    primary=g_converter_input_stream_new(G_INPUT_STREAM(stream),
  12.363 -      G_CONVERTER(decompressor));
  12.364 -    g_object_unref(stream);
  12.365 -    g_object_unref(decompressor);
  12.366 -    uri=razor_path_relative_to_uri(base_uri,"repodata/filelists.xml.gz",NULL);
  12.367 -    stream=plover_razor_input_stream_new(uri,error);
  12.368 -    free(uri);
  12.369 -    if (!stream) {
  12.370 -	g_object_unref(primary);
  12.371 -	XML_ParserFree(ctx.primary_parser);
  12.372 -	XML_ParserFree(ctx.filelists_parser);
  12.373 -	return NULL;
  12.374 -    }
  12.375 -    decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
  12.376 -    filelists=g_converter_input_stream_new(G_INPUT_STREAM(stream),
  12.377 -      G_CONVERTER(decompressor));
  12.378 -    g_object_unref(stream);
  12.379 -    g_object_unref(decompressor);
  12.380 -    ctx.current_parser=ctx.primary_parser;
  12.381 -    ctx.uris=g_tree_new_full((GCompareDataFunc)strcmp,NULL,g_free,NULL);
  12.382 -    ctx.current=0;
  12.383 -    do
  12.384 -    {
  12.385 -	XML_GetParsingStatus(ctx.current_parser,&status);
  12.386 -	switch (status.parsing)
  12.387 -	{
  12.388 -	    case XML_SUSPENDED:
  12.389 -		XML_ResumeParser(ctx.current_parser);
  12.390 -		break;
  12.391 -	    case XML_PARSING:
  12.392 -	    case XML_INITIALIZED:
  12.393 -		buf=XML_GetBuffer(ctx.current_parser,XML_BUFFER_SIZE);
  12.394 -		if (ctx.current_parser==ctx.primary_parser)
  12.395 -		    len=g_input_stream_read(G_INPUT_STREAM(primary),buf,
  12.396 -		      XML_BUFFER_SIZE,NULL,error);
  12.397 -		else
  12.398 -		    len=g_input_stream_read(G_INPUT_STREAM(filelists),buf,
  12.399 -		      XML_BUFFER_SIZE,NULL,error);
  12.400 -		if (len<0)
  12.401 -		    return NULL;
  12.402 -		XML_ParseBuffer(ctx.current_parser,len,!len);
  12.403 -		break;
  12.404 -	    case XML_FINISHED:
  12.405 -		break;
  12.406 -	}
  12.407 -    } while (status.parsing!=XML_FINISHED);
  12.408 -    XML_ParserFree(ctx.primary_parser);
  12.409 -    XML_ParserFree(ctx.filelists_parser);
  12.410 -    g_object_unref(primary);
  12.411 -    g_object_unref(filelists);
  12.412 -    razor=razor_importer_finish(ctx.importer);
  12.413 -#if RAZOR_HEADER_VERSION_MIN<=1
  12.414 -    /*
  12.415 -     * Header version 1 is supported by plover v0.3 and is used on
  12.416 -     * 32-bit intel machines which allows the setup and update
  12.417 -     * applications from v0.3 to work. On other machines, we don't
  12.418 -     * want these old applications to work (since they would do
  12.419 -     * the wrong thing) and so we use the current header version
  12.420 -     * which they don't support.
  12.421 -     */
  12.422 -    if (plover_system_arch_is_x86())
  12.423 -	razor_set_set_header_version(razor,1);
  12.424 -#endif
  12.425 -    uris=g_ptr_array_new();
  12.426 -    iter=razor_package_iterator_create(razor);
  12.427 -    while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_NAME,&name,
  12.428 -      RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST))
  12.429 -    {
  12.430 -	s=g_strconcat(name,"-",version,".",arch,NULL);
  12.431 -	g_ptr_array_add(uris,g_tree_lookup(ctx.uris,s));
  12.432 -	g_free(s);
  12.433 -    }
  12.434 -    razor_package_iterator_destroy(iter);
  12.435 -    g_ptr_array_add(uris,NULL);
  12.436 -    g_tree_unref(ctx.uris);
  12.437 -    rpm_uris=(gchar **)g_ptr_array_free(uris,FALSE);
  12.438 -    set=plover_package_set_new_from_razor(razor);
  12.439 -    razor_set_unref(razor);
  12.440 -    repository=plover_repository_new_from_package_set(set,
  12.441 -      (const char **)rpm_uris);
  12.442 -    g_object_unref(set);
  12.443 -    g_strfreev(rpm_uris);
  12.444 -    return repository;
  12.445 -}
  12.446 -
  12.447  struct razor_set *plover_razor_set_create_from_yum_uri(const char *base_uri,
  12.448    GError **error)
  12.449  {
  12.450 -    PloverRepository *repository;
  12.451 +    PloverYumRepository *repository;
  12.452      PloverPackageSet *set;
  12.453      struct razor_set *razor;
  12.454      g_return_val_if_fail(plover__uri_validate(base_uri),NULL);
  12.455 -    repository=plover_repository_new_from_yum_uri(base_uri,error);
  12.456 +    repository=plover_yum_repository_new_from_uri(base_uri,error);
  12.457      if (!repository)
  12.458  	return NULL;
  12.459 -    set=plover_repository_get_package_set(repository);
  12.460 +    set=plover_repository_get_package_set(PLOVER_REPOSITORY(repository));
  12.461      razor=plover_package_set_get_razor(set);
  12.462      razor_set_ref(razor);
  12.463      g_object_unref(repository);
    13.1 --- a/plover/log.c	Tue Jun 29 10:09:34 2021 +0100
    13.2 +++ b/plover/log.c	Tue Apr 25 17:41:00 2023 +0100
    13.3 @@ -288,6 +288,7 @@
    13.4  
    13.5  int plover_log_open(const char *path)
    13.6  {
    13.7 +    static gchar *logfile=NULL;
    13.8      int retval;
    13.9      char *root;
   13.10      gchar *filename,*uri;
   13.11 @@ -367,7 +368,8 @@
   13.12  	g_free(filename);
   13.13  	return -1;
   13.14      }
   13.15 -    g_free(filename);
   13.16 +    if (logfile)
   13.17 +	printf("Switching logging to %s on %s",filename,ctime(&t));
   13.18  #ifdef WIN32
   13.19      /*
   13.20       * The situation under MS-Windows is a little complicated. If standard
   13.21 @@ -402,7 +404,17 @@
   13.22      SetStdHandle(STD_ERROR_HANDLE,(HANDLE)_get_osfhandle(2));
   13.23  #endif
   13.24      time(&t);
   13.25 -    printf("Run started on %s",ctime(&t));
   13.26 +    if (logfile)
   13.27 +    {
   13.28 +	printf("Logging switched from %s on %s",logfile,ctime(&t));
   13.29 +	g_free(logfile);
   13.30 +	logfile=filename;
   13.31 +    }
   13.32 +    else
   13.33 +    {
   13.34 +	printf("Run started on %s",ctime(&t));
   13.35 +	logfile=filename;
   13.36 +    }
   13.37      fflush(stdout);
   13.38      return 0;
   13.39  }
    14.1 --- a/plover/packageset.c	Tue Jun 29 10:09:34 2021 +0100
    14.2 +++ b/plover/packageset.c	Tue Apr 25 17:41:00 2023 +0100
    14.3 @@ -1,5 +1,5 @@
    14.4  /*
    14.5 - * Copyright (C) 2010-2012, 2014  J. Ali Harlow <ali@juiblex.co.uk>
    14.6 + * Copyright (C) 2010-2012, 2014, 2023  J. Ali Harlow <ali@juiblex.co.uk>
    14.7   *
    14.8   * This program is free software; you can redistribute it and/or modify
    14.9   * it under the terms of the GNU General Public License as published by
   14.10 @@ -38,6 +38,7 @@
   14.11      GSList *packages;
   14.12      int no_details;
   14.13      gchar *guessed_prefix;
   14.14 +    PloverRepository *repository;
   14.15  } PloverPackageSetPrivate;
   14.16  
   14.17  #define PLOVER_PACKAGE_SET_GET_PRIVATE(obj)\
   14.18 @@ -118,6 +119,7 @@
   14.19  	g_free(priv->root_uri);
   14.20  	priv->root_uri=NULL;
   14.21      }
   14.22 +    g_clear_object(&priv->repository);
   14.23  }
   14.24  
   14.25  gboolean plover_package_set_open(PloverPackageSet *set,const char *root_uri,
   14.26 @@ -354,9 +356,18 @@
   14.27  	priv->set=plover_package_set_get_razor(unrelocated);
   14.28  	razor_set_ref(priv->set);
   14.29      }
   14.30 +    priv->repository=g_object_ref(repository);
   14.31      return set;
   14.32  }
   14.33  
   14.34 +PloverRepository *plover_package_set_get_repository(PloverPackageSet *set)
   14.35 +{
   14.36 +    PloverPackageSetPrivate *priv;
   14.37 +    g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
   14.38 +    priv=PLOVER_PACKAGE_SET_GET_PRIVATE(set);
   14.39 +    return priv->repository;
   14.40 +}
   14.41 +
   14.42  PloverPackageSet *plover_package_set_new_from_yum(const char *base,
   14.43    struct razor_relocations *relocations,GError **error)
   14.44  {
   14.45 @@ -700,6 +711,9 @@
   14.46  	priv->guessed_prefix=plover_comps_get_default_prefix(comps);
   14.47  	plover_comps_free(comps);
   14.48      }
   14.49 +    if (!priv->guessed_prefix)
   14.50 +	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
   14.51 +	  "No popular prefixes and no default prefix either");
   14.52      return priv->guessed_prefix;
   14.53  }
   14.54  
    15.1 --- a/plover/packageset.h	Tue Jun 29 10:09:34 2021 +0100
    15.2 +++ b/plover/packageset.h	Tue Apr 25 17:41:00 2023 +0100
    15.3 @@ -49,6 +49,7 @@
    15.4  PloverPackageSet *
    15.5    plover_package_set_new_from_repository(PloverRepository *repository,
    15.6    struct razor_relocations *relocations,GError **err);
    15.7 +PloverRepository *plover_package_set_get_repository(PloverPackageSet *set);
    15.8  PloverPackageSet *plover_package_set_new_from_yum(const char *base,
    15.9    struct razor_relocations *relocations,GError **err);
   15.10  PloverPackageSet *plover_package_set_new_from_rpms(const char **filenames,
    16.1 --- a/plover/plover.h	Tue Jun 29 10:09:34 2021 +0100
    16.2 +++ b/plover/plover.h	Tue Apr 25 17:41:00 2023 +0100
    16.3 @@ -112,6 +112,7 @@
    16.4  void plover_comps_set_vendor(struct comps *comps,const char *vendor);
    16.5  void plover_comps_set_distribution(struct comps *comps,
    16.6    const char *distribution);
    16.7 +const char *plover_get_vendor_prefix(void);
    16.8  gchar *plover_comps_get_default_prefix(struct comps *comps);
    16.9  
   16.10  int plover_log_open(const char *path);
    17.1 --- a/plover/plover.pc.in	Tue Jun 29 10:09:34 2021 +0100
    17.2 +++ b/plover/plover.pc.in	Tue Apr 25 17:41:00 2023 +0100
    17.3 @@ -6,6 +6,8 @@
    17.4  Name: plover
    17.5  Description: Plover packaging system
    17.6  Version: @VERSION@
    17.7 -Requires: razor expat zlib glib2
    17.8 +Requires: @LIBPLOVER_REQUIREMENTS@
    17.9 +Requires.private: @LIBPLOVER_PRIVATE_REQUIREMENTS@
   17.10  Libs: -L${libdir} -lplover
   17.11 +Libs.private: @LIBPLOVER_PRIVATE_LIBS@
   17.12  Cflags: -I${includedir}
    18.1 --- a/plover/repository.c	Tue Jun 29 10:09:34 2021 +0100
    18.2 +++ b/plover/repository.c	Tue Apr 25 17:41:00 2023 +0100
    18.3 @@ -19,12 +19,22 @@
    18.4  #include "config.h"
    18.5  #include <stdlib.h>
    18.6  #include <string.h>
    18.7 +#include <glib/gi18n.h>
    18.8  #include <glib-object.h>
    18.9  #include <razor.h>
   18.10  #include <plover/plover.h>
   18.11  #include <plover/repository.h>
   18.12  #include "plover/uri-handler.h"
   18.13  
   18.14 +enum {
   18.15 +    PROP_0,
   18.16 +    PROP_PACKAGE_SET,
   18.17 +    PROP_RPM_URIS,
   18.18 +    LAST_PROP
   18.19 +};
   18.20 +
   18.21 +static GParamSpec *properties[LAST_PROP]={0};
   18.22 +
   18.23  G_DEFINE_TYPE(PloverRepository,plover_repository,G_TYPE_OBJECT);
   18.24  
   18.25  typedef struct _PloverRepositoryPrivate {
   18.26 @@ -53,12 +63,60 @@
   18.27  	G_OBJECT_CLASS(plover_repository_parent_class)->dispose(obj);
   18.28  }
   18.29  
   18.30 +static void plover_repository_set_property(GObject *obj,guint property_id,
   18.31 +  const GValue *value,GParamSpec *pspec)
   18.32 +{
   18.33 +    PloverRepositoryPrivate *priv=PLOVER_REPOSITORY_GET_PRIVATE(obj);
   18.34 +    switch (property_id)
   18.35 +    {
   18.36 +	case PROP_PACKAGE_SET:
   18.37 +	    g_clear_object(&priv->set);
   18.38 +	    priv->set=g_value_dup_object(value);
   18.39 +	    break;
   18.40 +	case PROP_RPM_URIS:
   18.41 +	    g_strfreev(priv->uris);
   18.42 +	    priv->uris=g_value_dup_boxed(value);
   18.43 +	    break;
   18.44 +	default:
   18.45 +	    G_OBJECT_WARN_INVALID_PROPERTY_ID(obj,property_id,pspec);
   18.46 +	    break;
   18.47 +    }
   18.48 +}
   18.49 +
   18.50 +static void plover_repository_get_property(GObject *obj,guint property_id,
   18.51 +  GValue *value,GParamSpec *pspec)
   18.52 +{
   18.53 +    PloverRepositoryPrivate *priv=PLOVER_REPOSITORY_GET_PRIVATE(obj);
   18.54 +    switch (property_id)
   18.55 +    {
   18.56 +	case PROP_PACKAGE_SET:
   18.57 +	    g_value_set_object(value,priv->set);
   18.58 +	    break;
   18.59 +	case PROP_RPM_URIS:
   18.60 +	    g_value_set_boxed(value,priv->uris);
   18.61 +	    break;
   18.62 +	default:
   18.63 +	    G_OBJECT_WARN_INVALID_PROPERTY_ID(obj,property_id,pspec);
   18.64 +	    break;
   18.65 +    }
   18.66 +}
   18.67 +
   18.68  static void plover_repository_class_init(PloverRepositoryClass *klass)
   18.69  {
   18.70      GObjectClass *oclass=G_OBJECT_CLASS(klass);
   18.71      plover__uri_handler_init();
   18.72      oclass->finalize=plover_repository_finalize;
   18.73      oclass->dispose=plover_repository_dispose;
   18.74 +    oclass->set_property=plover_repository_set_property;
   18.75 +    oclass->get_property=plover_repository_get_property;
   18.76 +    g_object_class_install_property(oclass,PROP_PACKAGE_SET,
   18.77 +      g_param_spec_object("package-set",_("Package set"),
   18.78 +      _("The package set helper object"),PLOVER_TYPE_PACKAGE_SET,
   18.79 +      G_PARAM_STATIC_STRINGS|G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
   18.80 +    g_object_class_install_property(oclass,PROP_RPM_URIS,
   18.81 +      g_param_spec_boxed("rpm-uris",_("RPM URIs"),
   18.82 +      _("List of URIs, one for each RPM"),G_TYPE_STRV,
   18.83 +      G_PARAM_STATIC_STRINGS|G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
   18.84      g_type_class_add_private(klass,sizeof(PloverRepositoryPrivate));
   18.85  }
   18.86  
   18.87 @@ -69,15 +127,10 @@
   18.88  PloverRepository *plover_repository_new_from_package_set(PloverPackageSet *set,
   18.89    const char **rpm_uris)
   18.90  {
   18.91 -    PloverRepository *repository;
   18.92 -    PloverRepositoryPrivate *priv;
   18.93      g_return_val_if_fail(PLOVER_IS_PACKAGE_SET(set),NULL);
   18.94      g_return_val_if_fail(rpm_uris != NULL,NULL);
   18.95 -    repository=g_object_new(PLOVER_TYPE_REPOSITORY,NULL);
   18.96 -    priv=PLOVER_REPOSITORY_GET_PRIVATE(repository);
   18.97 -    priv->uris=g_strdupv((char **)rpm_uris);
   18.98 -    priv->set=g_object_ref(set);
   18.99 -    return repository;
  18.100 +    return g_object_new(PLOVER_TYPE_REPOSITORY,"package-set",set,
  18.101 +      "rpm-uris",rpm_uris,NULL);
  18.102  }
  18.103  
  18.104  PloverRepository *plover_repository_new_from_files(const char **filenames,
  18.105 @@ -105,20 +158,6 @@
  18.106      return repository;
  18.107  }
  18.108  
  18.109 -PloverRepository *plover_repository_new_from_yum(const char *base,
  18.110 -  GError **error)
  18.111 -{
  18.112 -    PloverRepository *repository;
  18.113 -    gchar *base_uri;
  18.114 -    GFile *file;
  18.115 -    file=g_file_new_for_path(base);
  18.116 -    base_uri=g_file_get_uri(file);
  18.117 -    g_object_unref(file);
  18.118 -    repository=plover_repository_new_from_yum_uri(base_uri,error);
  18.119 -    g_free(base_uri);
  18.120 -    return repository;
  18.121 -}
  18.122 -
  18.123  PloverPackageSet *
  18.124    plover_repository_get_package_set(PloverRepository *repository)
  18.125  {
    19.1 --- a/plover/util.c	Tue Jun 29 10:09:34 2021 +0100
    19.2 +++ b/plover/util.c	Tue Apr 25 17:41:00 2023 +0100
    19.3 @@ -30,37 +30,49 @@
    19.4  #include "plover.h"
    19.5  #include "ascii-ctype.h"
    19.6  
    19.7 -gchar *plover_comps_get_default_prefix(struct comps *comps)
    19.8 +const char *plover_get_vendor_prefix(void)
    19.9  {
   19.10 -    const char *vendor_prefix;
   19.11 +    static gchar *vendor_prefix=NULL;		/* Leaked */
   19.12  #ifdef WIN32
   19.13 -    /*
   19.14 -     * We want to sidestep any redirecting that MS-Windows may
   19.15 -     * introduce since this will be based on the architecture
   19.16 -     * of the installer whereas the architecture that actually
   19.17 -     * matters is of the packages (checked elsewhere).
   19.18 -     */
   19.19      BOOL is_wow64=FALSE;
   19.20      typedef BOOL (WINAPI *is_wow64_process_t)(HANDLE,PBOOL);
   19.21      is_wow64_process_t is_wow64_process;
   19.22      char *program_files=NULL;
   19.23      char buf[PATH_MAX];
   19.24 -    is_wow64_process=(is_wow64_process_t)
   19.25 -      GetProcAddress(GetModuleHandleA("kernel32"),"IsWow64Process");
   19.26 -    if (is_wow64_process)
   19.27 -	is_wow64_process(GetCurrentProcess(),&is_wow64);
   19.28 -    if (is_wow64)
   19.29 -	program_files=getenv("ProgramW6432");
   19.30 -    if (!program_files)
   19.31 +#endif
   19.32 +    if (!vendor_prefix)
   19.33      {
   19.34 -	SHGetFolderPath(NULL,CSIDL_PROGRAM_FILES|CSIDL_FLAG_DONT_VERIFY,NULL,0,
   19.35 -	  buf);
   19.36 -	program_files=buf;
   19.37 +#ifdef WIN32
   19.38 +	/*
   19.39 +	 * We want to sidestep any redirecting that MS-Windows may
   19.40 +	 * introduce since this will be based on the architecture
   19.41 +	 * of the installer whereas the architecture that actually
   19.42 +	 * matters is of the packages (checked elsewhere).
   19.43 +	 */
   19.44 +	is_wow64_process=(is_wow64_process_t)
   19.45 +	  GetProcAddress(GetModuleHandleA("kernel32"),"IsWow64Process");
   19.46 +	if (is_wow64_process)
   19.47 +	    is_wow64_process(GetCurrentProcess(),&is_wow64);
   19.48 +	if (is_wow64)
   19.49 +	    program_files=getenv("ProgramW6432");
   19.50 +	if (!program_files)
   19.51 +	{
   19.52 +	    SHGetFolderPath(NULL,CSIDL_PROGRAM_FILES|CSIDL_FLAG_DONT_VERIFY,
   19.53 +	      NULL,0,buf);
   19.54 +	    program_files=buf;
   19.55 +	}
   19.56 +	vendor_prefix=g_strdup(program_files);
   19.57 +#else
   19.58 +	vendor_prefix=g_strdup(g_getenv("PLOVER_VENDOR_PREFIX"));
   19.59 +#endif
   19.60      }
   19.61 -    vendor_prefix=program_files;
   19.62 -#else
   19.63 -    vendor_prefix=g_getenv("PLOVER_VENDOR_PREFIX");
   19.64 -#endif
   19.65 +    return vendor_prefix;
   19.66 +}
   19.67 +
   19.68 +gchar *plover_comps_get_default_prefix(struct comps *comps)
   19.69 +{
   19.70 +    const char *vendor_prefix;
   19.71 +    vendor_prefix=plover_get_vendor_prefix();
   19.72      if (!vendor_prefix)
   19.73  	return NULL;
   19.74      else if (!comps)
   19.75 @@ -156,13 +168,25 @@
   19.76      if (!d)
   19.77      {
   19.78  	if (g_error_matches(err,G_FILE_ERROR,G_FILE_ERROR_NOENT))
   19.79 -	    g_mkdir_with_parents(path,0777);
   19.80 +	{
   19.81 +	    if (g_mkdir_with_parents(path,0777))
   19.82 +		g_warning("Failed to create reports directory: %s: %s",path,
   19.83 +		  g_strerror(errno));
   19.84 +	    else
   19.85 +		g_message("0 reports found in %s",path);
   19.86 +	}
   19.87 +	else
   19.88 +	    g_warning("Failed to open reports directory: %s: %s",path,
   19.89 +	      err->message);
   19.90 +	g_clear_error(&err);
   19.91  	return;
   19.92      }
   19.93      while(count<=MAX_REPORTS && g_dir_read_name(d))
   19.94  	count++;
   19.95      if (count>MAX_REPORTS)
   19.96      {
   19.97 +	g_message("Purging %d report%s from %s",count-MAX_REPORTS,
   19.98 +	  count-MAX_REPORTS==1?"":"s",path);
   19.99  	g_dir_rewind(d);
  19.100  	while((name=g_dir_read_name(d)))
  19.101  	{
  19.102 @@ -188,6 +212,8 @@
  19.103  	    files=g_list_delete_link(files,files);
  19.104  	}
  19.105      }
  19.106 +    else
  19.107 +	g_message("%d report%s found in %s",count,count==1?"":"s",path);
  19.108      g_dir_close(d);
  19.109  }
  19.110  
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/plover/yumrepository.c	Tue Apr 25 17:41:00 2023 +0100
    20.3 @@ -0,0 +1,554 @@
    20.4 +
    20.5 +/*
    20.6 + * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
    20.7 + * Copyright (C) 2008  Red Hat, Inc
    20.8 + * Copyright (C) 2009, 2011, 2014, 2016, 2023 J. Ali Harlow <ali@juiblex.co.uk>
    20.9 + *
   20.10 + * This program is free software; you can redistribute it and/or modify
   20.11 + * it under the terms of the GNU General Public License as published by
   20.12 + * the Free Software Foundation; either version 2 of the License, or
   20.13 + * (at your option) any later version.
   20.14 + *
   20.15 + * This program is distributed in the hope that it will be useful,
   20.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
   20.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20.18 + * GNU General Public License for more details.
   20.19 + *
   20.20 + * You should have received a copy of the GNU General Public License along
   20.21 + * with this program; if not, write to the Free Software Foundation, Inc.,
   20.22 + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   20.23 + */
   20.24 +
   20.25 +#define _GNU_SOURCE
   20.26 +
   20.27 +#include "config.h"
   20.28 +#include <stdlib.h>
   20.29 +#include <string.h>
   20.30 +#include <stdio.h>
   20.31 +#include <stdint.h>
   20.32 +#include <sys/stat.h>
   20.33 +#include <unistd.h>
   20.34 +#include <fcntl.h>
   20.35 +#include <errno.h>
   20.36 +#include <glib.h>
   20.37 +#include <glib-object.h>
   20.38 +#include <expat.h>
   20.39 +#include <zlib.h>
   20.40 +#include <razor.h>
   20.41 +#include <plover/plover.h>
   20.42 +#include <plover/inputstream.h>
   20.43 +#include <plover/yumrepository.h>
   20.44 +#include <plover/uri-handler.h>
   20.45 +
   20.46 +G_DEFINE_TYPE(PloverYumRepository,plover_yum_repository,PLOVER_TYPE_REPOSITORY);
   20.47 +
   20.48 +typedef struct _PloverYumRepositoryPrivate {
   20.49 +    gchar *base_uri;
   20.50 +    struct comps *comps;
   20.51 +} PloverYumRepositoryPrivate;
   20.52 +
   20.53 +#define PLOVER_YUM_REPOSITORY_GET_PRIVATE(obj)\
   20.54 +				G_TYPE_INSTANCE_GET_PRIVATE(obj,\
   20.55 +				  PLOVER_TYPE_YUM_REPOSITORY,\
   20.56 +				  PloverYumRepositoryPrivate)
   20.57 +
   20.58 +enum {
   20.59 +	YUM_STATE_BEGIN,
   20.60 +	YUM_STATE_PACKAGE_NAME,
   20.61 +	YUM_STATE_PACKAGE_ARCH,
   20.62 +	YUM_STATE_SUMMARY,
   20.63 +	YUM_STATE_DESCRIPTION,
   20.64 +	YUM_STATE_URL,
   20.65 +	YUM_STATE_LICENSE,
   20.66 +	YUM_STATE_CHECKSUM,
   20.67 +	YUM_STATE_REQUIRES,
   20.68 +	YUM_STATE_PROVIDES,
   20.69 +	YUM_STATE_OBSOLETES,
   20.70 +	YUM_STATE_CONFLICTS,
   20.71 +	YUM_STATE_SKIPPING_PACKAGE,
   20.72 +	YUM_STATE_FILE
   20.73 +};
   20.74 +
   20.75 +struct yum_context {
   20.76 +	XML_Parser primary_parser;
   20.77 +	XML_Parser filelists_parser;
   20.78 +	XML_Parser current_parser;
   20.79 +
   20.80 +	struct razor_importer *importer;
   20.81 +	struct import_property_context *current_property_context;
   20.82 +	const char *base_uri;
   20.83 +	GTree *uris;
   20.84 +	char name[256], arch[64], summary[512], description[4096];
   20.85 +	char url[256], license[64], buffer[512], *p;
   20.86 +	char pkgid[128], evr[128];
   20.87 +	uint32_t property_type;
   20.88 +	int state;
   20.89 +
   20.90 +	int total, current;
   20.91 +};
   20.92 +
   20.93 +static void plover_yum_repository_finalize(GObject *obj)
   20.94 +{
   20.95 +    PloverYumRepositoryPrivate *priv=PLOVER_YUM_REPOSITORY_GET_PRIVATE(obj);
   20.96 +    plover_comps_free(priv->comps);
   20.97 +    g_free(priv->base_uri);
   20.98 +    if (G_OBJECT_CLASS(plover_yum_repository_parent_class)->finalize)
   20.99 +	G_OBJECT_CLASS(plover_yum_repository_parent_class)->finalize(obj);
  20.100 +}
  20.101 +
  20.102 +static void plover_yum_repository_class_init(PloverYumRepositoryClass *klass)
  20.103 +{
  20.104 +    GObjectClass *oclass=G_OBJECT_CLASS(klass);
  20.105 +    plover__uri_handler_init();
  20.106 +    oclass->finalize=plover_yum_repository_finalize;
  20.107 +    g_type_class_add_private(klass,sizeof(PloverYumRepositoryPrivate));
  20.108 +}
  20.109 +
  20.110 +static void plover_yum_repository_init(PloverYumRepository *repository)
  20.111 +{
  20.112 +}
  20.113 +
  20.114 +static uint32_t
  20.115 +yum_to_razor_relation (const char *flags)
  20.116 +{
  20.117 +	if (flags[0] == 'L') {
  20.118 +		if (flags[1] == 'T')
  20.119 +			return RAZOR_PROPERTY_LESS;
  20.120 +		else
  20.121 +			return RAZOR_PROPERTY_LESS | RAZOR_PROPERTY_EQUAL;
  20.122 +	} else if (flags[0] == 'G') {
  20.123 +		if (flags[1] == 'T')
  20.124 +			return RAZOR_PROPERTY_GREATER;
  20.125 +		else
  20.126 +			return RAZOR_PROPERTY_GREATER | RAZOR_PROPERTY_EQUAL;
  20.127 +	} else
  20.128 +		return RAZOR_PROPERTY_EQUAL;
  20.129 +}
  20.130 +
  20.131 +static void
  20.132 +yum_primary_start_element(void *data, const char *name, const char **atts)
  20.133 +{
  20.134 +	struct yum_context *ctx = data;
  20.135 +	const char *n, *epoch, *version, *release;
  20.136 +	char buffer[128];
  20.137 +	char *s;
  20.138 +	gchar *nevra;
  20.139 +	uint32_t pre, relation, flags;
  20.140 +	int i;
  20.141 +
  20.142 +	if (ctx->state == YUM_STATE_SKIPPING_PACKAGE)
  20.143 +		return;
  20.144 +
  20.145 +	if (strcmp(name, "metadata") == 0) {
  20.146 +		for (i = 0; atts[i]; i += 2) {
  20.147 +			if (strcmp(atts[i], "packages") == 0)
  20.148 +				ctx->total = atoi(atts[i + 1]);
  20.149 +		}
  20.150 +	} else if (strcmp(name, "package") == 0) {
  20.151 +		*ctx->name=*ctx->arch=*ctx->summary=*ctx->description='\0';
  20.152 +		*ctx->url=*ctx->license='\0';
  20.153 +	} else if (strcmp(name, "name") == 0) {
  20.154 +		ctx->state = YUM_STATE_PACKAGE_NAME;
  20.155 +		ctx->p = ctx->name;
  20.156 +	} else if (strcmp(name, "arch") == 0) {
  20.157 +		ctx->state = YUM_STATE_PACKAGE_ARCH;
  20.158 +		ctx->p = ctx->arch;
  20.159 +	} else if (strcmp(name, "version") == 0) {
  20.160 +		epoch = NULL;
  20.161 +		version = NULL;
  20.162 +		release = NULL;
  20.163 +		for (i = 0; atts[i]; i += 2) {
  20.164 +			if (strcmp(atts[i], "epoch") == 0)
  20.165 +				epoch = atts[i + 1];
  20.166 +			else if (strcmp(atts[i], "ver") == 0)
  20.167 +				version = atts[i + 1];
  20.168 +			else if (strcmp(atts[i], "rel") == 0)
  20.169 +				release = atts[i + 1];
  20.170 +		}
  20.171 +		if (version == NULL || release == NULL) {
  20.172 +			fprintf(stderr, "invalid version tag, "
  20.173 +				"missing version or  release attribute\n");
  20.174 +			return;
  20.175 +		}
  20.176 +
  20.177 +		razor_build_evr(ctx->evr, sizeof ctx->evr, epoch, version,
  20.178 +				release);
  20.179 +		if (!strcmp(ctx->arch, "noarch") ||
  20.180 +		    !strcmp(ctx->arch, razor_system_arch())) {
  20.181 +			razor_importer_begin_package(ctx->importer, ctx->name,
  20.182 +						     ctx->evr, ctx->arch);
  20.183 +		} else
  20.184 +			ctx->state = YUM_STATE_SKIPPING_PACKAGE;
  20.185 +	} else if (strcmp(name, "summary") == 0) {
  20.186 +		ctx->p = ctx->summary;
  20.187 +		ctx->state = YUM_STATE_SUMMARY;
  20.188 +	} else if (strcmp(name, "description") == 0) {
  20.189 +		ctx->p = ctx->description;
  20.190 +		ctx->state = YUM_STATE_DESCRIPTION;
  20.191 +	} else if (strcmp(name, "url") == 0) {
  20.192 +		ctx->p = ctx->url;
  20.193 +		ctx->state = YUM_STATE_URL;
  20.194 +	} else if (strcmp(name, "checksum") == 0) {
  20.195 +		ctx->p = ctx->pkgid;
  20.196 +		ctx->state = YUM_STATE_CHECKSUM;
  20.197 +	} else if (strcmp(name, "location") == 0) {
  20.198 +		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE) {
  20.199 +		    for (i = 0; atts[i]; i += 2)
  20.200 +			if (strcmp(atts[i], "href") == 0) {
  20.201 +			    nevra=g_strconcat(ctx->name,"-",ctx->evr,".",
  20.202 +			      ctx->arch,NULL);
  20.203 +			    s=razor_path_relative_to_uri(ctx->base_uri,
  20.204 +			      atts[i + 1],NULL);
  20.205 +			    g_tree_insert(ctx->uris,nevra,g_strdup(s));
  20.206 +			    free(s);
  20.207 +			    break;
  20.208 +			}
  20.209 +		}
  20.210 +	} else if (strcmp(name, "rpm:license") == 0) {
  20.211 +		ctx->p = ctx->license;
  20.212 +		ctx->state = YUM_STATE_LICENSE;
  20.213 +	} else if (strcmp(name, "rpm:requires") == 0) {
  20.214 +		ctx->state = YUM_STATE_REQUIRES;
  20.215 +		ctx->property_type = RAZOR_PROPERTY_REQUIRES;
  20.216 +	} else if (strcmp(name, "rpm:provides") == 0) {
  20.217 +		ctx->state = YUM_STATE_PROVIDES;
  20.218 +		ctx->property_type = RAZOR_PROPERTY_PROVIDES;
  20.219 +	} else if (strcmp(name, "rpm:obsoletes") == 0) {
  20.220 +		ctx->state = YUM_STATE_OBSOLETES;
  20.221 +		ctx->property_type = RAZOR_PROPERTY_OBSOLETES;
  20.222 +	} else if (strcmp(name, "rpm:conflicts") == 0) {
  20.223 +		ctx->state = YUM_STATE_CONFLICTS;
  20.224 +		ctx->property_type = RAZOR_PROPERTY_CONFLICTS;
  20.225 +	} else if (strcmp(name, "rpm:entry") == 0 &&
  20.226 +		   ctx->state != YUM_STATE_BEGIN) {
  20.227 +		n = NULL;
  20.228 +		epoch = NULL;
  20.229 +		version = NULL;
  20.230 +		release = NULL;
  20.231 +		relation = RAZOR_PROPERTY_EQUAL;
  20.232 +		pre = 0;
  20.233 +		for (i = 0; atts[i]; i += 2) {
  20.234 +			if (strcmp(atts[i], "name") == 0)
  20.235 +				n = atts[i + 1];
  20.236 +			else if (strcmp(atts[i], "epoch") == 0)
  20.237 +				epoch = atts[i + 1];
  20.238 +			else if (strcmp(atts[i], "ver") == 0)
  20.239 +				version = atts[i + 1];
  20.240 +			else if (strcmp(atts[i], "rel") == 0)
  20.241 +				release = atts[i + 1];
  20.242 +			else if (strcmp(atts[i], "flags") == 0)
  20.243 +				relation = yum_to_razor_relation(atts[i + 1]);
  20.244 +			else if (strcmp(atts[i], "pre") == 0)
  20.245 +				pre = RAZOR_PROPERTY_PRE;
  20.246 +		}
  20.247 +
  20.248 +		if (n == NULL) {
  20.249 +			fprintf(stderr, "invalid rpm:entry, "
  20.250 +				"missing name or version attributes\n");
  20.251 +			return;
  20.252 +		}
  20.253 +
  20.254 +		razor_build_evr(buffer, sizeof buffer, epoch, version, release);
  20.255 +		flags = ctx->property_type | relation | pre;
  20.256 +		razor_importer_add_property(ctx->importer, n, flags, buffer);
  20.257 +	}
  20.258 +}
  20.259 +
  20.260 +static void
  20.261 +yum_primary_end_element (void *data, const char *name)
  20.262 +{
  20.263 +	struct yum_context *ctx = data;
  20.264 +
  20.265 +	switch (ctx->state) {
  20.266 +	case YUM_STATE_PACKAGE_NAME:
  20.267 +	case YUM_STATE_PACKAGE_ARCH:
  20.268 +	case YUM_STATE_SUMMARY:
  20.269 +	case YUM_STATE_DESCRIPTION:
  20.270 +	case YUM_STATE_URL:
  20.271 +	case YUM_STATE_LICENSE:
  20.272 +	case YUM_STATE_CHECKSUM:
  20.273 +	case YUM_STATE_FILE:
  20.274 +		ctx->state = YUM_STATE_BEGIN;
  20.275 +		break;
  20.276 +	}
  20.277 +
  20.278 +	if (strcmp(name, "package") == 0) {
  20.279 +		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  20.280 +			razor_importer_add_details(ctx->importer, ctx->summary,
  20.281 +						   ctx->description, ctx->url,
  20.282 +						   ctx->license);
  20.283 +
  20.284 +		XML_StopParser(ctx->current_parser, XML_TRUE);
  20.285 +		ctx->current_parser = ctx->filelists_parser;
  20.286 +	}
  20.287 +}
  20.288 +
  20.289 +static void
  20.290 +yum_character_data (void *data, const XML_Char *s, int len)
  20.291 +{
  20.292 +	struct yum_context *ctx = data;
  20.293 +
  20.294 +	switch (ctx->state) {
  20.295 +	case YUM_STATE_PACKAGE_NAME:
  20.296 +	case YUM_STATE_PACKAGE_ARCH:
  20.297 +	case YUM_STATE_SUMMARY:
  20.298 +	case YUM_STATE_DESCRIPTION:
  20.299 +	case YUM_STATE_URL:
  20.300 +	case YUM_STATE_LICENSE:
  20.301 +	case YUM_STATE_CHECKSUM:
  20.302 +	case YUM_STATE_FILE:
  20.303 +		memcpy(ctx->p, s, len);
  20.304 +		ctx->p += len;
  20.305 +		*ctx->p = '\0';
  20.306 +		break;
  20.307 +	}
  20.308 +}
  20.309 +
  20.310 +static void
  20.311 +yum_filelists_start_element(void *data, const char *name, const char **atts)
  20.312 +{
  20.313 +	struct yum_context *ctx = data;
  20.314 +	const char *pkg, *pkgid;
  20.315 +	int i;
  20.316 +
  20.317 +	if (strcmp(name, "package") == 0 &&
  20.318 +	    ctx->state != YUM_STATE_SKIPPING_PACKAGE) {
  20.319 +		pkg = NULL;
  20.320 +		pkgid = NULL;
  20.321 +		for (i = 0; atts[i]; i += 2) {
  20.322 +			if (strcmp(atts[i], "name") == 0)
  20.323 +				pkg = atts[i + 1];
  20.324 +			else if (strcmp(atts[i], "pkgid") == 0)
  20.325 +				pkgid = atts[i + 1];
  20.326 +		}
  20.327 +		if (strcmp(pkgid, ctx->pkgid) != 0)
  20.328 +			fprintf(stderr, "primary.xml and filelists.xml "
  20.329 +				"mismatch for %s: %s vs %s",
  20.330 +				pkg, pkgid, ctx->pkgid);
  20.331 +	} else if (strcmp(name, "file") == 0) {
  20.332 +		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  20.333 +			ctx->state = YUM_STATE_FILE;
  20.334 +		ctx->p = ctx->buffer;
  20.335 +	}
  20.336 +}
  20.337 +
  20.338 +static void
  20.339 +yum_filelists_end_element (void *data, const char *name)
  20.340 +{
  20.341 +	struct yum_context *ctx = data;
  20.342 +
  20.343 +	if (strcmp(name, "package") == 0) {
  20.344 +		XML_StopParser(ctx->current_parser, XML_TRUE);
  20.345 +		ctx->current_parser = ctx->primary_parser;
  20.346 +		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  20.347 +			razor_importer_finish_package(ctx->importer);
  20.348 +		ctx->state = YUM_STATE_BEGIN;
  20.349 +	} else if (strcmp(name, "file") == 0) {
  20.350 +		if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  20.351 +			razor_importer_add_file(ctx->importer, ctx->buffer);
  20.352 +	}
  20.353 +	if (ctx->state != YUM_STATE_SKIPPING_PACKAGE)
  20.354 +		ctx->state = YUM_STATE_BEGIN;
  20.355 +}
  20.356 +
  20.357 +static int plover_system_arch_is_x86(void)
  20.358 +{
  20.359 +    const char *arch=razor_system_arch();
  20.360 +    if (!arch || arch[0]!='i' || arch[1]<'3' || arch[1]>'6')
  20.361 +	return 0;
  20.362 +    else
  20.363 +	return !strcmp(arch+2,"86");
  20.364 +}
  20.365 +
  20.366 +#define XML_BUFFER_SIZE 4096
  20.367 +
  20.368 +PloverYumRepository *plover_yum_repository_new_from_uri(const char *base_uri,
  20.369 +  GError **error)
  20.370 +{
  20.371 +    struct yum_context ctx;
  20.372 +    gchar *s,**rpm_uris;
  20.373 +    GPtrArray *uris;
  20.374 +    char *uri;
  20.375 +    const char *name,*version,*arch;
  20.376 +    void *buf;
  20.377 +    gssize len;
  20.378 +    GInputStream *stream;
  20.379 +    GInputStream *primary,*filelists;
  20.380 +    GZlibDecompressor *decompressor;
  20.381 +    XML_ParsingStatus status;
  20.382 +    struct razor_set *razor;
  20.383 +    struct razor_package_iterator *iter;
  20.384 +    struct razor_package *pkg;
  20.385 +    PloverPackageSet *set;
  20.386 +    PloverYumRepository *repository;
  20.387 +    PloverYumRepositoryPrivate *priv;
  20.388 +    g_return_val_if_fail(plover__uri_validate(base_uri),NULL);
  20.389 +    ctx.importer=razor_importer_create();
  20.390 +    ctx.state=YUM_STATE_BEGIN;
  20.391 +    ctx.base_uri=base_uri;
  20.392 +    ctx.primary_parser=XML_ParserCreate(NULL);
  20.393 +    XML_SetUserData(ctx.primary_parser,&ctx);
  20.394 +    XML_SetElementHandler(ctx.primary_parser,yum_primary_start_element,
  20.395 +      yum_primary_end_element);
  20.396 +    XML_SetCharacterDataHandler(ctx.primary_parser,yum_character_data);
  20.397 +    ctx.filelists_parser=XML_ParserCreate(NULL);
  20.398 +    XML_SetUserData(ctx.filelists_parser,&ctx);
  20.399 +    XML_SetElementHandler(ctx.filelists_parser,yum_filelists_start_element,
  20.400 +      yum_filelists_end_element);
  20.401 +    XML_SetCharacterDataHandler(ctx.filelists_parser,yum_character_data);
  20.402 +    uri=razor_path_relative_to_uri(base_uri,"repodata/primary.xml.gz",NULL);
  20.403 +    stream=plover_razor_input_stream_new(uri,error);
  20.404 +    free(uri);
  20.405 +    if (!stream) {
  20.406 +	XML_ParserFree(ctx.primary_parser);
  20.407 +	XML_ParserFree(ctx.filelists_parser);
  20.408 +	return NULL;
  20.409 +    }
  20.410 +    decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
  20.411 +    primary=g_converter_input_stream_new(G_INPUT_STREAM(stream),
  20.412 +      G_CONVERTER(decompressor));
  20.413 +    g_object_unref(stream);
  20.414 +    g_object_unref(decompressor);
  20.415 +    uri=razor_path_relative_to_uri(base_uri,"repodata/filelists.xml.gz",NULL);
  20.416 +    stream=plover_razor_input_stream_new(uri,error);
  20.417 +    free(uri);
  20.418 +    if (!stream) {
  20.419 +	g_object_unref(primary);
  20.420 +	XML_ParserFree(ctx.primary_parser);
  20.421 +	XML_ParserFree(ctx.filelists_parser);
  20.422 +	return NULL;
  20.423 +    }
  20.424 +    decompressor=g_zlib_decompressor_new(G_ZLIB_COMPRESSOR_FORMAT_GZIP);
  20.425 +    filelists=g_converter_input_stream_new(G_INPUT_STREAM(stream),
  20.426 +      G_CONVERTER(decompressor));
  20.427 +    g_object_unref(stream);
  20.428 +    g_object_unref(decompressor);
  20.429 +    ctx.current_parser=ctx.primary_parser;
  20.430 +    ctx.uris=g_tree_new_full((GCompareDataFunc)strcmp,NULL,g_free,NULL);
  20.431 +    ctx.current=0;
  20.432 +    do
  20.433 +    {
  20.434 +	XML_GetParsingStatus(ctx.current_parser,&status);
  20.435 +	switch (status.parsing)
  20.436 +	{
  20.437 +	    case XML_SUSPENDED:
  20.438 +		XML_ResumeParser(ctx.current_parser);
  20.439 +		break;
  20.440 +	    case XML_PARSING:
  20.441 +	    case XML_INITIALIZED:
  20.442 +		buf=XML_GetBuffer(ctx.current_parser,XML_BUFFER_SIZE);
  20.443 +		if (ctx.current_parser==ctx.primary_parser)
  20.444 +		    len=g_input_stream_read(G_INPUT_STREAM(primary),buf,
  20.445 +		      XML_BUFFER_SIZE,NULL,error);
  20.446 +		else
  20.447 +		    len=g_input_stream_read(G_INPUT_STREAM(filelists),buf,
  20.448 +		      XML_BUFFER_SIZE,NULL,error);
  20.449 +		if (len<0)
  20.450 +		    return NULL;
  20.451 +		XML_ParseBuffer(ctx.current_parser,len,!len);
  20.452 +		break;
  20.453 +	    case XML_FINISHED:
  20.454 +		break;
  20.455 +	}
  20.456 +    } while (status.parsing!=XML_FINISHED);
  20.457 +    XML_ParserFree(ctx.primary_parser);
  20.458 +    XML_ParserFree(ctx.filelists_parser);
  20.459 +    g_object_unref(primary);
  20.460 +    g_object_unref(filelists);
  20.461 +    razor=razor_importer_finish(ctx.importer);
  20.462 +#if RAZOR_HEADER_VERSION_MIN<=1
  20.463 +    /*
  20.464 +     * Header version 1 is supported by plover v0.3 and is used on
  20.465 +     * 32-bit intel machines which allows the setup and update
  20.466 +     * applications from v0.3 to work. On other machines, we don't
  20.467 +     * want these old applications to work (since they would do
  20.468 +     * the wrong thing) and so we use the current header version
  20.469 +     * which they don't support.
  20.470 +     */
  20.471 +    if (plover_system_arch_is_x86())
  20.472 +	razor_set_set_header_version(razor,1);
  20.473 +#endif
  20.474 +    uris=g_ptr_array_new();
  20.475 +    iter=razor_package_iterator_create(razor);
  20.476 +    while(razor_package_iterator_next(iter,&pkg,RAZOR_DETAIL_NAME,&name,
  20.477 +      RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,RAZOR_DETAIL_LAST))
  20.478 +    {
  20.479 +	s=g_strconcat(name,"-",version,".",arch,NULL);
  20.480 +	g_ptr_array_add(uris,g_tree_lookup(ctx.uris,s));
  20.481 +	g_free(s);
  20.482 +    }
  20.483 +    razor_package_iterator_destroy(iter);
  20.484 +    g_ptr_array_add(uris,NULL);
  20.485 +    g_tree_unref(ctx.uris);
  20.486 +    rpm_uris=(gchar **)g_ptr_array_free(uris,FALSE);
  20.487 +    set=plover_package_set_new_from_razor(razor);
  20.488 +    razor_set_unref(razor);
  20.489 +    repository=g_object_new(PLOVER_TYPE_YUM_REPOSITORY,"package-set",set,
  20.490 +      "rpm-uris",rpm_uris,NULL);
  20.491 +    g_object_unref(set);
  20.492 +    g_strfreev(rpm_uris);
  20.493 +    priv=PLOVER_YUM_REPOSITORY_GET_PRIVATE(repository);
  20.494 +    priv->base_uri=g_strdup(base_uri);
  20.495 +    return repository;
  20.496 +}
  20.497 +
  20.498 +PloverYumRepository *plover_yum_repository_new_from_path(const char *base,
  20.499 +  GError **error)
  20.500 +{
  20.501 +    PloverYumRepository *repository;
  20.502 +    gchar *base_uri;
  20.503 +    GFile *file;
  20.504 +    file=g_file_new_for_path(base);
  20.505 +    base_uri=g_file_get_uri(file);
  20.506 +    g_object_unref(file);
  20.507 +    repository=plover_yum_repository_new_from_uri(base_uri,error);
  20.508 +    g_free(base_uri);
  20.509 +    return repository;
  20.510 +}
  20.511 +
  20.512 +/* Compatibility function: Depreciated in favour of
  20.513 + * plover_yum_repository_new_from_uri()
  20.514 + */
  20.515 +
  20.516 +PloverRepository *plover_repository_new_from_yum_uri(const char *base_uri,
  20.517 +  GError **error)
  20.518 +{
  20.519 +    PloverYumRepository *repository;
  20.520 +    repository=plover_yum_repository_new_from_uri(base_uri,error);
  20.521 +    return repository?PLOVER_REPOSITORY(repository):NULL;
  20.522 +}
  20.523 +
  20.524 +/* Compatibility function: Depreciated in favour of
  20.525 + * plover_yum_repository_new_from_path()
  20.526 + */
  20.527 +
  20.528 +PloverRepository *plover_repository_new_from_yum(const char *base,
  20.529 +  GError **error)
  20.530 +{
  20.531 +    PloverYumRepository *repository;
  20.532 +    repository=plover_yum_repository_new_from_path(base,error);
  20.533 +    return repository?PLOVER_REPOSITORY(repository):NULL;
  20.534 +}
  20.535 +
  20.536 +struct comps *plover_yum_repository_get_comps(PloverYumRepository *repository,
  20.537 +  GError **error)
  20.538 +{
  20.539 +    gchar *uri;
  20.540 +    PloverYumRepositoryPrivate *priv;
  20.541 +    g_return_val_if_fail(PLOVER_IS_YUM_REPOSITORY(repository),NULL);
  20.542 +    priv=PLOVER_YUM_REPOSITORY_GET_PRIVATE(repository);
  20.543 +    if (!priv->base_uri)
  20.544 +    {
  20.545 +	g_set_error(error,PLOVER_GENERAL_ERROR,PLOVER_GENERAL_ERROR_FAILED,
  20.546 +	  "No base URI set");
  20.547 +	return NULL;
  20.548 +    }
  20.549 +    if (!priv->comps)
  20.550 +    {
  20.551 +	uri=razor_path_relative_to_uri(priv->base_uri,"repodata/comps.xml",
  20.552 +	  NULL);
  20.553 +	priv->comps=plover_comps_new_from_uri(uri,error);
  20.554 +	free(uri);
  20.555 +    }
  20.556 +    return priv->comps;
  20.557 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/plover/yumrepository.h	Tue Apr 25 17:41:00 2023 +0100
    21.3 @@ -0,0 +1,46 @@
    21.4 +#ifndef __PLOVER_YUM_REPOSITORY_H__
    21.5 +#define __PLOVER_YUM_REPOSITORY_H__
    21.6 +
    21.7 +#include <plover/repository.h>
    21.8 +
    21.9 +G_BEGIN_DECLS
   21.10 +
   21.11 +#define PLOVER_TYPE_YUM_REPOSITORY \
   21.12 +				plover_yum_repository_get_type()
   21.13 +#define PLOVER_YUM_REPOSITORY(obj)	G_TYPE_CHECK_INSTANCE_CAST(obj,\
   21.14 +				  PLOVER_TYPE_YUM_REPOSITORY,\
   21.15 +				  PloverYumRepository)
   21.16 +#define PLOVER_YUM_REPOSITORY_CLASS(klass)\
   21.17 +				G_TYPE_CHECK_CLASS_CAST(klass,\
   21.18 +				  PLOVER_TYPE_YUM_REPOSITORY,\
   21.19 +				  PloverYumRepositoryClass)
   21.20 +#define PLOVER_IS_YUM_REPOSITORY(obj)\
   21.21 +				G_TYPE_CHECK_INSTANCE_TYPE(obj,\
   21.22 +				  PLOVER_TYPE_YUM_REPOSITORY)
   21.23 +#define PLOVER_IS_YUM_REPOSITORY_CLASS(klass)\
   21.24 +				G_TYPE_CHECK_CLASS_TYPE(obj,\
   21.25 +				  PLOVER_TYPE_YUM_REPOSITORY)
   21.26 +#define PLOVER_YUM_REPOSITORY_GET_CLASS(obj)\
   21.27 +				G_TYPE_INSTANCE_GET_CLASS(obj,\
   21.28 +				  PLOVER_TYPE_YUM_REPOSITORY,\
   21.29 +				  PloverYumRepositoryClass)
   21.30 +
   21.31 +typedef struct _PloverYumRepository {
   21.32 +    PloverRepository parent_instance;
   21.33 +} PloverYumRepository;
   21.34 +
   21.35 +typedef struct _PloverYumRepositoryClass {
   21.36 +    PloverRepositoryClass parent_class;
   21.37 +} PloverYumRepositoryClass;
   21.38 +
   21.39 +GType plover_yum_repository_get_type(void) G_GNUC_CONST;
   21.40 +PloverYumRepository *plover_yum_repository_new_from_uri(const char *base_uri,
   21.41 +  GError **error);
   21.42 +PloverYumRepository *plover_yum_repository_new_from_path(const char *base,
   21.43 +  GError **error);
   21.44 +struct comps *plover_yum_repository_get_comps(PloverYumRepository *repository,
   21.45 +  GError **error);
   21.46 +
   21.47 +G_END_DECLS
   21.48 +
   21.49 +#endif /* __PLOVER_YUM_REPOSITORY_H__ */
    22.1 --- a/pre-inst/pre-inst.c	Tue Jun 29 10:09:34 2021 +0100
    22.2 +++ b/pre-inst/pre-inst.c	Tue Apr 25 17:41:00 2023 +0100
    22.3 @@ -48,12 +48,13 @@
    22.4  #endif	/* WIN32 */
    22.5  #include "post.h"
    22.6  
    22.7 -#ifdef WIN32
    22.8 -/* Under WIN32, g_spawn requires a helper program which we'd rather avoid */
    22.9 -#undef USE_G_SPAWN
   22.10 -#else
   22.11 +/*
   22.12 + * Under WIN32, g_spawn may require a helper program which we'd rather avoid.
   22.13 + * At least with glib 2.58, this isn't needed if g_spawn_sync() is used (or
   22.14 + * G_SPAWN_DO_NOT_REAP_CHILD is specified), so we can now define USE_G_SPAWN
   22.15 + * unconditionally.
   22.16 + */
   22.17  #define USE_G_SPAWN
   22.18 -#endif
   22.19  
   22.20  LUALIB_API int luaopen_posix(lua_State *L);
   22.21  
   22.22 @@ -376,6 +377,7 @@
   22.23  	  "Post command exited with code %ld",(long)rc);
   22.24  	return FALSE;
   22.25      }
   22.26 +    fprintf(stderr,"post command exited normally\n");
   22.27      return TRUE;
   22.28  }
   22.29  
   22.30 @@ -422,6 +424,29 @@
   22.31      return TRUE;
   22.32  }
   22.33  
   22.34 +print_arguments(int argc,char **argv)
   22.35 +{
   22.36 +    int i,j;
   22.37 +    for(i=0;i<argc;i++)
   22.38 +    {
   22.39 +	if (i)
   22.40 +	    putchar(' ');
   22.41 +	if (strchr(argv[i],' ') || strchr(argv[i],'"') || strchr(argv[i],'\n'))
   22.42 +	{
   22.43 +	    putchar('"');
   22.44 +	    for(j=0;argv[i][j];j++)
   22.45 +	    {
   22.46 +		if (strchr("$`\"\\\n",argv[i][j]))
   22.47 +		    putchar('\\');
   22.48 +		putchar(argv[i][j]);
   22.49 +	    }
   22.50 +	    putchar('"');
   22.51 +	}
   22.52 +	else
   22.53 +	    fputs(argv[i],stdout);
   22.54 +    }
   22.55 +}
   22.56 +
   22.57  /*
   22.58   * Run a command after completing request.
   22.59   *
   22.60 @@ -446,7 +471,6 @@
   22.61  	  "--post: No command given");
   22.62  	return FALSE;
   22.63      }
   22.64 -    printf("Running post command: %s\n",argv[1]);
   22.65      if (!g_shell_parse_argv(argv[1],&post_argc,&post_argv,&tmp_error))
   22.66      {
   22.67  	g_propagate_prefixed_error(error,tmp_error,"%s: ",argv[1]);
   22.68 @@ -482,6 +506,9 @@
   22.69  	    post_argv[i]=expanded;
   22.70  	}
   22.71      }
   22.72 +    printf("Running post command: ");
   22.73 +    print_arguments(post_argc,post_argv);
   22.74 +    putchar('\n');
   22.75      return pre_install_spawn_sync(post_argv,error);
   22.76  }
   22.77  
   22.78 @@ -593,7 +620,12 @@
   22.79  	}
   22.80      }
   22.81      if (post && post->argc>0)
   22.82 +    {
   22.83 +	printf("Running post command: ");
   22.84 +	print_arguments(post->argc,post->argv);
   22.85 +	putchar('\n');
   22.86  	pre_install_spawn_sync(post->argv,&error);
   22.87 +    }
   22.88      else if (argv)
   22.89  	run_post(argc,argv,success,repository,&error);
   22.90      if (post)