First usable command-line UI version.
[captive.git] / src / install / acquire / ui-line.c
1 /* $Id$
2  * Drivers acquiring installation utility
3  * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "ui-line.h"    /* self */
23 #include <glib/gmessages.h>
24 #include "moduriload.h"
25 #include "main.h"
26 #include <unistd.h>
27 #include <time.h>
28
29 #ifdef HAVE_LIBREADLINE
30 #include <readline/readline.h>
31 #ifdef HAVE_READLINE_HISTORY_H
32 #include <readline/history.h>
33 #endif /* HAVE_READLINE_HISTORY_H */
34 #endif /* HAVE_LIBREADLINE */
35
36 #include <captive/macros.h>
37
38 static void print_ui_line_module_available(struct module_available *module_available)
39 {
40 gint priority_best;
41
42         g_return_if_fail(module_available!=NULL);
43         g_return_if_fail(module_available->module!=NULL);
44
45         if (G_MININT==(priority_best=captivemodid_module_type_best_priority_lookup(module_available->module->type)))
46                 printf(_("Found best available \"%s\": %s\n"),module_available->module->type,module_available->module->id);
47         else
48                 printf(_("Found although not best \"%s\" (pri=%d; best=%d): %s\n"),
49                                 module_available->module->type,module_available->module->priority,priority_best,
50                                 module_available->module->id);
51 }
52
53 static void ui_line_module_available_notify(struct module_available *module_available)
54 {
55         g_return_if_fail(module_available!=NULL);
56
57         print_ui_line_module_available(module_available);
58         printf(_("at URI: %s\n"),module_available->uri_text);
59 }
60
61 static gboolean all_modules_found=FALSE;
62
63 static void ui_line_all_modules_found_notify(void)
64 {
65         puts(_("All modules found in their best known versions."));
66         all_modules_found=TRUE;
67 }
68
69 static gboolean aborted=FALSE;
70 static time_t search_start_time;
71 static gboolean abort_msg_printed=FALSE;
72
73 static gboolean ui_line_search_is_aborted(void)
74 {
75 fd_set readfds;
76 struct timeval timeval;
77
78         if (aborted)
79                 return TRUE;
80         if (all_modules_found)
81                 return TRUE;
82
83         if (!search_start_time)
84                 search_start_time=time(NULL);
85         if (!abort_msg_printed && time(NULL)>=search_start_time+2) {
86                 puts(_("Searching... Hit ENTER to abort."));
87                 abort_msg_printed=TRUE;
88                 }
89
90         if (isatty(0)) {
91                 FD_ZERO(&readfds);
92                 FD_SET(0,&readfds);
93                 timeval.tv_sec=0;
94                 timeval.tv_usec=0;
95                 if (1==select(1,&readfds,NULL,NULL,&timeval)) {
96                         aborted=TRUE;
97                         getchar();
98                         puts(_("*** OPERATION ABORTED ***"));
99                         return TRUE;
100                         }
101                 }
102
103         return FALSE;
104 }
105
106 static void ui_line_search_is_aborted_reset(void)
107 {
108         aborted=FALSE;
109         search_start_time=0;
110         abort_msg_printed=FALSE;
111 }
112
113 static char *line_read(const gchar *prompt)
114 {
115 #ifdef HAVE_LIBREADLINE
116 char *line;
117 #else /* HAVE_LIBREADLINE */
118 char line[1024],*s;
119 #endif /* HAVE_LIBREADLINE */
120
121         g_return_val_if_fail(prompt!=NULL,NULL);
122
123         ui_line_search_is_aborted_reset();
124
125 #ifdef HAVE_LIBREADLINE
126         line=readline(prompt);
127 #ifdef HAVE_ADD_HISTORY
128         if (line && *line)
129                 add_history(line);
130 #endif /* HAVE_ADD_HISTORY */
131 #else /* HAVE_LIBREADLINE */
132         fputs(prompt,stdout); fflush(stdout);
133         line=fgets(line,sizeof(line),stdin);
134 #endif /* HAVE_LIBREADLINE */
135         if (!line)
136                 return NULL;
137 #ifndef HAVE_LIBREADLINE
138         if (line && (s=strchr(line,'\n')))
139                 *s='\0';
140 #endif /* HAVE_LIBREADLINE */
141
142         return line;
143 }
144
145 /* FIXME: HACK: Encode module essentiality to '.captivemodid.xml'. */
146 struct print_modules_available_foreach_param {
147         gboolean ntoskrnl_exe_found;
148         gboolean ntfs_sys_found;
149         };
150
151 static void print_modules_available_foreach
152                 (const xmlChar *type /* key */,struct module_available *module_available /* value */,
153                 struct print_modules_available_foreach_param *param /* user_data */)
154 {
155         g_return_if_fail(type!=NULL);
156         g_return_if_fail(module_available!=NULL);
157         g_return_if_fail(module_available->module!=NULL);
158         g_return_if_fail(!strcmp(type,module_available->module->type));
159         g_return_if_fail(param!=NULL);
160
161         print_ui_line_module_available(module_available);
162
163         /**/ if (!strcmp(type,"ntoskrnl.exe"))
164                 param->ntoskrnl_exe_found=TRUE;
165         else if (!strcmp(type,"ntfs.sys"))
166                 param->ntfs_sys_found=TRUE;
167 }
168
169 /* Returns: TRUE if essential modules were found at any priority. */
170 static gboolean print_modules_available(void)
171 {
172 struct print_modules_available_foreach_param param;
173 gboolean r;
174
175         putchar('\n');
176         param.ntoskrnl_exe_found=FALSE;
177         param.ntfs_sys_found=FALSE;
178         if (module_available_hash)
179                 g_hash_table_foreach(module_available_hash,(GHFunc)print_modules_available_foreach,&param);
180         r=param.ntoskrnl_exe_found && param.ntfs_sys_found;
181
182         if (!param.ntoskrnl_exe_found)
183                 printf(_("Still needed essential module: %s\n"),"ntoskrnl.exe");
184         if (!param.ntfs_sys_found)
185                 printf(_("Still needed essential module: %s\n"),"ntfs.sys");
186         if (r)
187                 puts(_(
188                                 "Essential modules (\"ntoskrnl.exe\" and \"ntfs.sys\") are available.\n"
189                                 "You still may want to get their better version and/or more modules."));
190         putchar('\n');
191
192         return r;
193 }
194
195 static gboolean ui_line_interactive_ask(const gchar *prompt)
196 {
197 char *line;
198 gboolean essentials_available;
199
200         if (all_modules_found)
201                 return FALSE;
202
203   essentials_available=print_modules_available();
204         puts(prompt);
205         for (;;) {
206                 line=line_read(captive_printf_alloca(_("Enter 'y' for YES, 'n' to NO%s [hit ENTER for YES]: "),
207                                 (!essentials_available ? "" : _(", 'd' if DONE"))));
208                 if (!line)
209                         return FALSE;
210                 if (!strncasecmp(line,_("yes"),strlen(line))) {
211                         free(line);
212                         return TRUE;
213                         }
214                 if (!strncasecmp(line,_("no"),strlen(line))) {
215                         free(line);
216                         return FALSE;
217                         }
218                 if (!strncasecmp(line,_("done"),strlen(line)))
219                         exit(EXIT_SUCCESS);
220                 free(line);
221                 }
222         /* NOTREACHED */
223 }
224
225 static void ui_line_interactive(void)
226 {
227 #ifndef HAVE_LIBREADLINE
228         puts(_("Line editing not available, please recompile with readline library installed"));
229 #endif /* HAVE_LIBREADLINE */
230
231         if (ui_line_interactive_ask(_("Quickly scan your local disks to find needed drivers?")))
232                 scan_disks_quick();
233         while (!all_modules_found) {
234 char *line;
235
236                 if (ui_line_interactive_ask(_("Fully scan all directories of your local disks?")))
237                         scan_disks();
238
239                 if (!all_modules_found)
240                         do {
241                                 print_modules_available();
242                                 puts(_("Do you want to enter your custom search path and/or files? You can also enter web URL."));
243                                 line=line_read(_("Enter pathname or URL [hit ENTER to skip it]: "));
244                                 if (line && *line) {
245 GnomeVFSURI *uri;
246
247                                         uri=gnome_vfs_uri_new((strncmp(line,"http://",strlen("http://")) ? line
248                                                         : captive_printf_alloca("httpcaptive://%s",line+strlen("http://"))));
249                                         if (!uri)
250                                                 printf(_("Error paring URI: %s"),line);
251                                         else {
252                                                 mod_uri_load(uri);
253                                                 gnome_vfs_uri_unref(uri);
254                                                 }
255                                         free(line);
256                                         }
257                                 else {
258                                         free(line);
259                                         line=NULL;
260                                         }
261                                 } while (!all_modules_found && line);
262
263                 if (ui_line_interactive_ask(_(
264                                 "You can download the best available version of needed drivers from Microsoft.\n"
265                                 "They can be found in Microsoft Windows XP Service Pack 1 Checked Build.\n"
266                                 "URL: http://www.microsoft.com/WindowsXP/pro/downloads/servicepacks/sp1/checkedbuild.asp\n"
267                                 "Legal: In some countries you need to have valid Microsoft Windows XP license to use it.\n"
268                                 "We will need to download approx 29MB od data right now (takes 2 hours on 33.6 modem).")))
269                         microsoft_com();
270                 if (!all_modules_found)
271                         puts(_("\nWe tried all available drivers acquiration method - the options will start again."));
272                 }
273 }
274
275 gboolean ui_line_init(void)
276 {
277         acquire_module_available_notify=ui_line_module_available_notify;
278         acquire_module_all_modules_found_notify=ui_line_all_modules_found_notify;
279         ui_search_is_aborted=ui_line_search_is_aborted;
280         ui_interactive=ui_line_interactive;
281         return TRUE;
282 }