ui/ncurses: Adjust position of add-url field to fit translated label
[petitboot] / ui / ncurses / nc-config.c
1 /*
2  *  Copyright (C) 2013 IBM Corporation
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #if defined(HAVE_CONFIG_H)
19 #include "config.h"
20 #endif
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <pb-config/pb-config.h>
27 #include <talloc/talloc.h>
28 #include <types/types.h>
29 #include <log/log.h>
30 #include <i18n/i18n.h>
31
32 #include "nc-cui.h"
33 #include "nc-config.h"
34 #include "nc-widgets.h"
35
36 #define N_FIELDS        26
37
38 extern struct help_text config_help_text;
39
40 enum autoboot_type {
41         AUTOBOOT_ANY,
42         AUTOBOOT_ONE,
43         AUTOBOOT_DISABLED,
44 };
45
46 enum net_conf_type {
47         NET_CONF_TYPE_DHCP_ALL,
48         NET_CONF_TYPE_DHCP_ONE,
49         NET_CONF_TYPE_STATIC,
50 };
51
52 struct config_screen {
53         struct nc_scr           scr;
54         struct cui              *cui;
55         struct nc_widgetset     *widgetset;
56         WINDOW                  *pad;
57
58         bool                    exit;
59         bool                    show_help;
60         void                    (*on_exit)(struct cui *);
61
62         int                     scroll_y;
63
64         int                     label_x;
65         int                     field_x;
66         int                     network_config_y;
67
68         enum net_conf_type      net_conf_type;
69         enum autoboot_type      autoboot_type;
70
71         struct {
72                 struct nc_widget_select         *autoboot_f;
73                 struct nc_widget_label          *autoboot_l;
74                 struct nc_widget_select         *boot_device_f;
75                 struct nc_widget_textbox        *timeout_f;
76                 struct nc_widget_label          *timeout_l;
77                 struct nc_widget_label          *timeout_help_l;
78
79                 struct nc_widget_label          *network_l;
80                 struct nc_widget_select         *network_f;
81
82                 struct nc_widget_label          *iface_l;
83                 struct nc_widget_select         *iface_f;
84                 struct nc_widget_label          *ip_addr_l;
85                 struct nc_widget_textbox        *ip_addr_f;
86                 struct nc_widget_label          *ip_mask_l;
87                 struct nc_widget_textbox        *ip_mask_f;
88                 struct nc_widget_label          *ip_addr_mask_help_l;
89                 struct nc_widget_label          *gateway_l;
90                 struct nc_widget_textbox        *gateway_f;
91                 struct nc_widget_label          *gateway_help_l;
92                 struct nc_widget_label          *dns_l;
93                 struct nc_widget_textbox        *dns_f;
94                 struct nc_widget_label          *dns_dhcp_help_l;
95                 struct nc_widget_label          *dns_help_l;
96
97                 struct nc_widget_label          *safe_mode;
98                 struct nc_widget_button         *ok_b;
99                 struct nc_widget_button         *help_b;
100                 struct nc_widget_button         *cancel_b;
101         } widgets;
102 };
103
104 static struct config_screen *config_screen_from_scr(struct nc_scr *scr)
105 {
106         struct config_screen *config_screen;
107
108         assert(scr->sig == pb_config_screen_sig);
109         config_screen = (struct config_screen *)
110                 ((char *)scr - (size_t)&((struct config_screen *)0)->scr);
111         assert(config_screen->scr.sig == pb_config_screen_sig);
112         return config_screen;
113 }
114
115 static void pad_refresh(struct config_screen *screen)
116 {
117         int y, x, rows, cols;
118
119         getmaxyx(screen->scr.sub_ncw, rows, cols);
120         getbegyx(screen->scr.sub_ncw, y, x);
121
122         prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
123 }
124
125 static void config_screen_process_key(struct nc_scr *scr, int key)
126 {
127         struct config_screen *screen = config_screen_from_scr(scr);
128         bool handled;
129
130         handled = widgetset_process_key(screen->widgetset, key);
131
132         if (!handled) {
133                 switch (key) {
134                 case 'x':
135                 case 27: /* esc */
136                         screen->exit = true;
137                         break;
138                 case 'h':
139                         screen->show_help = true;
140                         break;
141                 }
142         }
143
144         if (screen->exit) {
145                 screen->on_exit(screen->cui);
146
147         } else if (screen->show_help) {
148                 screen->show_help = false;
149                 cui_show_help(screen->cui, _("System Configuration"),
150                                 &config_help_text);
151
152         } else if (handled) {
153                 pad_refresh(screen);
154         }
155 }
156
157 static void config_screen_resize(struct nc_scr *scr)
158 {
159         struct config_screen *screen = config_screen_from_scr(scr);
160         (void)screen;
161 }
162
163 static int config_screen_post(struct nc_scr *scr)
164 {
165         struct config_screen *screen = config_screen_from_scr(scr);
166         widgetset_post(screen->widgetset);
167         nc_scr_frame_draw(scr);
168         redrawwin(scr->main_ncw);
169         wrefresh(screen->scr.main_ncw);
170         pad_refresh(screen);
171         return 0;
172 }
173
174 static int config_screen_unpost(struct nc_scr *scr)
175 {
176         struct config_screen *screen = config_screen_from_scr(scr);
177         widgetset_unpost(screen->widgetset);
178         return 0;
179 }
180
181 struct nc_scr *config_screen_scr(struct config_screen *screen)
182 {
183         return &screen->scr;
184 }
185
186 static int screen_process_form(struct config_screen *screen)
187 {
188         const struct system_info *sysinfo = screen->cui->sysinfo;
189         enum net_conf_type net_conf_type;
190         struct interface_config *iface;
191         char *str, *end, *uuid;
192         struct config *config;
193         int rc, idx;
194
195         config = config_copy(screen, screen->cui->config);
196
197         screen->autoboot_type =
198                 widget_select_get_value(screen->widgets.autoboot_f);
199
200         config->autoboot_enabled = screen->autoboot_type != AUTOBOOT_DISABLED;
201
202         uuid = NULL;
203         if (screen->autoboot_type == AUTOBOOT_ONE) {
204                 char mac[20];
205
206                 /* if idx is -1 here, we have an unknown UUID selected.
207                  * Otherwise, it's a blockdev index (idx <= n_blockdevs) or an
208                  * interface index.
209                  */
210                 idx = widget_select_get_value(screen->widgets.boot_device_f);
211                 if (idx >= (int)sysinfo->n_blockdevs) {
212                         struct interface_info *info = sysinfo->
213                                 interfaces[idx - sysinfo->n_blockdevs];
214                         mac_str(info->hwaddr, info->hwaddr_size,
215                                         mac, sizeof(mac));
216                         uuid = mac;
217                 } else if (idx != -1) {
218                         uuid = sysinfo->blockdevs[idx]->uuid;
219                 }
220         }
221
222         talloc_free(config->boot_device);
223         config->boot_device = uuid ? talloc_strdup(config, uuid) : NULL;
224
225         str = widget_textbox_get_value(screen->widgets.timeout_f);
226         if (str) {
227                 unsigned long x;
228                 errno = 0;
229                 x = strtoul(str, &end, 10);
230                 if (!errno && end != str)
231                         config->autoboot_timeout_sec = x;
232         }
233
234         net_conf_type = widget_select_get_value(screen->widgets.network_f);
235
236         /* if we don't have any network interfaces, prevent per-interface
237          * configuration */
238         if (sysinfo->n_interfaces == 0)
239                 net_conf_type = NET_CONF_TYPE_DHCP_ALL;
240
241         if (net_conf_type == NET_CONF_TYPE_DHCP_ALL) {
242                 config->network.n_interfaces = 0;
243
244         } else {
245                 iface = talloc_zero(config, struct interface_config);
246                 config->network.n_interfaces = 1;
247                 config->network.interfaces = talloc_array(config,
248                                 struct interface_config *, 1);
249                 config->network.interfaces[0] = iface;
250
251                 /* copy hwaddr (from the sysinfo interface data) to
252                  * the configuration */
253                 idx = widget_select_get_value(screen->widgets.iface_f);
254                 memcpy(iface->hwaddr, sysinfo->interfaces[idx]->hwaddr,
255                                 sizeof(iface->hwaddr));
256         }
257
258         if (net_conf_type == NET_CONF_TYPE_DHCP_ONE) {
259                 iface->method = CONFIG_METHOD_DHCP;
260         }
261
262         if (net_conf_type == NET_CONF_TYPE_STATIC) {
263                 char *ip, *mask, *gateway;
264
265                 ip = widget_textbox_get_value(screen->widgets.ip_addr_f);
266                 mask = widget_textbox_get_value(screen->widgets.ip_mask_f);
267                 gateway = widget_textbox_get_value(screen->widgets.gateway_f);
268
269                 if (!ip || !*ip || !mask || !*mask) {
270                         screen->scr.frame.status =
271                                 _("No IP / mask values are set");
272                         nc_scr_frame_draw(&screen->scr);
273                         talloc_free(config);
274                         return -1;
275                 }
276
277                 iface->method = CONFIG_METHOD_STATIC;
278                 iface->static_config.address = talloc_asprintf(iface, "%s/%s",
279                                 ip, mask);
280                 iface->static_config.gateway = talloc_strdup(iface, gateway);
281         }
282
283         str = widget_textbox_get_value(screen->widgets.dns_f);
284         talloc_free(config->network.dns_servers);
285         config->network.dns_servers = NULL;
286         config->network.n_dns_servers = 0;
287
288         if (str && strlen(str)) {
289                 char *dns, *tmp;
290                 int i;
291
292                 for (;;) {
293                         dns = strtok_r(str, " \t", &tmp);
294
295                         if (!dns)
296                                 break;
297
298                         i = config->network.n_dns_servers++;
299                         config->network.dns_servers = talloc_realloc(config,
300                                         config->network.dns_servers,
301                                         const char *,
302                                         config->network.n_dns_servers);
303                         config->network.dns_servers[i] =
304                                 talloc_strdup(config, dns);
305
306                         str = NULL;
307                 }
308         }
309
310         config->safe_mode = false;
311         rc = cui_send_config(screen->cui, config);
312         talloc_free(config);
313
314         if (rc)
315                 pb_log("cui_send_config failed!\n");
316         else
317                 pb_debug("config sent!\n");
318
319         return 0;
320 }
321
322 static void ok_click(void *arg)
323 {
324         struct config_screen *screen = arg;
325         if (screen_process_form(screen))
326                 /* errors are written to the status line, so we'll need
327                  * to refresh */
328                 wrefresh(screen->scr.main_ncw);
329         else
330                 screen->exit = true;
331 }
332
333 static void help_click(void *arg)
334 {
335         struct config_screen *screen = arg;
336         screen->show_help = true;
337 }
338
339 static void cancel_click(void *arg)
340 {
341         struct config_screen *screen = arg;
342         screen->exit = true;
343 }
344
345 static int layout_pair(struct config_screen *screen, int y,
346                 struct nc_widget_label *label,
347                 struct nc_widget *field)
348 {
349         struct nc_widget *label_w = widget_label_base(label);
350         widget_move(label_w, y, screen->label_x);
351         widget_move(field, y, screen->field_x);
352         return max(widget_height(label_w), widget_height(field));
353 }
354
355 static void config_screen_layout_widgets(struct config_screen *screen)
356 {
357         struct nc_widget *wl, *wf, *wh;
358         int y, x, help_x;
359         bool show;
360
361         y = 1;
362         help_x = screen->field_x + 2 +
363                 widget_width(widget_textbox_base(screen->widgets.dns_f));
364
365         y += layout_pair(screen, y, screen->widgets.autoboot_l,
366                         widget_select_base(screen->widgets.autoboot_f));
367
368         wf = widget_select_base(screen->widgets.boot_device_f);
369         if (screen->autoboot_type == AUTOBOOT_ONE) {
370                 widget_set_visible(wf, true);
371                 widget_move(wf, y, screen->field_x + 3);
372                 y += widget_height(wf);
373         } else {
374                 widget_set_visible(wf, false);
375         }
376
377         y += 1;
378
379         wf = widget_textbox_base(screen->widgets.timeout_f);
380         wl = widget_label_base(screen->widgets.timeout_l);
381         wh = widget_label_base(screen->widgets.timeout_help_l);
382         if (screen->autoboot_type != AUTOBOOT_DISABLED) {
383                 widget_set_visible(wl, true);
384                 widget_set_visible(wf, true);
385                 widget_set_visible(wh, true);
386                 widget_move(wl, y, screen->label_x);
387                 widget_move(wf, y, screen->field_x);
388                 widget_move(wh, y, screen->field_x + widget_width(wf) + 1);
389                 y += 2;
390         } else {
391                 widget_set_visible(wl, false);
392                 widget_set_visible(wf, false);
393                 widget_set_visible(wh, false);
394         }
395
396         y += layout_pair(screen, y, screen->widgets.network_l,
397                         widget_select_base(screen->widgets.network_f));
398
399         y += 1;
400
401         /* conditionally show iface select */
402         wl = widget_label_base(screen->widgets.iface_l);
403         wf = widget_select_base(screen->widgets.iface_f);
404
405         show = screen->net_conf_type == NET_CONF_TYPE_DHCP_ONE ||
406                 screen->net_conf_type == NET_CONF_TYPE_STATIC;
407
408         widget_set_visible(wl, show);
409         widget_set_visible(wf, show);
410
411         if (show)
412                 y += layout_pair(screen, y, screen->widgets.iface_l, wf) + 1;
413
414         /* conditionally show static IP params */
415         show = screen->net_conf_type == NET_CONF_TYPE_STATIC;
416
417         wl = widget_label_base(screen->widgets.ip_addr_l);
418         wf = widget_textbox_base(screen->widgets.ip_addr_f);
419         widget_set_visible(wl, show);
420         widget_set_visible(wf, show);
421         x = screen->field_x + widget_width(wf) + 1;
422
423         if (show)
424                 layout_pair(screen, y, screen->widgets.ip_addr_l, wf);
425
426         wl = widget_label_base(screen->widgets.ip_mask_l);
427         wf = widget_textbox_base(screen->widgets.ip_mask_f);
428         widget_set_visible(wl, show);
429         widget_set_visible(wf, show);
430
431         if (show) {
432                 widget_move(wl, y, x);
433                 widget_move(wf, y, x + 2);
434         }
435
436         /* help for IP/mask */
437         wh = widget_label_base(screen->widgets.ip_addr_mask_help_l);
438         widget_set_visible(wh, show);
439         if (show) {
440                 widget_move(wh, y, help_x);
441                 y++;
442         }
443
444         wl = widget_label_base(screen->widgets.gateway_l);
445         wf = widget_textbox_base(screen->widgets.gateway_f);
446         wh = widget_label_base(screen->widgets.gateway_help_l);
447         widget_set_visible(wl, show);
448         widget_set_visible(wf, show);
449         widget_set_visible(wh, show);
450
451         if (show) {
452                 layout_pair(screen, y, screen->widgets.gateway_l, wf);
453                 widget_move(wh, y, help_x);
454                 y++;
455         }
456
457         wh = widget_label_base(screen->widgets.dns_help_l);
458         layout_pair(screen, y, screen->widgets.dns_l,
459                         widget_textbox_base(screen->widgets.dns_f));
460         widget_move(wh, y, help_x);
461         y++;
462
463         /* we show the DNS/DHCP help if we're configuring DHCP */
464         show = screen->net_conf_type != NET_CONF_TYPE_STATIC;
465         wl = widget_label_base(screen->widgets.dns_dhcp_help_l);
466         widget_set_visible(wl, show);
467         if (show) {
468                 widget_move(wl, y, screen->field_x);
469                 y += 1;
470         }
471
472         y += 1;
473
474         show = screen->cui->config->safe_mode;
475         if (show) {
476                 widget_move(widget_label_base(screen->widgets.safe_mode),
477                         y, screen->field_x);
478                 y += 1;
479         }
480
481         widget_move(widget_button_base(screen->widgets.ok_b),
482                         y, screen->field_x);
483         widget_move(widget_button_base(screen->widgets.help_b),
484                         y, screen->field_x + 10);
485         widget_move(widget_button_base(screen->widgets.cancel_b),
486                         y, screen->field_x + 23);
487 }
488
489 static void config_screen_network_change(void *arg, int value)
490 {
491         struct config_screen *screen = arg;
492         screen->net_conf_type = value;
493         widgetset_unpost(screen->widgetset);
494         config_screen_layout_widgets(screen);
495         widgetset_post(screen->widgetset);
496 }
497
498 static void config_screen_autoboot_change(void *arg, int value)
499 {
500         struct config_screen *screen = arg;
501         screen->autoboot_type = value;
502         widgetset_unpost(screen->widgetset);
503         config_screen_layout_widgets(screen);
504         widgetset_post(screen->widgetset);
505 }
506
507 static struct interface_config *first_active_interface(
508                 const struct config *config)
509 {
510         unsigned int i;
511
512         for (i = 0; i < config->network.n_interfaces; i++) {
513                 if (config->network.interfaces[i]->ignore)
514                         continue;
515                 return config->network.interfaces[i];
516         }
517         return NULL;
518 }
519
520 static enum net_conf_type find_net_conf_type(const struct config *config)
521 {
522         struct interface_config *ifcfg;
523
524         ifcfg = first_active_interface(config);
525
526         if (!ifcfg)
527                 return NET_CONF_TYPE_DHCP_ALL;
528
529         else if (ifcfg->method == CONFIG_METHOD_DHCP)
530                 return NET_CONF_TYPE_DHCP_ONE;
531
532         else if (ifcfg->method == CONFIG_METHOD_STATIC)
533                 return NET_CONF_TYPE_STATIC;
534
535         assert(0);
536         return NET_CONF_TYPE_DHCP_ALL;
537 }
538
539 static void config_screen_setup_empty(struct config_screen *screen)
540 {
541         widget_new_label(screen->widgetset, 2, screen->field_x,
542                         _("Waiting for configuration data..."));
543         screen->widgets.cancel_b = widget_new_button(screen->widgetset,
544                         4, screen->field_x, 9, _("Cancel"),
545                         cancel_click, screen);
546 }
547
548
549 static void config_screen_setup_widgets(struct config_screen *screen,
550                 const struct config *config,
551                 const struct system_info *sysinfo)
552 {
553         struct nc_widgetset *set = screen->widgetset;
554         struct interface_config *ifcfg;
555         char *str, *ip, *mask, *gw;
556         enum net_conf_type type;
557         unsigned int i;
558         bool found;
559
560         build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
561                         == N_FIELDS);
562
563         type = screen->net_conf_type;
564         ifcfg = first_active_interface(config);
565
566         screen->widgets.autoboot_l = widget_new_label(set, 0, 0,
567                                         _("Autoboot:"));
568         screen->widgets.autoboot_f = widget_new_select(set, 0, 0, 55);
569
570         widget_select_on_change(screen->widgets.autoboot_f,
571                         config_screen_autoboot_change, screen);
572
573         screen->widgets.boot_device_f = widget_new_select(set, 0, 0, 55);
574
575         widget_select_add_option(screen->widgets.autoboot_f,
576                                         AUTOBOOT_DISABLED,
577                                         _("Don't autoboot"),
578                                         screen->autoboot_type ==
579                                                 AUTOBOOT_DISABLED);
580         widget_select_add_option(screen->widgets.autoboot_f,
581                                         AUTOBOOT_ANY,
582                                         _("Autoboot from any "
583                                                 "disk/network device"),
584                                         screen->autoboot_type ==
585                                                 AUTOBOOT_ANY);
586         widget_select_add_option(screen->widgets.autoboot_f,
587                                         AUTOBOOT_ONE,
588                                         _("Only autoboot from a specific "
589                                                 "disk/network device"),
590                                         screen->autoboot_type ==
591                                                 AUTOBOOT_ONE);
592
593         found = false;
594
595         for (i = 0; i < sysinfo->n_blockdevs; i++) {
596                 struct blockdev_info *bd = sysinfo->blockdevs[i];
597                 bool selected;
598                 char *label;
599
600                 selected = config->boot_device &&
601                                 !strcmp(config->boot_device, bd->uuid);
602                 if (selected)
603                         found = true;
604
605                 label = talloc_asprintf(screen, _("disk: %s [uuid: %s]"),
606                                 bd->name, bd->uuid);
607
608                 widget_select_add_option(screen->widgets.boot_device_f, i,
609                                         label, selected);
610         }
611
612         for (i = 0; i < sysinfo->n_interfaces; i++) {
613                 struct interface_info *info = sysinfo->interfaces[i];
614                 char *label, mac[20];
615                 bool selected;
616
617                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
618                 selected = config->boot_device &&
619                                 !strcmp(config->boot_device, mac);
620                 if (selected)
621                         found = true;
622
623                 label = talloc_asprintf(screen, _("net:  %s [mac: %s]"),
624                                 info->name, mac);
625
626                 widget_select_add_option(screen->widgets.boot_device_f,
627                                                 i + sysinfo->n_blockdevs,
628                                                 label, selected);
629         }
630
631         if (screen->autoboot_type == AUTOBOOT_ONE && !found) {
632                 char *label;
633
634                 label = talloc_asprintf(screen, _("Unknown UUID: %s"),
635                                 config->boot_device);
636
637                 widget_select_add_option(screen->widgets.boot_device_f, -1,
638                                                 label, true);
639         }
640
641         str = talloc_asprintf(screen, "%d", config->autoboot_timeout_sec);
642         screen->widgets.timeout_l = widget_new_label(set, 0, 0, _("Timeout:"));
643         screen->widgets.timeout_f = widget_new_textbox(set, 0, 0, 5, str);
644         screen->widgets.timeout_help_l = widget_new_label(set, 0, 0,
645                                         _("seconds"));
646
647         widget_textbox_set_fixed_size(screen->widgets.timeout_f);
648         widget_textbox_set_validator_integer(screen->widgets.timeout_f, 0, 999);
649
650         screen->widgets.network_l = widget_new_label(set, 0, 0, _("Network:"));
651         screen->widgets.network_f = widget_new_select(set, 0, 0, 50);
652
653         widget_select_add_option(screen->widgets.network_f,
654                                         NET_CONF_TYPE_DHCP_ALL,
655                                         _("DHCP on all active interfaces"),
656                                         type == NET_CONF_TYPE_DHCP_ALL);
657         widget_select_add_option(screen->widgets.network_f,
658                                         NET_CONF_TYPE_DHCP_ONE,
659                                         _("DHCP on a specific interface"),
660                                         type == NET_CONF_TYPE_DHCP_ONE);
661         widget_select_add_option(screen->widgets.network_f,
662                                         NET_CONF_TYPE_STATIC,
663                                         _("Static IP configuration"),
664                                         type == NET_CONF_TYPE_STATIC);
665
666         widget_select_on_change(screen->widgets.network_f,
667                         config_screen_network_change, screen);
668
669         screen->widgets.iface_l = widget_new_label(set, 0, 0, _("Device:"));
670         screen->widgets.iface_f = widget_new_select(set, 0, 0, 50);
671
672         for (i = 0; i < sysinfo->n_interfaces; i++) {
673                 struct interface_info *info = sysinfo->interfaces[i];
674                 char str[50], mac[20];
675                 bool is_default;
676
677                 is_default = ifcfg && !memcmp(ifcfg->hwaddr, info->hwaddr,
678                                         sizeof(ifcfg->hwaddr));
679
680                 mac_str(info->hwaddr, info->hwaddr_size, mac, sizeof(mac));
681                 snprintf(str, sizeof(str), "%s [%s, %s]", info->name, mac,
682                                 info->link ? _("link up") : _("link down"));
683
684                 widget_select_add_option(screen->widgets.iface_f,
685                                                 i, str, is_default);
686         }
687
688         gw = ip = mask = NULL;
689         if (ifcfg && ifcfg->method == CONFIG_METHOD_STATIC) {
690                 char *sep;
691
692                 str = talloc_strdup(screen, ifcfg->static_config.address);
693                 sep = strchr(str, '/');
694                 ip = str;
695
696                 if (sep) {
697                         *sep = '\0';
698                         mask = sep + 1;
699                 }
700                 gw = ifcfg->static_config.gateway;
701         }
702
703         screen->widgets.ip_addr_l = widget_new_label(set, 0, 0, _("IP/mask:"));
704         screen->widgets.ip_addr_f = widget_new_textbox(set, 0, 0, 16, ip);
705         screen->widgets.ip_mask_l = widget_new_label(set, 0, 0, "/");
706         screen->widgets.ip_mask_f = widget_new_textbox(set, 0, 0, 3, mask);
707         screen->widgets.ip_addr_mask_help_l =
708                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.10 / 24)"));
709
710         widget_textbox_set_fixed_size(screen->widgets.ip_addr_f);
711         widget_textbox_set_fixed_size(screen->widgets.ip_mask_f);
712         widget_textbox_set_validator_ipv4(screen->widgets.ip_addr_f);
713         widget_textbox_set_validator_integer(screen->widgets.ip_mask_f, 1, 31);
714
715         screen->widgets.gateway_l = widget_new_label(set, 0, 0, _("Gateway:"));
716         screen->widgets.gateway_f = widget_new_textbox(set, 0, 0, 16, gw);
717         screen->widgets.gateway_help_l =
718                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.1)"));
719
720         widget_textbox_set_fixed_size(screen->widgets.gateway_f);
721         widget_textbox_set_validator_ipv4(screen->widgets.gateway_f);
722
723         str = talloc_strdup(screen, "");
724         for (i = 0; i < config->network.n_dns_servers; i++) {
725                 str = talloc_asprintf_append(str, "%s%s",
726                                 (i == 0) ? "" : " ",
727                                 config->network.dns_servers[i]);
728         }
729
730         screen->widgets.dns_l = widget_new_label(set, 0, 0,
731                                         _("DNS Server(s):"));
732         screen->widgets.dns_f = widget_new_textbox(set, 0, 0, 32, str);
733         screen->widgets.dns_help_l =
734                 widget_new_label(set, 0, 0, _("(eg. 192.168.0.2)"));
735
736         widget_textbox_set_validator_ipv4_multi(screen->widgets.dns_f);
737
738         screen->widgets.dns_dhcp_help_l = widget_new_label(set, 0, 0,
739                         _("(if not provided by DHCP server)"));
740
741         if (config->safe_mode)
742                 screen->widgets.safe_mode = widget_new_label(set, 0, 0,
743                          _("Selecting 'OK' will exit safe mode"));
744
745         screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, _("OK"),
746                         ok_click, screen);
747         screen->widgets.help_b = widget_new_button(set, 0, 0, 9, _("Help"),
748                         help_click, screen);
749         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 9, _("Cancel"),
750                         cancel_click, screen);
751 }
752
753 static void config_screen_widget_focus(struct nc_widget *widget, void *arg)
754 {
755         struct config_screen *screen = arg;
756         int w_y, s_max;
757
758         w_y = widget_y(widget) + widget_focus_y(widget);
759         s_max = getmaxy(screen->scr.sub_ncw) - 1;
760
761         if (w_y < screen->scroll_y)
762                 screen->scroll_y = w_y;
763
764         else if (w_y + screen->scroll_y + 1 > s_max)
765                 screen->scroll_y = 1 + w_y - s_max;
766
767         else
768                 return;
769
770         pad_refresh(screen);
771 }
772
773 static void config_screen_draw(struct config_screen *screen,
774                 const struct config *config,
775                 const struct system_info *sysinfo)
776 {
777         bool repost = false;
778         int height;
779
780         /* The size of the pad we'll need depends on the number of interfaces.
781          *
782          * We use N_FIELDS (which is quite conservative, as some fields share
783          * a line) as a base, then:
784          * - add 6 (as the network select & boot device select fields take 3
785          *   lines each),
786          * - add n_interfaces for every field in the network select field, and
787          * - add (n_blockdevs + n_interfaces) for every field in the boot device
788          *   select field
789          */
790         height = N_FIELDS + 6;
791         if (sysinfo) {
792                 height += sysinfo->n_interfaces;
793                 height += (sysinfo->n_blockdevs + sysinfo->n_interfaces);
794         }
795         if (!screen->pad || getmaxy(screen->pad) < height) {
796                 if (screen->pad)
797                         delwin(screen->pad);
798                 screen->pad = newpad(height, COLS);
799         }
800
801         if (screen->widgetset) {
802                 widgetset_unpost(screen->widgetset);
803                 talloc_free(screen->widgetset);
804                 repost = true;
805         }
806
807         screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
808                         screen->pad);
809         widgetset_set_widget_focus(screen->widgetset,
810                         config_screen_widget_focus, screen);
811
812         if (!config || !sysinfo) {
813                 config_screen_setup_empty(screen);
814         } else {
815                 screen->net_conf_type = find_net_conf_type(config);
816                 if (!config->autoboot_enabled)
817                         screen->autoboot_type = AUTOBOOT_DISABLED;
818                 else
819                         screen->autoboot_type = config->boot_device ?
820                                         AUTOBOOT_ONE : AUTOBOOT_ANY;
821
822                 config_screen_setup_widgets(screen, config, sysinfo);
823                 config_screen_layout_widgets(screen);
824         }
825
826         if (repost)
827                 widgetset_post(screen->widgetset);
828 }
829
830 void config_screen_update(struct config_screen *screen,
831                 const struct config *config,
832                 const struct system_info *sysinfo)
833 {
834         config_screen_draw(screen, config, sysinfo);
835         pad_refresh(screen);
836 }
837
838 static int config_screen_destroy(void *arg)
839 {
840         struct config_screen *screen = arg;
841         if (screen->pad)
842                 delwin(screen->pad);
843         return 0;
844 }
845
846 struct config_screen *config_screen_init(struct cui *cui,
847                 const struct config *config,
848                 const struct system_info *sysinfo,
849                 void (*on_exit)(struct cui *))
850 {
851         struct config_screen *screen;
852
853         screen = talloc_zero(cui, struct config_screen);
854         talloc_set_destructor(screen, config_screen_destroy);
855         nc_scr_init(&screen->scr, pb_config_screen_sig, 0,
856                         cui, config_screen_process_key,
857                         config_screen_post, config_screen_unpost,
858                         config_screen_resize);
859
860         screen->cui = cui;
861         screen->on_exit = on_exit;
862         screen->label_x = 2;
863         screen->field_x = 17;
864
865         screen->scr.frame.ltitle = talloc_strdup(screen,
866                         _("Petitboot System Configuration"));
867         screen->scr.frame.rtitle = NULL;
868         screen->scr.frame.help = talloc_strdup(screen,
869                         _("tab=next, shift+tab=previous, x=exit, h=help"));
870         nc_scr_frame_draw(&screen->scr);
871
872         scrollok(screen->scr.sub_ncw, true);
873
874         config_screen_draw(screen, config, sysinfo);
875
876         return screen;
877 }