+ while (i < cui->plugin_menu->item_count) {
+ item = item_userptr(cui->plugin_menu->items[i]);
+ if (!item || !item->data) {
+ i++;
+ continue;
+ }
+ cod = cod_from_item(item);
+ if (!cod->opt && !cod->dev) {
+ i++;
+ continue;
+ }
+
+ pmenu_remove(cui->plugin_menu, item);
+ /* plugin_menu entries will shift, jump to bottom to make sure
+ * we remove all plugin option items */
+ i = 0;
+ }
+
+ /* Re-attach the items array. */
+ set_menu_items(cui->plugin_menu->ncm, cui->plugin_menu->items);
+
+ set_menu_items(cui->main->ncm, NULL);
+ for (i = 0; i < cui->main->item_count; i++) {
+ item = item_userptr(cui->main->items[i]);
+ if (item->on_execute != menu_plugin_execute)
+ continue;
+ cui->n_plugins = 0;
+ pmenu_item_update(item, _("Plugins (0)"));
+ break;
+ }
+
+ set_menu_items(cui->main->ncm, cui->main->items);
+
+ if (cui->current == &cui->main->scr)
+ nc_scr_post(cui->current);
+
+ /* If we're currently in a plugin screen jump back to the plugin menu */
+ if (cui->plugin_screen &&
+ cui->current == plugin_screen_scr(cui->plugin_screen))
+ cui_plugin_exit(cui);
+
+ return 0;
+}
+
+static void cui_update_mm_title(struct cui *cui)
+{
+ struct nc_frame *frame = &cui->main->scr.frame;
+
+ talloc_free(frame->rtitle);
+
+ frame->rtitle = talloc_strdup(cui->main, cui->sysinfo->type);
+ if (cui->sysinfo->identifier)
+ frame->rtitle = talloc_asprintf_append(frame->rtitle,
+ " %s", cui->sysinfo->identifier);
+
+ if (cui->current == &cui->main->scr)
+ nc_scr_post(cui->current);
+
+ frame = &cui->plugin_menu->scr.frame;
+
+ talloc_free(frame->rtitle);
+
+ frame->rtitle = talloc_strdup(cui->main, cui->sysinfo->type);
+ if (cui->sysinfo->identifier)
+ frame->rtitle = talloc_asprintf_append(frame->rtitle,
+ " %s", cui->sysinfo->identifier);
+
+ if (cui->current == &cui->main->scr)
+ nc_scr_post(cui->current);
+}
+
+static void cui_update_sysinfo(struct system_info *sysinfo, void *arg)
+{
+ struct cui *cui = cui_from_arg(arg);
+ cui->sysinfo = talloc_steal(cui, sysinfo);
+
+ /* if we're currently displaying the system info screen, inform it
+ * of the updated information. */
+ if (cui->sysinfo_screen)
+ sysinfo_screen_update(cui->sysinfo_screen, sysinfo);
+
+ if (cui->subset_screen)
+ subset_screen_update(cui->subset_screen);
+
+ /* ... and do the same with the config screen... */
+ if (cui->config_screen)
+ config_screen_update(cui->config_screen, cui->config, sysinfo);
+
+ /* ... and the boot editor. */
+ if (cui->boot_editor)
+ boot_editor_update(cui->boot_editor, sysinfo);
+
+ cui_update_mm_title(cui);
+}
+
+void cui_update_language(struct cui *cui, const char *lang)
+{
+ bool repost_menu;
+ char *cur_lang;
+
+ cur_lang = setlocale(LC_ALL, NULL);
+ if (cur_lang && !strcmp(cur_lang, lang))
+ return;
+
+ setlocale(LC_ALL, lang);
+
+ /* we'll need to update the menu: drop all items and repopulate */
+ repost_menu = cui->current == &cui->main->scr ||
+ cui->current == &cui->plugin_menu->scr;
+ if (repost_menu)
+ nc_scr_unpost(cui->current);
+
+ talloc_free(cui->main);
+ cui->main = main_menu_init(cui);
+ cui->plugin_menu = plugin_menu_init(cui);
+
+ if (repost_menu) {
+ cui->current = &cui->main->scr;
+ nc_scr_post(cui->current);
+ }
+
+ discover_client_enumerate(cui->client);
+}
+
+static void cui_update_config(struct config *config, void *arg)
+{
+ struct cui *cui = cui_from_arg(arg);
+ cui->config = talloc_steal(cui, config);
+
+ if (config->lang)
+ cui_update_language(cui, config->lang);
+
+ if (cui->subset_screen)
+ subset_screen_update(cui->subset_screen);
+
+ if (cui->config_screen)
+ config_screen_update(cui->config_screen, config, cui->sysinfo);
+
+ if (config->safe_mode)
+ nc_scr_status_printf(cui->current,
+ _("SAFE MODE: select '%s' to continue"),
+ _("Rescan devices"));
+}
+
+int cui_send_config(struct cui *cui, struct config *config)
+{
+ return discover_client_send_config(cui->client, config);
+}
+
+int cui_send_url(struct cui *cui, char * url)
+{
+ return discover_client_send_url(cui->client, url);
+}
+
+int cui_send_plugin_install(struct cui *cui, char *file)
+{
+ return discover_client_send_plugin_install(cui->client, file);
+}
+
+int cui_send_authenticate(struct cui *cui, char *password)
+{
+ return discover_client_send_authenticate(cui->client, password);
+}
+
+int cui_send_set_password(struct cui *cui, char *password, char *new_password)
+{
+ return discover_client_send_set_password(cui->client, password,
+ new_password);
+}
+
+void cui_send_reinit(struct cui *cui)
+{
+ discover_client_send_reinit(cui->client);
+}
+
+/**
+ * pb_mm_init - Setup the main menu instance.
+ */
+static struct pmenu *main_menu_init(struct cui *cui)
+{
+ struct pmenu_item *i;
+ struct pmenu *m;
+ int result;
+ bool lockdown = lockdown_active();
+
+ m = pmenu_init(cui, 9, lockdown ? cui_abort_on_exit : cui_on_exit);
+ if (!m) {
+ pb_log_fn("failed\n");
+ return NULL;
+ }
+
+ m->n_hot_keys = 1;
+ m->hot_keys = talloc_array(m, hot_key_fn, m->n_hot_keys);
+ if (!m->hot_keys) {
+ pb_log_fn("failed to allocate hot_keys\n");
+ talloc_free(m);
+ return NULL;
+ }
+ m->hot_keys[0] = pmenu_main_hot_keys;
+ m->on_new = cui_item_new;
+
+ m->scr.frame.ltitle = talloc_asprintf(m,
+ "Petitboot (" PACKAGE_VERSION ")");
+ m->scr.frame.rtitle = NULL;
+ m->scr.frame.help = talloc_strdup(m,
+ _("Enter=accept, e=edit, n=new, x=exit, l=language, g=log, h=help"));
+ m->scr.frame.status = talloc_strdup(m, _("Welcome to Petitboot"));
+
+ /* add a separator */
+ i = pmenu_item_create(m, " ");
+ item_opts_off(i->nci, O_SELECTABLE);
+ pmenu_item_insert(m, i, 0);
+
+ /* add system items */
+ i = pmenu_item_create(m, _("System information"));
+ i->on_execute = menu_sysinfo_execute;
+ pmenu_item_insert(m, i, 1);
+
+ i = pmenu_item_create(m, _("System configuration"));
+ i->on_execute = menu_config_execute;
+ pmenu_item_insert(m, i, 2);
+
+ i = pmenu_item_create(m, _("System status log"));
+ i->on_execute = menu_statuslog_execute;
+ pmenu_item_insert(m, i, 3);
+
+ /* this label isn't translated, so we don't want a gettext() here */
+ i = pmenu_item_create(m, "Language");
+ i->on_execute = menu_lang_execute;
+ pmenu_item_insert(m, i, 4);
+
+ i = pmenu_item_create(m, _("Rescan devices"));
+ i->on_execute = menu_reinit_execute;
+ pmenu_item_insert(m, i, 5);
+
+ i = pmenu_item_create(m, _("Retrieve config from URL"));
+ i->on_execute = menu_add_url_execute;
+ pmenu_item_insert(m, i, 6);
+
+ i = pmenu_item_create(m, _("Plugins (0)"));
+ i->on_execute = menu_plugin_execute;
+ pmenu_item_insert(m, i, 7);
+
+ if (lockdown)
+ i = pmenu_item_create(m, _("Reboot"));
+ else
+ i = pmenu_item_create(m, _("Exit to shell"));
+ i->on_execute = pmenu_exit_cb;
+ pmenu_item_insert(m, i, 8);
+
+ result = pmenu_setup(m);
+
+ if (result) {
+ pb_log("%s:%d: pmenu_setup failed: %s\n", __func__, __LINE__,
+ strerror(errno));
+ goto fail_setup;
+ }
+
+ m->help_title = _("main menu");
+ m->help_text = &main_menu_help_text;
+
+ menu_opts_off(m->ncm, O_SHOWDESC);
+ set_menu_mark(m->ncm, " *");
+ set_current_item(m->ncm, i->nci);
+
+ return m;
+
+fail_setup:
+ talloc_free(m);
+ return NULL;
+}
+
+/*
+ * plugin_menu_init: Set up the plugin menu instance
+ */
+static struct pmenu *plugin_menu_init(struct cui *cui)
+{
+ struct pmenu_item *i;
+ struct pmenu *m;
+ int result;
+
+ m = pmenu_init(cui, 2, cui_plugin_menu_exit);
+ m->scr.frame.ltitle = talloc_asprintf(m, _("Petitboot Plugins"));
+ m->scr.frame.rtitle = talloc_asprintf(m, "%s", "");
+ m->scr.frame.help = talloc_strdup(m,
+ _("Enter=install, e=details, x=exit, h=help"));
+ m->scr.frame.status = talloc_asprintf(m,
+ _("Available Petitboot Plugins"));
+
+ /* add a separator */
+ i = pmenu_item_create(m, " ");
+ item_opts_off(i->nci, O_SELECTABLE);
+ pmenu_item_insert(m, i, 0);
+
+ i = pmenu_item_create(m, _("Return to Main Menu"));
+ i->on_execute = pmenu_exit_cb;
+ pmenu_item_insert(m, i, 1);
+
+ result = pmenu_setup(m);
+
+ if (result) {
+ pb_log("%s:%d: pmenu_setup failed: %s\n", __func__, __LINE__,
+ strerror(errno));
+ goto fail_setup;
+ }
+
+ m->help_title = _("plugin menu");
+ m->help_text = &plugin_menu_help_text;
+
+ return m;
+
+fail_setup:
+ talloc_free(m);
+ return NULL;