1177fb1debad0708c3efbc24c85640a519559bfa
[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 #include "final.h"
29
30 #ifdef HAVE_LIBREADLINE
31 #include <readline/readline.h>
32 #ifdef HAVE_READLINE_HISTORY_H
33 #include <readline/history.h>
34 #endif /* HAVE_READLINE_HISTORY_H */
35 #endif /* HAVE_LIBREADLINE */
36
37 #include <captive/macros.h>
38 #include <captive/captivemodid.h>
39
40 static void print_ui_line_module_available(struct module_available *module_available)
41 {
42 gint priority_best;
43
44         g_return_if_fail(module_available!=NULL);
45         g_return_if_fail(module_available->module!=NULL);
46
47         if (G_MININT==(priority_best=captive_captivemodid_module_type_best_priority_lookup(
48                         captivemodid,module_available->module->type)))
49                 printf(_("Found best available \"%s\": %s\n"),module_available->module->type,module_available->module->id);
50         else
51                 printf(_("Found although not best \"%s\" (pri=%d; best=%d): %s\n"),
52                                 module_available->module->type,module_available->module->priority,priority_best,
53                                 module_available->module->id);
54 }
55
56 static void ui_line_module_available_notify(struct module_available *module_available)
57 {
58         g_return_if_fail(module_available!=NULL);
59
60         print_ui_line_module_available(module_available);
61         printf(_("at URI: %s\n"),module_available->uri_text);
62 }
63
64 static gboolean all_modules_found=FALSE;
65
66 static void ui_line_all_modules_found_notify(void)
67 {
68         puts(_("All modules found in their best known versions."));
69         all_modules_found=TRUE;
70 }
71
72 static gboolean aborted=FALSE;
73 static time_t search_start_time;
74 static gboolean abort_msg_printed=FALSE;
75
76 static gboolean ui_line_progress(GnomeVFSURI *uri)
77 {
78 fd_set readfds;
79 struct timeval timeval;
80 static int stdin_isatty=-1;
81
82         /* 'uri' may be NULL */
83
84         if (aborted)
85                 return TRUE;
86         if (all_modules_found)
87                 return TRUE;
88
89         if (!search_start_time)
90                 search_start_time=time(NULL);
91         if (!abort_msg_printed && time(NULL)>=search_start_time+2) {
92                 puts(_("Searching... Hit ENTER to abort."));
93                 abort_msg_printed=TRUE;
94                 }
95
96         if (stdin_isatty==-1)
97                 stdin_isatty=isatty(0);
98         if (stdin_isatty>0) {
99                 FD_ZERO(&readfds);
100                 FD_SET(0,&readfds);
101                 timeval.tv_sec=0;
102                 timeval.tv_usec=0;
103                 if (1==select(1,&readfds,NULL,NULL,&timeval)) {
104                         aborted=TRUE;
105                         getchar();
106                         puts(_("*** OPERATION ABORTED ***"));
107                         return TRUE;
108                         }
109                 }
110
111         return FALSE;
112 }
113
114 static void ui_line_progress_reset(void)
115 {
116         aborted=FALSE;
117         search_start_time=0;
118         abort_msg_printed=FALSE;
119 }
120
121 static char *line_read(const gchar *prompt)
122 {
123 #ifdef HAVE_LIBREADLINE
124 char *line;
125 #else /* HAVE_LIBREADLINE */
126 char line[1024],*s;
127 #endif /* HAVE_LIBREADLINE */
128
129         g_return_val_if_fail(prompt!=NULL,NULL);
130
131         ui_line_progress_reset();
132
133 #ifdef HAVE_LIBREADLINE
134         line=readline(prompt);
135 #ifdef HAVE_ADD_HISTORY
136         if (line && *line)
137                 add_history(line);
138 #endif /* HAVE_ADD_HISTORY */
139 #else /* HAVE_LIBREADLINE */
140         fputs(prompt,stdout); fflush(stdout);
141         line=fgets(line,sizeof(line),stdin);
142 #endif /* HAVE_LIBREADLINE */
143         if (!line)
144                 return NULL;
145 #ifndef HAVE_LIBREADLINE
146         if (line && (s=strchr(line,'\n')))
147                 *s='\0';
148 #endif /* HAVE_LIBREADLINE */
149
150         return line;
151 }
152
153 /* FIXME: HACK: Encode module essentiality to '.captivemodid.xml'. */
154 struct print_modules_available_foreach_param {
155         gboolean do_print;
156         gboolean ntoskrnl_exe_found;
157         gboolean ntfs_sys_found;
158         };
159
160 static void print_modules_available_foreach
161                 (const xmlChar *type /* key */,struct module_available *module_available /* value */,
162                 struct print_modules_available_foreach_param *param /* user_data */)
163 {
164         g_return_if_fail(type!=NULL);
165         g_return_if_fail(module_available!=NULL);
166         g_return_if_fail(module_available->module!=NULL);
167         g_return_if_fail(!strcmp((const char *)type,(const char *)module_available->module->type));
168         g_return_if_fail(param!=NULL);
169
170         if (param->do_print)
171                 print_ui_line_module_available(module_available);
172
173         /**/ if (!strcmp((const char *)type,"ntoskrnl.exe"))
174                 param->ntoskrnl_exe_found=TRUE;
175         else if (!strcmp((const char *)type,"ntfs.sys"))
176                 param->ntfs_sys_found=TRUE;
177 }
178
179 /* Returns: TRUE if essential modules were found at any priority. */
180 static gboolean print_modules_available(void)
181 {
182 struct print_modules_available_foreach_param param;
183 gboolean r;
184 static gboolean first_time=TRUE;
185
186         putchar('\n');
187         param.do_print=!first_time;
188         param.ntoskrnl_exe_found=FALSE;
189         param.ntfs_sys_found=FALSE;
190         if (module_available_hash)
191                 g_hash_table_foreach(module_available_hash,(GHFunc)print_modules_available_foreach,&param);
192         r=param.ntoskrnl_exe_found && param.ntfs_sys_found;
193
194         if (!param.ntoskrnl_exe_found)
195                 printf(_("Still needed essential module: %s\n"),"ntoskrnl.exe");
196         if (!param.ntfs_sys_found)
197                 printf(_("Still needed essential module: %s\n"),"ntfs.sys");
198         if (r)
199                 puts(_(
200                                 "Essential modules (\"ntoskrnl.exe\" and \"ntfs.sys\") are available.\n"
201                                 "You may still want to get their better version and/or more modules."));
202         putchar('\n');
203
204         first_time=FALSE;
205
206         return r;
207 }
208
209 static gboolean ui_line_interactive_ask(const gchar *prompt)
210 {
211 char *line;
212 gboolean essentials_available;
213
214         if (all_modules_found)
215                 return FALSE;
216
217   essentials_available=print_modules_available();
218         puts(prompt);
219         for (;;) {
220                 line=line_read(captive_printf_alloca(_("Enter 'y' for YES, 'n' to NO%s [hit ENTER for YES]: "),
221                                 (!essentials_available ? "" : _(", 'd' if DONE"))));
222                 if (!line)
223                         return FALSE;
224                 if (!strncasecmp(line,_("yes"),strlen(line))) {
225                         free(line);
226                         return TRUE;
227                         }
228                 if (!strncasecmp(line,_("no"),strlen(line))) {
229                         free(line);
230                         return FALSE;
231                         }
232                 if (!strncasecmp(line,_("done"),strlen(line))) {
233                         putchar('\n');
234                         puts(final_text(all_modules_found));
235                         exit(EXIT_SUCCESS);
236                         }
237                 free(line);
238                 }
239         /* NOTREACHED */
240 }
241
242 static void ui_line_interactive(void)
243 {
244 #ifndef HAVE_LIBREADLINE
245         puts(_("Line editing not available, please recompile with readline library installed"));
246 #endif /* HAVE_LIBREADLINE */
247
248         if (ui_line_interactive_ask(_("Quickly scan your local disks to find needed drivers?")))
249                 scan_disks_quick();
250         while (!all_modules_found) {
251 char *line;
252
253                 if (ui_line_interactive_ask(_(
254                                 "Detection of language localized MS-Windows drivers is missing."
255                                 " You may need to copy localized ntfs.sys and ntoskrnl.exe to /var/lib/captive/ by cp(1) command;"
256                                 " contact me for their proper identification, please.\n"
257                                 "Fully scan all directories of your local disks?")))
258                         scan_disks();
259
260                 if (!all_modules_found)
261                         do {
262                                 print_modules_available();
263                                 puts(_("Do you want to enter your custom search path and/or files? You can also enter web URL."));
264                                 line=line_read(_("Enter pathname or URL [hit ENTER to skip it]: "));
265                                 if (line && *line) {
266 GnomeVFSURI *uri;
267
268                                         if (!(uri=gnome_vfs_uri_new(line)))
269                                                 printf(_("Error paring URI: %s"),line);
270                                         else {
271                                                 mod_uri_load_base_reporting(uri);
272                                                 gnome_vfs_uri_unref(uri);
273                                                 }
274                                         free(line);
275                                         }
276                                 else {
277                                         free(line);
278                                         line=NULL;
279                                         }
280                                 } while (!all_modules_found && line);
281
282                 if (ui_line_interactive_ask(_(
283                                 "You can download the best available version of needed drivers from Microsoft. They can be found in Microsoft Windows XP Service Pack 2 Checked Build.\n"
284                                 "URL: http://msdn.microsoft.com/security/productinfo/xpsp2\n"
285                                 "Legal: In some countries you need to have valid Microsoft Windows XP license to use it.\n"
286                                 "It is needed to download approx 61MB of data right now out of the 307MB file size. You can also download the file separately and load it in the previous screen if some problems occur.\n")))
287                         microsoft_com();
288                 if (!all_modules_found)
289                         puts(_("\nWe tried all available drivers acquiration methods - the options will start again."));
290                 }
291         putchar('\n');
292         puts(final_text(all_modules_found));
293 }
294
295 gboolean ui_line_init(void)
296 {
297         acquire_module_available_notify=ui_line_module_available_notify;
298         acquire_module_all_modules_found_notify=ui_line_all_modules_found_notify;
299         ui_progress=ui_line_progress;
300         ui_interactive=ui_line_interactive;
301         /* 'captive_captivemodid_module_best_priority_notify' left NULL. */
302         return TRUE;
303 }