First usable command-line UI version.
authorshort <>
Thu, 4 Sep 2003 07:30:54 +0000 (07:30 +0000)
committershort <>
Thu, 4 Sep 2003 07:30:54 +0000 (07:30 +0000)
12 files changed:
src/install/acquire/Makefile.am
src/install/acquire/cabinet.c
src/install/acquire/captivemodid.c
src/install/acquire/captivemodid.h
src/install/acquire/main.c
src/install/acquire/main.h
src/install/acquire/microsoftcom.c [new file with mode: 0644]
src/install/acquire/microsoftcom.h [new file with mode: 0644]
src/install/acquire/moduriload.c
src/install/acquire/moduriload.h
src/install/acquire/ui-line.c [new file with mode: 0644]
src/install/acquire/ui-line.h [new file with mode: 0644]

index a8c5a9b..d5a5443 100644 (file)
@@ -29,12 +29,19 @@ captive_install_acquire_SOURCES= \
                diskscan.h \
                main.c \
                main.h \
+               microsoftcom.c \
+               microsoftcom.h \
                moduriload.c \
-               moduriload.h
+               moduriload.h \
+               ui-line.c \
+               ui-line.h
 captive_install_acquire_CFLAGS=$(GNOME_VFS_CFLAGS) $(LIBXML_CFLAGS) $(OPENSSL_CFLAGS)
 captive_install_acquire_LDADD =$(GNOME_VFS_LIBS)   $(LIBXML_LIBS)   $(OPENSSL_LIBS)   $(LIBNTFS_LIBS) $(POPT_LIBS)
+captive_install_acquire_LDADD+= $(READLINE_LIBS)    $(INTLLIBS)
+captive_install_acquire_LDFLAGS=$(READLINE_LDFLAGS)
 
 captive_install_acquire_CFLAGS+=-DSYSCONFDIR="$(sysconfdir)"
+captive_install_acquire_CFLAGS+=-DVARLIBCAPTIVEDIR="$(localstatedir)/lib/$(PACKAGE)"
 captive_install_acquire_LDADD+=../libcaptive-install/libcaptive-install.a
 
 EXTRA_DIST+= \
index 515d0c9..f18695c 100644 (file)
@@ -28,6 +28,7 @@
 #include "moduriload.h"
 #include <sys/mman.h>
 #include <unistd.h>
+#include "main.h"
 
 #include <captive/macros.h>
 
@@ -36,6 +37,8 @@ void acquire_cabinet_seek(struct acquire_cabinet *acquire_cabinet,GnomeVFSFileOf
 {
        g_return_if_fail(acquire_cabinet!=NULL);
 
+       (*ui_search_is_aborted)();
+
        acquire_cabinet->offset=offset;
 }
 
@@ -43,6 +46,8 @@ void acquire_cabinet_seek_skip(struct acquire_cabinet *acquire_cabinet,GnomeVFSF
 {
        g_return_if_fail(acquire_cabinet!=NULL);
 
+       (*ui_search_is_aborted)();
+
        acquire_cabinet->offset+=offset;
 }
 
@@ -50,6 +55,8 @@ GnomeVFSFileOffset acquire_cabinet_tell(struct acquire_cabinet *acquire_cabinet)
 {
        g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
+       (*ui_search_is_aborted)();
+
        return acquire_cabinet->offset;
 }
 
@@ -67,6 +74,9 @@ GnomeVFSFileSize bytes_read_now;
        g_return_val_if_fail(acquire_cabinet!=NULL,GNOME_VFS_ERROR_BAD_PARAMETERS);
        g_return_val_if_fail(buffer!=NULL || bytes==0,GNOME_VFS_ERROR_BAD_PARAMETERS);
 
+       if ((*ui_search_is_aborted)())
+               return GNOME_VFS_ERROR_INTERRUPTED;
+
        bytes=MAX(0,MIN(bytes,acquire_cabinet->size-acquire_cabinet->offset));
        if (!bytes)
                return GNOME_VFS_ERROR_EOF;
@@ -199,6 +209,9 @@ int file_write(struct file *fi, UBYTE *buf, size_t length)
        g_return_val_if_fail(fi==file_write_fi_assertion,0);
        g_return_val_if_fail(file_write_bytearray!=NULL,0);
 
+       if ((*ui_search_is_aborted)())
+               return 0;
+
        g_byte_array_append(file_write_bytearray,buf,length);
 
        return 1;       /* success */
@@ -211,6 +224,9 @@ struct file *filelist,*fi;
 
        g_return_if_fail(acquire_cabinet!=NULL);
 
+       if ((*ui_search_is_aborted)())
+               return;
+
        basecab=find_cabs_in_file(acquire_cabinet);
        if (!basecab)
                return;
@@ -228,6 +244,9 @@ GnomeVFSURI *uri_fi;
                if (!captivemodid_module_length_is_valid(fi->length))
                        continue;
 
+               if ((*ui_search_is_aborted)())
+                       return;
+
                file_write_fi_assertion=fi;
                file_write_bytearray=g_byte_array_new();
                extract_file(fi,
index 8421cef..cc14139 100644 (file)
@@ -83,6 +83,20 @@ static void module_md5_hash_init(void)
        module_md5_hash=g_hash_table_new(g_str_hash,g_str_equal);
 }
 
+/* map: (const xmlChar *)type -> (gpointer)GINT_TO_POINTER(priority) */
+/* We remove entry for module with already the best priority found,
+ * therefore captivemodid_module_type_best_priority_lookup() will return
+ * 'G_MININT' afterwards.
+ */
+static GHashTable *module_type_best_priority_hash;
+
+static void module_type_best_priority_hash_init(void)
+{
+       if (module_type_best_priority_hash)
+               return;
+       module_type_best_priority_hash=g_hash_table_new(g_str_hash,g_str_equal);
+}
+
 static void captivemodid_load_module(struct captivemodid_module *module)
 {
 struct captivemodid_module *module_md5_conflict;
@@ -94,8 +108,17 @@ struct captivemodid_module *module_md5_conflict;
                return;
                }
        g_hash_table_insert(module_md5_hash,(/* de-const */ xmlChar *)module->md5,module);
+
        module_valid_length_hash_init();
        g_hash_table_insert(module_valid_length_hash,GINT_TO_POINTER(module->length),module_valid_length_hash);
+
+       if (strcmp(module->type,"cabinet")) {
+               if (module->priority>captivemodid_module_type_best_priority_lookup(module->type)) {
+                       module_type_best_priority_hash_init();
+                       g_hash_table_insert(module_type_best_priority_hash,
+                                       (/* de-const */ xmlChar *)module->type,GINT_TO_POINTER(module->priority));
+                       }
+               }
 }
 
 gboolean captivemodid_module_length_is_valid(GnomeVFSFileSize file_size)
@@ -104,6 +127,7 @@ gint file_size_gint;
 
        if ((GnomeVFSFileSize)(file_size_gint=file_size)!=file_size)    /* Size too big to be valid. */
                return FALSE;
+       module_valid_length_hash_init();
        return !!g_hash_table_lookup(module_valid_length_hash,GINT_TO_POINTER(file_size_gint));
 }
 
@@ -111,9 +135,42 @@ struct captivemodid_module *captivemodid_module_md5_lookup(const gchar *file_md5
 {
        g_return_val_if_fail(file_md5!=NULL,NULL);
 
+       module_md5_hash_init();
        return g_hash_table_lookup(module_md5_hash,file_md5);
 }
 
+gint captivemodid_module_type_best_priority_lookup(const xmlChar *module_type)
+{
+gpointer r_gpointer;
+gboolean errbool;
+
+       g_return_val_if_fail(module_type!=NULL,G_MININT);
+
+       module_type_best_priority_hash_init();
+       errbool=g_hash_table_lookup_extended(module_type_best_priority_hash,
+                       module_type,    /* lookup_key */
+                       NULL,   /* orig_key */
+                       &r_gpointer);   /* value */
+       if (!errbool)
+               return G_MININT;
+
+       return GPOINTER_TO_INT(r_gpointer);
+}
+
+/* Returns: TRUE if all modules were found. */
+gboolean captivemodid_module_type_best_priority_found(const xmlChar *module_type)
+{
+gboolean errbool;
+
+       g_return_val_if_fail(module_type!=NULL,FALSE);
+
+       module_type_best_priority_hash_init();
+       errbool=g_hash_table_remove(module_type_best_priority_hash,module_type);
+       g_assert(errbool==TRUE);
+
+       return !g_hash_table_size(module_type_best_priority_hash);
+}
+
 static xmlChar *captivemodid_load_module_xml_get_attr
                (const gchar *captivemodid_pathname,xmlTextReader *xml_reader,const gchar *attr_name)
 {
@@ -185,12 +242,12 @@ fail_free_module:
 }
 
 
-void captivemodid_load(const gchar *captivemodid_pathname)
+gboolean captivemodid_load(const gchar *captivemodid_pathname)
 {
 xmlTextReader *xml_reader;
 
-       xml_reader=xmlNewTextReaderFilename(captivemodid_pathname);
-       g_assert(xml_reader!=NULL);
+       if (!(xml_reader=xmlNewTextReaderFilename(captivemodid_pathname)))
+               return FALSE;
        while (1==xmlTextReaderRead(xml_reader)) {
                switch (xmlTextReaderNodeType(xml_reader)) {
 
@@ -222,4 +279,5 @@ const xmlChar *xml_name;
                        }
                }
        xmlFreeTextReader(xml_reader);
+       return TRUE;
 }
index 1fcdd4f..bc0390f 100644 (file)
@@ -39,7 +39,9 @@ struct captivemodid_module {
 gchar *calc_md5(gconstpointer base,size_t length);
 gboolean captivemodid_module_length_is_valid(GnomeVFSFileSize file_size);
 struct captivemodid_module *captivemodid_module_md5_lookup(const gchar *file_md5);
-void captivemodid_load(const gchar *captivemodid_pathname);
+gint captivemodid_module_type_best_priority_lookup(const xmlChar *module_type);
+gboolean captivemodid_module_type_best_priority_found(const xmlChar *module_type);
+gboolean captivemodid_load(const gchar *captivemodid_pathname);
 
 G_END_DECLS
 
index d6de799..5983c1e 100644 (file)
@@ -31,6 +31,8 @@
 #include <errno.h>
 #include <unistd.h>
 #include <libgnomevfs/gnome-vfs-init.h>
+#include "ui-line.h"
+#include "microsoftcom.h"
 
 #include <captive/macros.h>
 
 
 
 int optarg_verbose;
+int optarg_dry;
+static int optarg_microsoft_com;
 static int optarg_scan_disks;
+static int optarg_scan_disks_quick;
+static char *optarg_modid_path=G_STRINGIFY(SYSCONFDIR) "/w32-mod-id.captivemodid.xml";
 static GList *optarg_scan_path_list;   /* of (char *) */
 
 static void acquire_popt_callback
@@ -62,9 +68,17 @@ static const struct poptOption popt_table[]={
                        argDescrip: (argDescripP), \
                }
 
-               BUG_ACQUIRE_POPT('v',"verbose"   ,POPT_ARG_NONE  ,&optarg_verbose   ,0,N_("Display additional debug information"),NULL),
-               BUG_ACQUIRE_POPT(0  ,"scan-disks",POPT_ARG_NONE  ,&optarg_scan_disks,0,N_("Scan all local disks"),NULL),
-               BUG_ACQUIRE_POPT(0  ,"scan-path" ,POPT_ARG_STRING,NULL              ,0,N_("Scan specified disk path"),N_("path/URI")),
+               BUG_ACQUIRE_POPT('v',"verbose"         ,POPT_ARG_NONE  ,&optarg_verbose,0,N_("Display additional debug information"),NULL),
+               BUG_ACQUIRE_POPT('n',"dry"             ,POPT_ARG_NONE  ,&optarg_dry    ,0,N_("No modifications, no files written"),NULL),
+               BUG_ACQUIRE_POPT(0  ,"modid-path"      ,POPT_ARG_STRING|POPT_ARGFLAG_SHOW_DEFAULT,&optarg_modid_path,0,
+                               N_("Path to .captivemodid.xml database"),N_("path")),
+               BUG_ACQUIRE_POPT(0  ,"scan-disks"      ,POPT_ARG_NONE  ,&optarg_scan_disks,0,N_("Scan all files on local disks"),NULL),
+               BUG_ACQUIRE_POPT(0  ,"scan-disks-quick",POPT_ARG_NONE  ,&optarg_scan_disks_quick,0,
+                               N_("Scan MS-Windows directories on local disks"),NULL),
+               BUG_ACQUIRE_POPT(0  ,"scan-path" ,POPT_ARG_STRING,NULL              ,0,
+                               N_("Scan specified disk path or web URL"),N_("path/URI")),
+               BUG_ACQUIRE_POPT(0  ,"microsoft-com"   ,POPT_ARG_NONE  ,&optarg_microsoft_com,0,
+                               N_("Download from microsoft.com; Legal: You may need to have valid Microsoft Windows XP license."),NULL),
 
 #undef BUG_ACQUIRE_POPT
                POPT_AUTOHELP
@@ -84,13 +98,68 @@ static void acquire_popt_callback
 }
 
 
+void (*ui_interactive)(void);
+
+static gboolean ui_search_is_aborted_dummy(void)
+{
+       return FALSE;   /* not aborted */
+}
+
+gboolean (*ui_search_is_aborted)(void)=ui_search_is_aborted_dummy;
+
+static GList *mod_uri_list_local;
+static void mod_uri_list_local_init(void)
+{
+       if (mod_uri_list_local)
+               return;
+       mod_uri_list_local=mod_uri_list();
+}
+
+void scan_disks_quick(void)
+{
+GList *mod_uri_list_quick_local,*mod_uri_l;
+
+       mod_uri_list_local_init();
+       mod_uri_list_quick_local=NULL;
+       for (mod_uri_l=mod_uri_list_local;mod_uri_l;mod_uri_l=mod_uri_l->next) {
+               mod_uri_list_quick_local=g_list_prepend(mod_uri_list_quick_local,
+                               gnome_vfs_uri_append_path(mod_uri_l->data,"windows/system32"));
+               }
+       mod_uri_list_quick_local=g_list_reverse(mod_uri_list_quick_local);
+       g_list_foreach(mod_uri_list_quick_local,(GFunc)mod_uri_load,NULL);
+       gnome_vfs_uri_list_free(mod_uri_list_quick_local);
+}
+
+void scan_disks(void)
+{
+       mod_uri_list_local_init();
+       g_list_foreach(mod_uri_list_local,(GFunc)mod_uri_load,NULL);
+}
+
+void microsoft_com(void)
+{
+       g_list_foreach(mod_uri_microsoftcom_list(),(GFunc)mod_uri_load,NULL);
+}
+
+static void scan_batch(void)
+{
+       g_list_foreach(optarg_scan_path_list,(GFunc)mod_uri_load,NULL);
+
+       if (optarg_scan_disks_quick)
+               scan_disks_quick();
+       if (optarg_scan_disks)
+               scan_disks();
+       if (optarg_microsoft_com)
+               microsoft_com();
+}
+
 int main(int argc,char **argv)
 {
 poptContext context;
 int errint;
-GList *scan_uri_list;
+gboolean is_interactive;
 
-#ifdef MAINTAINER_MODE
+#if 0
        g_log_set_always_fatal(~(0
                        |G_LOG_LEVEL_MESSAGE
                        |G_LOG_LEVEL_INFO
@@ -131,13 +200,37 @@ GList *scan_uri_list;
                return EXIT_FAILURE;
                }
 
-       scan_uri_list=NULL;
-       scan_uri_list=g_list_concat(scan_uri_list,gnome_vfs_uri_list_copy(optarg_scan_path_list));
-       if (optarg_scan_disks)
-               scan_uri_list=g_list_concat(scan_uri_list,mod_uri_list());
+       is_interactive=(1
+                       && ! optarg_scan_path_list
+                       && ! optarg_scan_disks_quick
+                       && ! optarg_scan_disks 
+                       && ! optarg_microsoft_com);
+
+       /* Initialize UI here to catch all GLog errors below. */
+       if (!ui_line_init())
+               g_error(_("No UI interface could be initialized"));
 
-       captivemodid_load("./w32-mod-id.captivemodid.xml");
-       g_list_foreach(scan_uri_list,(GFunc)mod_uri_load,NULL);
+       if (!captivemodid_load(optarg_modid_path) && !captivemodid_load("./w32-mod-id.captivemodid.xml"))
+               g_error(_("Unable to load modid database: %s"),optarg_modid_path);
+
+{
+void (*acquire_module_available_notify_orig)(struct module_available *module_available);
+void (*acquire_module_all_modules_found_notify_orig)(void);
+
+       acquire_module_available_notify_orig=acquire_module_available_notify;
+       acquire_module_available_notify=NULL;
+       acquire_module_all_modules_found_notify_orig=acquire_module_all_modules_found_notify;
+       acquire_module_all_modules_found_notify=NULL;
+       mod_uri_load(gnome_vfs_uri_new("file://" G_STRINGIFY(VARLIBCAPTIVEDIR)));
+       acquire_module_available_notify=acquire_module_available_notify_orig;
+       acquire_module_all_modules_found_notify=acquire_module_all_modules_found_notify_orig;
+       }
+
+       if (!is_interactive)
+               scan_batch();
+       else if (!(*ui_search_is_aborted)()) {
+               (*ui_interactive)();
+               }
 
        gnome_vfs_shutdown();
 
index 1f8989a..5f3c32b 100644 (file)
 G_BEGIN_DECLS
 
 extern gboolean optarg_verbose;
+extern gboolean optarg_dry;
+extern void (*ui_interactive)(void);
+extern gboolean (*ui_search_is_aborted)(void);
+
+void scan_disks_quick(void);
+void scan_disks(void);
+void microsoft_com(void);
 
 G_END_DECLS
 
diff --git a/src/install/acquire/microsoftcom.c b/src/install/acquire/microsoftcom.c
new file mode 100644 (file)
index 0000000..80abf67
--- /dev/null
@@ -0,0 +1,75 @@
+/* $Id$
+ * W32 modules finder from microsoft.com Internet download
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include "microsoftcom.h"      /* self */
+#include <glib/gmessages.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <libgnomevfs/gnome-vfs-result.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <string.h>
+
+#include <captive/macros.h>
+
+
+/* Config: */
+/* Do we really need to use indirection by the following 'base' URL?
+ * It appears to me as if some Microsoft Service Pack files URLs
+ * have changed in the past.
+ */
+#define MICROSOFTCOM_URL "http://www.microsoft.com/WindowsXP/pro/downloads/servicepacks/sp1/checkedbuild.asp"
+
+
+GList * /* of (GnomeVFSURI *) */ mod_uri_microsoftcom_list(void)
+{
+int base_size;
+char *base_contents;
+char *href,*href_end;
+const char *href2;
+GnomeVFSURI *uri;
+
+       base_contents=NULL;
+       if (GNOME_VFS_OK!=gnome_vfs_read_entire_file(MICROSOFTCOM_URL,&base_size,&base_contents)
+                       || base_size<=0) {
+               g_warning(_("Cannot load file-URL pointing base URL: %s"),MICROSOFTCOM_URL);
+               goto fail_free_base_contents;
+               }
+       base_contents[base_size-1]=0;   /* string terminator */
+       if (!(href=strstr(base_contents,"http://download.microsoft.com/")) || !(href_end=strchr(href,'"'))) {
+               g_warning(_("File-URL not found in base URL: %s"),MICROSOFTCOM_URL);
+               goto fail_free_base_contents;
+               }
+       *href_end=0;
+       if (strncmp(href,"http://",strlen("http://"))) {
+               g_warning(_("File URL not valid: %s"),href);
+               goto fail_free_base_contents;
+               }
+       href2=captive_printf_alloca("httpcaptive://%s",href+strlen("http://"));
+       if (!(uri=gnome_vfs_uri_new(href2))) {
+               g_warning(_("Found file URL not parsable: %s"),href2);
+               goto fail_free_base_contents;
+               }
+       g_free(base_contents);
+       return g_list_append(NULL,uri);
+
+fail_free_base_contents:
+       g_free(base_contents);
+       return NULL;
+}
diff --git a/src/install/acquire/microsoftcom.h b/src/install/acquire/microsoftcom.h
new file mode 100644 (file)
index 0000000..1017f98
--- /dev/null
@@ -0,0 +1,35 @@
+/* $Id$
+ * Include file for W32 modules finder from microsoft.com Internet download
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _CAPTIVE_INSTALL_ACQUIRE_MICROSOFTCOM_H
+#define _CAPTIVE_INSTALL_ACQUIRE_MICROSOFTCOM_H 1
+
+
+#include <glib/gtypes.h>
+#include <glib/glist.h>
+
+
+G_BEGIN_DECLS
+
+GList * /* of (GnomeVFSURI *) */ mod_uri_microsoftcom_list(void);
+
+G_END_DECLS
+
+
+#endif /* _CAPTIVE_INSTALL_ACQUIRE_MICROSOFTCOM_H */
index 4d67e44..af56ad2 100644 (file)
 #include "cabinet.h"
 #include <libgnomevfs/gnome-vfs-ops.h>
 #include <libgnomevfs/gnome-vfs-directory.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <captive/macros.h>
 
 
 /* Config: */
 #define MAX_FILE_LOAD_LENGTH 5000000   /* Otherwise use cabextract-over-http. */
 
 
+/* map: (const xmlChar *)type -> (struct module_available *) */
+GHashTable *module_available_hash;
+
+static void module_available_hash_value_destroy_func(struct module_available *module_available)
+{
+       g_return_if_fail(module_available!=NULL);
+
+       g_free(module_available->file_base);
+       g_free(module_available->uri_text);
+       g_free(module_available);
+}
+
+static void module_available_hash_init(void)
+{
+       if (module_available_hash)
+               return;
+       module_available_hash=g_hash_table_new_full(g_str_hash,g_str_equal,
+                       (GDestroyNotify)NULL,
+                       (GDestroyNotify)module_available_hash_value_destroy_func);
+}
+
+
+void (*acquire_module_available_notify)(struct module_available *module_available);
+void (*acquire_module_all_modules_found_notify)(void);
+
 static void mod_uri_load_module_from_memory
                (struct captivemodid_module *module,gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
 {
-gchar *uri_text;
+struct module_available *module_available;
+gint best_priority;
+gboolean all_modules_found;
 
        g_return_if_fail(module!=NULL);
        g_return_if_fail(file_base!=NULL);
        g_return_if_fail(uri!=NULL);
+       g_return_if_fail((size_t)module->length==file_length);
+
+       module_available_hash_init();
+       if ((module_available=g_hash_table_lookup(module_available_hash,module->type))) {
+               if (module_available->module->priority>=module->priority)
+                       return;
+               }
+
+       captive_new(module_available);
+       module_available->module=module;
+       module_available->file_base=g_memdup(file_base,file_length);
+       module_available->uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
+       /* It may possibly destroy the old 'module_available': */
+       g_hash_table_insert(module_available_hash,(/* de-const */ xmlChar *)module->type,module_available);
+
+       if (!optarg_dry) {
+const gchar *dest_pathname;
+int dest_fd;
+
+               dest_pathname=captive_printf_alloca("%s/%s",G_STRINGIFY(VARLIBCAPTIVEDIR),module->type);
+               if (-1==(dest_fd=open(dest_pathname,O_CREAT|O_TRUNC|O_WRONLY,0644)))
+                       g_warning(_("Cannot open target file \"%s\": %m"),dest_pathname);
+               else {
+                       if ((ssize_t)file_length!=write(dest_fd,file_base,file_length))
+                               g_warning(_("Error writing target file \"%s\": %m"),dest_pathname);
+                       if (close(dest_fd))
+                               g_warning(_("Error closing target file \"%s\": %m"),dest_pathname);
+                       }
+               }
 
-       uri_text=gnome_vfs_uri_to_string(uri,GNOME_VFS_URI_HIDE_PASSWORD);
-       g_message("type=%s,id:%s: %s",module->type,module->id,uri_text);
-       g_free(uri_text);
+       all_modules_found=FALSE;
+
+       best_priority=captivemodid_module_type_best_priority_lookup(module->type);
+       if (best_priority==G_MININT     /* no longer seeking for such module */
+                       || module_available->module->priority==best_priority) {
+               if (captivemodid_module_type_best_priority_found(module->type)) {
+                       /* Postpone (*acquire_module_all_modules_found_notify)()
+                        * after (*acquire_module_available_notify)().
+                        */
+                       all_modules_found=TRUE;
+                       }
+               }
+
+       if (acquire_module_available_notify)
+               (*acquire_module_available_notify)(module_available);
+       if (all_modules_found)
+               if (acquire_module_all_modules_found_notify)
+                       (*acquire_module_all_modules_found_notify)();
 }
 
 void mod_uri_load_file_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri)
@@ -165,6 +240,9 @@ static gboolean mod_uri_load_directory_visit_func
 
        *recurse=FALSE;
 
+       if ((*ui_search_is_aborted)())
+               return FALSE;   /* abort traversal */
+
        switch (info->type) {
                case GNOME_VFS_FILE_TYPE_REGULAR: {
 GnomeVFSURI *file_uri;
index a0c03f3..f46e36e 100644 (file)
 
 G_BEGIN_DECLS
 
+struct module_available {
+       struct captivemodid_module *module;
+       gpointer file_base;     /* of 'module->length' */
+       gchar *uri_text;
+       };
+
+/* map: (const xmlChar *)type -> (struct module_available *) */
+extern GHashTable *module_available_hash;
+
+extern void (*acquire_module_available_notify)(struct module_available *module_available);
+extern void (*acquire_module_all_modules_found_notify)(void);
+
 void mod_uri_load_file_from_memory(gconstpointer file_base,size_t file_length,GnomeVFSURI *uri);
 void mod_uri_load(GnomeVFSURI *uri);
 
diff --git a/src/install/acquire/ui-line.c b/src/install/acquire/ui-line.c
new file mode 100644 (file)
index 0000000..c349d11
--- /dev/null
@@ -0,0 +1,282 @@
+/* $Id$
+ * Drivers acquiring installation utility
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include "ui-line.h"   /* self */
+#include <glib/gmessages.h>
+#include "moduriload.h"
+#include "main.h"
+#include <unistd.h>
+#include <time.h>
+
+#ifdef HAVE_LIBREADLINE
+#include <readline/readline.h>
+#ifdef HAVE_READLINE_HISTORY_H
+#include <readline/history.h>
+#endif /* HAVE_READLINE_HISTORY_H */
+#endif /* HAVE_LIBREADLINE */
+
+#include <captive/macros.h>
+
+static void print_ui_line_module_available(struct module_available *module_available)
+{
+gint priority_best;
+
+       g_return_if_fail(module_available!=NULL);
+       g_return_if_fail(module_available->module!=NULL);
+
+       if (G_MININT==(priority_best=captivemodid_module_type_best_priority_lookup(module_available->module->type)))
+               printf(_("Found best available \"%s\": %s\n"),module_available->module->type,module_available->module->id);
+       else
+               printf(_("Found although not best \"%s\" (pri=%d; best=%d): %s\n"),
+                               module_available->module->type,module_available->module->priority,priority_best,
+                               module_available->module->id);
+}
+
+static void ui_line_module_available_notify(struct module_available *module_available)
+{
+       g_return_if_fail(module_available!=NULL);
+
+       print_ui_line_module_available(module_available);
+       printf(_("at URI: %s\n"),module_available->uri_text);
+}
+
+static gboolean all_modules_found=FALSE;
+
+static void ui_line_all_modules_found_notify(void)
+{
+       puts(_("All modules found in their best known versions."));
+       all_modules_found=TRUE;
+}
+
+static gboolean aborted=FALSE;
+static time_t search_start_time;
+static gboolean abort_msg_printed=FALSE;
+
+static gboolean ui_line_search_is_aborted(void)
+{
+fd_set readfds;
+struct timeval timeval;
+
+       if (aborted)
+               return TRUE;
+       if (all_modules_found)
+               return TRUE;
+
+       if (!search_start_time)
+               search_start_time=time(NULL);
+       if (!abort_msg_printed && time(NULL)>=search_start_time+2) {
+               puts(_("Searching... Hit ENTER to abort."));
+               abort_msg_printed=TRUE;
+               }
+
+       if (isatty(0)) {
+               FD_ZERO(&readfds);
+               FD_SET(0,&readfds);
+               timeval.tv_sec=0;
+               timeval.tv_usec=0;
+               if (1==select(1,&readfds,NULL,NULL,&timeval)) {
+                       aborted=TRUE;
+                       getchar();
+                       puts(_("*** OPERATION ABORTED ***"));
+                       return TRUE;
+                       }
+               }
+
+       return FALSE;
+}
+
+static void ui_line_search_is_aborted_reset(void)
+{
+       aborted=FALSE;
+       search_start_time=0;
+       abort_msg_printed=FALSE;
+}
+
+static char *line_read(const gchar *prompt)
+{
+#ifdef HAVE_LIBREADLINE
+char *line;
+#else /* HAVE_LIBREADLINE */
+char line[1024],*s;
+#endif /* HAVE_LIBREADLINE */
+
+       g_return_val_if_fail(prompt!=NULL,NULL);
+
+       ui_line_search_is_aborted_reset();
+
+#ifdef HAVE_LIBREADLINE
+       line=readline(prompt);
+#ifdef HAVE_ADD_HISTORY
+       if (line && *line)
+               add_history(line);
+#endif /* HAVE_ADD_HISTORY */
+#else /* HAVE_LIBREADLINE */
+       fputs(prompt,stdout); fflush(stdout);
+       line=fgets(line,sizeof(line),stdin);
+#endif /* HAVE_LIBREADLINE */
+       if (!line)
+               return NULL;
+#ifndef HAVE_LIBREADLINE
+       if (line && (s=strchr(line,'\n')))
+               *s='\0';
+#endif /* HAVE_LIBREADLINE */
+
+       return line;
+}
+
+/* FIXME: HACK: Encode module essentiality to '.captivemodid.xml'. */
+struct print_modules_available_foreach_param {
+       gboolean ntoskrnl_exe_found;
+       gboolean ntfs_sys_found;
+       };
+
+static void print_modules_available_foreach
+               (const xmlChar *type /* key */,struct module_available *module_available /* value */,
+               struct print_modules_available_foreach_param *param /* user_data */)
+{
+       g_return_if_fail(type!=NULL);
+       g_return_if_fail(module_available!=NULL);
+       g_return_if_fail(module_available->module!=NULL);
+       g_return_if_fail(!strcmp(type,module_available->module->type));
+       g_return_if_fail(param!=NULL);
+
+       print_ui_line_module_available(module_available);
+
+       /**/ if (!strcmp(type,"ntoskrnl.exe"))
+               param->ntoskrnl_exe_found=TRUE;
+       else if (!strcmp(type,"ntfs.sys"))
+               param->ntfs_sys_found=TRUE;
+}
+
+/* Returns: TRUE if essential modules were found at any priority. */
+static gboolean print_modules_available(void)
+{
+struct print_modules_available_foreach_param param;
+gboolean r;
+
+       putchar('\n');
+       param.ntoskrnl_exe_found=FALSE;
+       param.ntfs_sys_found=FALSE;
+       if (module_available_hash)
+               g_hash_table_foreach(module_available_hash,(GHFunc)print_modules_available_foreach,&param);
+       r=param.ntoskrnl_exe_found && param.ntfs_sys_found;
+
+       if (!param.ntoskrnl_exe_found)
+               printf(_("Still needed essential module: %s\n"),"ntoskrnl.exe");
+       if (!param.ntfs_sys_found)
+               printf(_("Still needed essential module: %s\n"),"ntfs.sys");
+       if (r)
+               puts(_(
+                               "Essential modules (\"ntoskrnl.exe\" and \"ntfs.sys\") are available.\n"
+                               "You still may want to get their better version and/or more modules."));
+       putchar('\n');
+
+       return r;
+}
+
+static gboolean ui_line_interactive_ask(const gchar *prompt)
+{
+char *line;
+gboolean essentials_available;
+
+       if (all_modules_found)
+               return FALSE;
+
+  essentials_available=print_modules_available();
+       puts(prompt);
+       for (;;) {
+               line=line_read(captive_printf_alloca(_("Enter 'y' for YES, 'n' to NO%s [hit ENTER for YES]: "),
+                               (!essentials_available ? "" : _(", 'd' if DONE"))));
+               if (!line)
+                       return FALSE;
+               if (!strncasecmp(line,_("yes"),strlen(line))) {
+                       free(line);
+                       return TRUE;
+                       }
+               if (!strncasecmp(line,_("no"),strlen(line))) {
+                       free(line);
+                       return FALSE;
+                       }
+               if (!strncasecmp(line,_("done"),strlen(line)))
+                       exit(EXIT_SUCCESS);
+               free(line);
+               }
+       /* NOTREACHED */
+}
+
+static void ui_line_interactive(void)
+{
+#ifndef HAVE_LIBREADLINE
+       puts(_("Line editing not available, please recompile with readline library installed"));
+#endif /* HAVE_LIBREADLINE */
+
+       if (ui_line_interactive_ask(_("Quickly scan your local disks to find needed drivers?")))
+               scan_disks_quick();
+       while (!all_modules_found) {
+char *line;
+
+               if (ui_line_interactive_ask(_("Fully scan all directories of your local disks?")))
+                       scan_disks();
+
+               if (!all_modules_found)
+                       do {
+                               print_modules_available();
+                               puts(_("Do you want to enter your custom search path and/or files? You can also enter web URL."));
+                               line=line_read(_("Enter pathname or URL [hit ENTER to skip it]: "));
+                               if (line && *line) {
+GnomeVFSURI *uri;
+
+                                       uri=gnome_vfs_uri_new((strncmp(line,"http://",strlen("http://")) ? line
+                                                       : captive_printf_alloca("httpcaptive://%s",line+strlen("http://"))));
+                                       if (!uri)
+                                               printf(_("Error paring URI: %s"),line);
+                                       else {
+                                               mod_uri_load(uri);
+                                               gnome_vfs_uri_unref(uri);
+                                               }
+                                       free(line);
+                                       }
+                               else {
+                                       free(line);
+                                       line=NULL;
+                                       }
+                               } while (!all_modules_found && line);
+
+               if (ui_line_interactive_ask(_(
+                               "You can download the best available version of needed drivers from Microsoft.\n"
+                               "They can be found in Microsoft Windows XP Service Pack 1 Checked Build.\n"
+                               "URL: http://www.microsoft.com/WindowsXP/pro/downloads/servicepacks/sp1/checkedbuild.asp\n"
+                               "Legal: In some countries you need to have valid Microsoft Windows XP license to use it.\n"
+                               "We will need to download approx 29MB od data right now (takes 2 hours on 33.6 modem).")))
+                       microsoft_com();
+               if (!all_modules_found)
+                       puts(_("\nWe tried all available drivers acquiration method - the options will start again."));
+               }
+}
+
+gboolean ui_line_init(void)
+{
+       acquire_module_available_notify=ui_line_module_available_notify;
+       acquire_module_all_modules_found_notify=ui_line_all_modules_found_notify;
+       ui_search_is_aborted=ui_line_search_is_aborted;
+       ui_interactive=ui_line_interactive;
+       return TRUE;
+}
diff --git a/src/install/acquire/ui-line.h b/src/install/acquire/ui-line.h
new file mode 100644 (file)
index 0000000..32db441
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id$
+ * Include file for drivers acquiring installation utility
+ * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; exactly version 2 of June 1991 is required
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef _CAPTIVE_INSTALL_ACQUIRE_UI_LINE_H
+#define _CAPTIVE_INSTALL_ACQUIRE_UI_LINE_H 1
+
+
+#include <glib/gtypes.h>
+
+
+G_BEGIN_DECLS
+
+gboolean ui_line_init(void);
+
+G_END_DECLS
+
+
+#endif /* _CAPTIVE_INSTALL_ACQUIRE_UI_LINE_H */