+ _("Failed to send install request"));
+ } else {
+ nc_scr_status_printf(cui->current, _("Installing plugin %s"),
+ cod->pd->plugin_file);
+ pb_debug("cui_send_plugin_install sent!\n");
+ }
+
+ return rc;
+}
+
+static void cui_plugin_install_cb(struct nc_scr *scr)
+{
+ struct pmenu *menu = pmenu_from_scr(scr);
+
+ if (pmenu_find_selected(menu))
+ cui_install_plugin(pmenu_find_selected(menu));
+ else
+ pb_debug("%s: no current item\n", __func__);
+}
+
+static int cui_plugin_install_check(struct pmenu_item *item)
+{
+ struct cui *cui = cui_from_item(item);
+
+ if (discover_client_authenticated(cui->client))
+ return cui_install_plugin(item);
+
+ cui_show_auth(cui, item->pmenu->scr.main_ncw, false,
+ cui_plugin_install_cb);
+
+ return 0;
+}
+
+static void cui_sysinfo_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->main->scr);
+ talloc_free(cui->sysinfo_screen);
+ cui->sysinfo_screen = NULL;
+}
+
+void cui_show_sysinfo(struct cui *cui)
+{
+ cui->sysinfo_screen = sysinfo_screen_init(cui, cui->sysinfo,
+ cui_sysinfo_exit);
+ cui_set_current(cui, sysinfo_screen_scr(cui->sysinfo_screen));
+}
+
+static void cui_config_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->main->scr);
+ talloc_free(cui->config_screen);
+ cui->config_screen = NULL;
+}
+
+void cui_show_config(struct cui *cui)
+{
+ cui->config_screen = config_screen_init(cui, cui->config,
+ cui->sysinfo, cui_config_exit);
+ cui_set_current(cui, config_screen_scr(cui->config_screen));
+}
+
+static void cui_lang_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->main->scr);
+ talloc_free(cui->lang_screen);
+ cui->lang_screen = NULL;
+}
+
+void cui_show_lang(struct cui *cui)
+{
+ cui->lang_screen = lang_screen_init(cui, cui->config, cui_lang_exit);
+ cui_set_current(cui, lang_screen_scr(cui->lang_screen));
+}
+
+static void cui_statuslog_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->main->scr);
+ talloc_free(cui->statuslog_screen);
+ cui->statuslog_screen = NULL;
+}
+
+void cui_show_statuslog(struct cui *cui)
+{
+ cui->statuslog_screen = statuslog_screen_init(cui, cui_statuslog_exit);
+ cui_set_current(cui, statuslog_screen_scr(cui->statuslog_screen));
+}
+
+static void cui_add_url_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->main->scr);
+ talloc_free(cui->add_url_screen);
+ cui->add_url_screen = NULL;
+}
+
+static void cui_plugin_exit(struct cui *cui)
+{
+ cui_set_current(cui, &cui->plugin_menu->scr);
+ talloc_free(cui->plugin_screen);
+ cui->plugin_screen = NULL;
+}
+
+static void cui_plugin_menu_exit(struct pmenu *menu)
+{
+ struct cui *cui = cui_from_pmenu(menu);
+ cui_set_current(cui, &cui->main->scr);
+}
+
+void cui_show_add_url(struct cui *cui)
+{
+ cui->add_url_screen = add_url_screen_init(cui, cui_add_url_exit);
+ cui_set_current(cui, add_url_screen_scr(cui->add_url_screen));
+}
+
+void cui_show_plugin_menu(struct cui *cui)
+{
+ cui_set_current(cui, &cui->plugin_menu->scr);
+}
+
+void cui_show_plugin(struct pmenu_item *item)
+{
+ struct cui *cui = cui_from_item(item);
+ cui->plugin_screen = plugin_screen_init(cui, item, cui_plugin_exit);
+ cui_set_current(cui, plugin_screen_scr(cui->plugin_screen));
+}
+
+static void cui_help_exit(struct cui *cui)
+{
+ cui_set_current(cui, help_screen_return_scr(cui->help_screen));
+ talloc_free(cui->help_screen);
+ cui->help_screen = NULL;
+}
+
+void cui_show_help(struct cui *cui, const char *title,
+ const struct help_text *text)
+{
+ if (!cui->current)
+ return;
+
+ if (cui->help_screen)
+ return;
+
+ cui->help_screen = help_screen_init(cui, cui->current,
+ title, text, cui_help_exit);
+
+ if (cui->help_screen)
+ cui_set_current(cui, help_screen_scr(cui->help_screen));
+}
+
+static void cui_subset_exit(struct cui *cui)
+{
+ cui_set_current(cui, subset_screen_return_scr(cui->subset_screen));
+ talloc_free(cui->subset_screen);
+ cui->subset_screen = NULL;
+}
+
+void cui_show_subset(struct cui *cui, const char *title,
+ void *arg)
+{
+ if (!cui->current)
+ return;
+
+ if (cui->subset_screen)
+ return;
+
+ cui->subset_screen = subset_screen_init(cui, cui->current,
+ title, arg, cui_subset_exit);
+
+ if (cui->subset_screen)
+ cui_set_current(cui, subset_screen_scr(cui->subset_screen));
+}
+
+static void cui_auth_exit(struct cui *cui)
+{
+ struct nc_scr *return_scr = auth_screen_return_scr(cui->auth_screen);
+
+ /*
+ * Destroy the auth screen first so that the subwindow is cleaned up
+ * before the return_scr posts. If we don't do this operations on the
+ * main_ncw can cause a blank screen at first (eg. status update).
+ */
+ nc_scr_unpost(cui->current);
+ talloc_free(cui->auth_screen);
+ cui->auth_screen = NULL;
+
+ cui->current = return_scr;
+ nc_scr_post(cui->current);
+}
+
+void cui_show_auth(struct cui *cui, WINDOW *parent, bool set_password,
+ void (*callback)(struct nc_scr *))
+{
+ if (!cui->current)
+ return;
+
+ if (cui->auth_screen)
+ return;
+
+ cui->auth_screen = auth_screen_init(cui, parent, set_password,
+ callback, cui_auth_exit);
+
+ if (cui->auth_screen)
+ cui_set_current(cui, auth_screen_scr(cui->auth_screen));
+}
+
+/**
+ * cui_set_current - Set the currently active screen and redraw it.
+ */
+
+struct nc_scr *cui_set_current(struct cui *cui, struct nc_scr *scr)
+{
+ struct nc_scr *old;
+
+ DBGS("%p -> %p\n", cui->current, scr);
+
+ assert(cui->current != scr);
+
+ old = cui->current;
+ nc_scr_unpost(old);
+
+ cui->current = scr;
+
+ nc_scr_post(cui->current);
+
+ return old;
+}
+
+static bool set_temp_autoboot_opt(struct cui *cui, struct autoboot_option *opt)
+{
+ cui->autoboot_opt = opt;
+ if (cui->client)
+ discover_client_send_temp_autoboot(cui->client, opt);
+
+ return true;
+}
+
+static bool key_cancels_boot(int key)
+{
+ unsigned int i;
+
+ if (key == 0xc)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(autoboot_override_keys); i++)
+ if (key == autoboot_override_keys[i].key)
+ return false;
+
+ return true;
+}
+
+static bool process_global_keys(struct cui *cui, int key)
+{
+ unsigned int i;
+
+ switch (key) {
+ case 0xc:
+ if (cui->current && cui->current->main_ncw)
+ wrefresh(curscr);
+ return true;
+ }
+
+ /* check for autoboot override keys */
+ for (i = 0; i < ARRAY_SIZE(autoboot_override_keys); i++) {
+ if (key != autoboot_override_keys[i].key)
+ continue;
+
+ pb_log("Sending temporary autoboot override\n");
+ set_temp_autoboot_opt(cui, &autoboot_override_keys[i].opt);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * cui_process_key - Process input on stdin.
+ */
+
+static int cui_process_key(void *arg)
+{
+ struct cui *cui = cui_from_arg(arg);
+ unsigned int i;
+ char *sequence;
+ int grab;
+
+ assert(cui->current);
+
+ for (;;) {
+ int c = getch();
+
+ pb_debug("%s: got key %d\n", __func__, c);
+
+ if (c == ERR)
+ break;
+
+ if (c == 27) {
+ /*
+ * If this is a console code sequence try to parse it
+ * and don't treat this as a key press.
+ */
+ grab = getch();
+ if (grab != ERR && grab != 27) {
+ ungetch(grab);
+ pb_debug("%s: Caught unhandled command sequence\n",
+ __func__);
+ sequence = handle_control_sequence(cui, c);
+ pb_debug("Caught sequence ");
+ if (sequence) {
+ pb_debug("(%zu): ", strlen(sequence));
+ for (i = 0; i < strlen(sequence); i++)
+ pb_debug("0%o ", sequence[i]);
+ pb_debug("\n");
+ } else
+ pb_debug("(0): (none)\n");
+ continue;
+ }
+ }
+
+ if (cui->preboot_mode) {
+ /* Turn curses options back on if the user interacts */
+ cui->preboot_mode = false;
+ cui_set_curses_options(true);
+ }
+
+ if (!cui->has_input && key_cancels_boot(c)) {
+ cui->has_input = true;
+ if (cui->client) {
+ pb_log("UI input received (key = %d), aborting "
+ "default boot\n", c);
+ discover_client_cancel_default(cui->client);
+ } else {
+ pb_log("UI input received (key = %d), aborting "
+ "once server connects\n", c);
+ }
+ }
+
+ if (process_global_keys(cui, c))
+ continue;
+
+ cui->current->process_key(cui->current, c);