1 /*
2  * Copyright (c)2004 Cat's Eye Technologies.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  *   Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  *
11  *   Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in
13  *   the documentation and/or other materials provided with the
14  *   distribution.
15  *
16  *   Neither the name of Cat's Eye Technologies nor the names of its
17  *   contributors may be used to endorse or promote products derived
18  *   from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * main.c
36  * Main program for dfuife_curses.
37  * $Id: main.c,v 1.21 2005/03/25 04:51:10 cpressey Exp $
38  */
39 
40 #include <ctype.h>
41 #include <ncurses.h>
42 #include <signal.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <term.h>
46 #include <unistd.h>
47 
48 #ifdef ENABLE_NLS
49 #include <libintl.h>
50 #include "libdfui/lang.h"
51 #define _(String) gettext (String)
52 extern int _nl_msg_cat_cntr;
53 #else
54 #define _(String) (String)
55 #endif
56 
57 #include "libaura/mem.h"
58 
59 #include "libdfui/dfui.h"
60 #ifdef DEBUG
61 #include "libdfui/dump.h"
62 #endif
63 #include "libdfui/system.h"
64 
65 #include "curses_form.h"
66 #include "curses_widget.h"
67 #include "curses_bar.h"
68 #include "curses_util.h"
69 #include "curses_xlat.h"
70 
71 /*** GLOBALS ***/
72 
73 struct curses_bar *menubar, *statusbar;
74 
75 /*** SIGNAL HANDLING ***/
76 
77 #ifdef SIGNAL_HANDLING
78 volatile sig_atomic_t caught_signal;
79 
80 void signal_handler(int signo)
81 {
82 	caught_signal = signo;
83 }
84 
85 void
86 abort_frontend(struct dfui_connection *c)
87 {
88 	dfui_fe_abort(c);
89 
90 	clear();
91 	refresh();
92 	endwin();
93 	exit(1);
94 }
95 #endif
96 
97 static struct dfui_response *
98 #ifdef SIGNAL_HANDLING
99 present_form(struct dfui_connection *c, struct dfui_form *f)
100 #else
101 present_form(struct dfui_connection *c __unused, struct dfui_form *f)
102 #endif
103 {
104 	struct dfui_response *r = NULL;
105 	struct curses_form *cf;
106 	struct curses_widget *cw;
107 
108 	cf = curses_form_construct_from_dfui_form(f);
109 	curses_form_draw(cf);
110 	curses_form_refresh(cf);
111 	cw = curses_form_frob(cf);
112 #ifdef SIGNAL_HANDLING
113 	if (caught_signal) abort_frontend(c);
114 #endif
115 	r = response_construct_from_curses_form(f, cf, cw);
116 	curses_form_free(cf);
117 	curses_form_refresh(NULL);
118 	return(r);
119 }
120 
121 static void
122 usage(char **argv)
123 {
124 	fprintf(stderr, _("Usage: %s "
125 	    "[-b backdrop] [-r rendezvous] [-t caps|npipe|tcp]\n"),
126 	    argv[0]);
127 	exit(1);
128 }
129 
130 /*
131  * dfuife_curses
132  * DFUI Curses frontend.
133  */
134 int
135 main(int argc, char **argv)
136 {
137 	struct dfui_connection *c;
138 	struct dfui_form *f;
139 	struct dfui_response *r;
140 	struct dfui_progress *pr;
141 	struct dfui_property *gp;
142 
143 	struct curses_form *pf = NULL;
144 	struct curses_widget *pbar = NULL, *plab = NULL, *pcan = NULL;
145 	struct curses_widget *w;
146 
147 	void *payload;
148 	int done = 0;
149 	char msgtype;
150 	int opt;
151 	int last_amount = 0;
152 	char last_message[80];
153 	int is_streaming = 0;
154 	int ch;
155 	char *bdropfn = NULL;
156 	char *rendezvous = NULL;
157 	int transport = 0;
158 	int force_monochrome = 0;
159 
160 	/*
161 	 * Get command-line arguments.
162 	 */
163 	while ((opt = getopt(argc, argv, "b:mr:t:")) != -1) {
164 		switch(opt) {
165 		case 'b':
166 			bdropfn = aura_strdup(optarg);
167 			break;
168 		case 'm':
169 			force_monochrome = 1;
170 			break;
171 		case 'r':
172 			rendezvous = aura_strdup(optarg);
173 			break;
174 		case 't':
175 			transport = user_get_transport(optarg);
176 			break;
177 		case '?':
178 		default:
179 			usage(argv);
180 		}
181 	}
182 	argc -= optind;
183 	argv += optind;
184 
185 	if (!transport)
186 		transport = user_get_transport("tcp");
187 
188 	if (rendezvous == NULL) {
189 		if (transport == DFUI_TRANSPORT_TCP) {
190 			rendezvous = aura_strdup("9999");
191 		} else {
192 			rendezvous = aura_strdup("test");
193 		}
194 	}
195 
196 #ifdef ENABLE_NLS
197 	setlocale (LC_ALL, "");
198 	bindtextdomain (PACKAGE, LOCALEDIR);
199 	textdomain (PACKAGE);
200 #endif
201 
202 	/*
203 	 * Set up screen.
204 	 */
205 
206 	initscr();
207 
208 #ifdef SIGNAL_HANDLING
209 	signal(SIGINT, signal_handler);
210 	signal(SIGTERM, signal_handler);
211 #endif
212 
213 	curses_colors_init(force_monochrome);
214 	cbreak();
215 	noecho();
216 	nonl();
217 	keypad(stdscr, TRUE);
218 	curs_set(0);
219 
220 	getmaxyx(stdscr, ymax, xmax);
221 
222 	if (bdropfn == NULL) {
223 		curses_colors_set(stdscr, CURSES_COLORS_BACKDROP);
224 		curses_window_blank(stdscr);
225 	} else {
226 		curses_load_backdrop(stdscr, bdropfn);
227 	}
228 
229 	menubar = curses_bar_new(0, 0, 0, 1, CURSES_COLORS_MENUBAR,
230 				 CURSES_BAR_WIDEN);
231 	statusbar = curses_bar_new(0, 0, 0, 1, CURSES_COLORS_STATUSBAR,
232 				   CURSES_BAR_WIDEN | CURSES_BAR_BOTTOM);
233 
234 	curses_bar_set_text(menubar, _("F10=Refresh Display"));
235 	curses_bar_set_text(statusbar, _("Waiting for backend..."));
236 
237 	update_panels();
238 	doupdate();
239 
240 #ifdef DEBUG
241 	dfui_debug_file = fopen("/tmp/dfuife_curses_debug.log", "w");
242 #endif
243 
244 	c = dfui_connection_new(transport, rendezvous);
245 	dfui_fe_connect(c);
246 
247 	curses_bar_set_text(statusbar, _("Connected"));
248 
249 	while (!done) {
250 		dfui_fe_receive(c, &msgtype, &payload);
251 		switch (msgtype) {
252 		case DFUI_BE_MSG_PRESENT:
253 			f = (struct dfui_form *)payload;
254 			r = present_form(c, f);
255 #ifdef SIGNAL_HANDLING
256 			if (caught_signal) abort_frontend(c);
257 #endif
258 			dfui_fe_submit(c, r);
259 			dfui_form_free(f);
260 			dfui_response_free(r);
261 			break;
262 		case DFUI_BE_MSG_PROG_BEGIN:
263 			pr = (struct dfui_progress *)payload;
264 			if (pf != NULL)
265 				curses_form_free(pf);
266 			is_streaming = dfui_progress_get_streaming(pr);
267 			last_amount = dfui_progress_get_amount(pr);
268 			strncpy(last_message, dfui_info_get_short_desc(
269 			    dfui_progress_get_info(pr)), 79);
270 			pf = curses_form_construct_from_dfui_progress(pr,
271 			    &pbar, &plab, &pcan);
272 			curses_form_draw(pf);
273 			curses_form_refresh(pf);
274 			dfui_progress_free(pr);
275 			nodelay(stdscr, TRUE);
276 			dfui_fe_progress_continue(c);
277 			break;
278 		case DFUI_BE_MSG_PROG_UPDATE:
279 			pr = (struct dfui_progress *)payload;
280 			if (pf != NULL) {
281 				curses_widgets_update_from_dfui_progress(pr,
282 				    pbar, plab, pcan);
283 			}
284 			dfui_progress_free(pr);
285 			ch = getch();
286 			if (ch == ' ' || ch == '\n' || ch == '\r') {
287 				dfui_fe_progress_cancel(c);
288 			} else if (ch == KEY_F(10)) {
289 				redrawwin(stdscr);
290 				curses_form_refresh(NULL);
291 				dfui_fe_progress_continue(c);
292 			} else {
293 				dfui_fe_progress_continue(c);
294 			}
295 			break;
296 		case DFUI_BE_MSG_PROG_END:
297 			if (pf != NULL) {
298 				if (is_streaming) {
299 					w = curses_form_widget_add(pf, 0, pf->int_height, 0,
300 					    CURSES_BUTTON, "OK", -1,
301 					    CURSES_WIDGET_CENTER | CURSES_WIDGET_WIDEN);
302 					pf->int_height++;
303 					curses_widget_set_click_cb(w, cb_click_close_form);
304 					pf->widget_focus = w;
305 					curses_form_widget_ensure_visible(w);
306 					curses_widget_draw(w);
307 					curses_form_refresh(pf);
308 					curses_form_frob(pf);
309 				}
310 				curses_form_free(pf);
311 				curses_form_refresh(NULL);
312 			}
313 			pf = NULL;
314 			plab = pbar = pcan = NULL;
315 			nodelay(stdscr, FALSE);
316 			dfui_fe_progress_continue(c);
317 			break;
318 		case DFUI_BE_MSG_SET_GLOBAL:
319 			gp = (struct dfui_property *)payload;
320 
321 #ifdef ENABLE_NLS
322 			/*
323 			 * Check for a change to the "lang" setting...
324 			 */
325 			if (strcmp(dfui_property_get_name(gp), "lang") == 0) {
326 				set_lang_envars(dfui_property_get_value(gp));
327 
328 				/* let gettext know about changes */
329 				++_nl_msg_cat_cntr;
330 
331 				/* BEGIN: reinit curses to use new TERM */
332 				curses_bar_free(menubar);
333 				curses_bar_free(statusbar);
334 
335 				endwin();
336 				newterm(getenv("TERM"), stdout, stdin);
337 
338 				curses_colors_init(force_monochrome);
339 				cbreak();
340 				noecho();
341 				nonl();
342 				keypad(stdscr, TRUE);
343 				curs_set(0);
344 
345 				update_panels();
346 				doupdate();
347 
348 				if (bdropfn == NULL) {
349 					curses_colors_set(stdscr,
350 					    CURSES_COLORS_BACKDROP);
351 					curses_window_blank(stdscr);
352 				} else {
353 					curses_load_backdrop(stdscr, bdropfn);
354 				}
355 
356 				menubar = curses_bar_new(0, 0, 0, 1,
357 				    CURSES_COLORS_MENUBAR, CURSES_BAR_WIDEN);
358 				statusbar = curses_bar_new(0, 0, 0, 1,
359 				    CURSES_COLORS_STATUSBAR,
360 				    CURSES_BAR_WIDEN | CURSES_BAR_BOTTOM);
361 				/* END: reinit curses to use new TERM */
362 
363 				curses_bar_set_text(menubar,
364 					_("F1=Help F10=Refresh Display"));
365 			}
366 #endif
367 
368 			dfui_fe_confirm_set_global(c);
369 			dfui_property_free(gp);
370 			break;
371 		case DFUI_BE_MSG_STOP:
372 			dfui_fe_confirm_stop(c);
373 			done = 1;
374 			break;
375 		}
376 	}
377 
378 	dfui_fe_disconnect(c);
379 
380 #ifdef DEBUG
381 	fclose(dfui_debug_file);
382 #endif
383 
384 	curses_bar_free(menubar);
385 	curses_bar_free(statusbar);
386 
387 	clear();
388 	refresh();
389 	endwin();
390 
391 	if (rendezvous != NULL)
392 		free(rendezvous);
393 	if (bdropfn != NULL)
394 		free(bdropfn);
395 
396 	exit(0);
397 }
398