summaryrefslogtreecommitdiffstats
path: root/ui/ncurses/nc-plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui/ncurses/nc-plugin.c')
-rw-r--r--ui/ncurses/nc-plugin.c418
1 files changed, 418 insertions, 0 deletions
diff --git a/ui/ncurses/nc-plugin.c b/ui/ncurses/nc-plugin.c
new file mode 100644
index 0000000..ad8210f
--- /dev/null
+++ b/ui/ncurses/nc-plugin.c
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2017 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <talloc/talloc.h>
+#include <types/types.h>
+#include <i18n/i18n.h>
+#include <log/log.h>
+
+#include "nc-cui.h"
+#include "nc-plugin.h"
+#include "nc-widgets.h"
+#include "nc-menu.h"
+#include "ui/common/discover-client.h"
+#include "process/process.h"
+#include "system/system.h"
+
+#define N_FIELDS 15
+
+extern const struct help_text plugin_help_text;
+
+struct plugin_screen {
+ struct nc_scr scr;
+ struct cui *cui;
+ struct nc_widgetset *widgetset;
+ WINDOW *pad;
+
+ bool exit;
+ bool show_help;
+ bool need_redraw;
+ void (*on_exit)(struct cui *);
+
+ int label_x;
+ int field_x;
+ int scroll_y;
+
+ const struct plugin_option *opt;
+
+ struct {
+ struct nc_widget_label *id_l;
+ struct nc_widget_label *id_f;
+ struct nc_widget_label *name_l;
+ struct nc_widget_label *name_f;
+ struct nc_widget_label *vendor_l;
+ struct nc_widget_label *vendor_f;
+ struct nc_widget_label *vendor_id_l;
+ struct nc_widget_label *vendor_id_f;
+ struct nc_widget_label *version_l;
+ struct nc_widget_label *version_f;
+ struct nc_widget_label *date_l;
+ struct nc_widget_label *date_f;
+
+ struct nc_widget_label *commands_l;
+ struct nc_widget_select *commands_f;
+
+ struct nc_widget_button *run_b;
+ } widgets;
+};
+
+static void plugin_screen_draw(struct plugin_screen *screen,
+ struct pmenu_item *item);
+
+static struct plugin_screen *plugin_screen_from_scr(struct nc_scr *scr)
+{
+ struct plugin_screen *plugin_screen;
+
+ assert(scr->sig == pb_plugin_screen_sig);
+ plugin_screen = (struct plugin_screen *)
+ ((char *)scr - (size_t)&((struct plugin_screen *)0)->scr);
+ assert(plugin_screen->scr.sig == pb_plugin_screen_sig);
+ return plugin_screen;
+}
+
+struct nc_scr *plugin_screen_scr(struct plugin_screen *screen)
+{
+ return &screen->scr;
+}
+
+static void pad_refresh(struct plugin_screen *screen)
+{
+ int y, x, rows, cols;
+
+ getmaxyx(screen->scr.sub_ncw, rows, cols);
+ getbegyx(screen->scr.sub_ncw, y, x);
+
+ prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
+}
+
+static void plugin_screen_widget_focus(struct nc_widget *widget, void *arg)
+{
+ struct plugin_screen *screen = arg;
+ int w_y, w_height, w_focus, s_max, adjust;
+
+ w_height = widget_height(widget);
+ w_focus = widget_focus_y(widget);
+ w_y = widget_y(widget) + w_focus;
+ s_max = getmaxy(screen->scr.sub_ncw) - 1;
+
+ if (w_y < screen->scroll_y)
+ screen->scroll_y = w_y;
+
+ else if (w_y + screen->scroll_y + 1 > s_max) {
+ /* Fit as much of the widget into the screen as possible */
+ adjust = min(s_max - 1, w_height - w_focus);
+ if (w_y + adjust >= screen->scroll_y + s_max)
+ screen->scroll_y = max(0, 1 + w_y + adjust - s_max);
+ } else
+ return;
+
+ pad_refresh(screen);
+}
+
+static void plugin_screen_process_key(struct nc_scr *scr, int key)
+{
+ struct plugin_screen *screen = plugin_screen_from_scr(scr);
+ bool handled;
+
+ handled = widgetset_process_key(screen->widgetset, key);
+
+ if (!handled) {
+ pb_log("Not handled by widgetset\n");
+ switch (key) {
+ case 'x':
+ case 27: /* esc */
+ screen->exit = true;
+ break;
+ case 'h':
+ screen->show_help = true;
+ break;
+ }
+ }
+
+ if (screen->exit) {
+ screen->on_exit(screen->cui);
+
+ } else if (screen->show_help) {
+ screen->show_help = false;
+ screen->need_redraw = true;
+ cui_show_help(screen->cui, _("Petitboot Plugin"),
+ &plugin_help_text);
+
+ } else if (handled) {
+ pad_refresh(screen);
+ }
+}
+
+static int plugin_screen_post(struct nc_scr *scr)
+{
+ struct plugin_screen *screen = plugin_screen_from_scr(scr);
+
+ widgetset_post(screen->widgetset);
+
+ nc_scr_frame_draw(scr);
+ if (screen->need_redraw) {
+ redrawwin(scr->main_ncw);
+ screen->need_redraw = false;
+ }
+ wrefresh(screen->scr.main_ncw);
+ pad_refresh(screen);
+ return 0;
+}
+
+static int plugin_screen_unpost(struct nc_scr *scr)
+{
+ widgetset_unpost(plugin_screen_from_scr(scr)->widgetset);
+ return 0;
+}
+
+static void plugin_screen_resize(struct nc_scr *scr)
+{
+ /* FIXME: forms can't be resized, need to recreate here */
+ plugin_screen_unpost(scr);
+ plugin_screen_post(scr);
+}
+
+static void plugin_run_command(void *arg)
+{
+ struct plugin_screen *screen = arg;
+ char *cmd;
+ int i, result;
+
+ i = widget_select_get_value(screen->widgets.commands_f);
+ /* pb-plugin copies all executables to the wrapper directory */
+ cmd = talloc_asprintf(screen, "%s/%s", "/var/lib/pb-plugins/bin",
+ basename(screen->opt->executables[i]));
+
+ if (!cmd) {
+ pb_log("nc-plugin: plugin option has missing command %d\n", i);
+ return;
+ }
+
+ const char *argv[] = {
+ pb_system_apps.pb_exec,
+ cmd,
+ NULL
+ };
+
+ /* Drop our pad before running plugin */
+ delwin(screen->pad);
+ screen->pad = NULL;
+
+ result = cui_run_cmd(screen->cui, argv);
+
+ if (result)
+ pb_log("Failed to run plugin command %s\n", cmd);
+ else
+ nc_scr_status_printf(screen->cui->current, _("Finished: %s"), cmd);
+
+ plugin_screen_draw(screen, NULL);
+
+ talloc_free(cmd);
+}
+
+/* Call pb-plugin to install a plugin specified by plugin_file */
+int plugin_install_plugin(struct pmenu_item *item)
+{
+ struct cui *cui = cui_from_item(item);
+ struct cui_opt_data *cod = cod_from_item(item);
+ int rc;
+
+ assert(cui->current == &cui->plugin_menu->scr);
+
+ nc_scr_status_printf(cui->current, _("Installing plugin %s"),
+ cod->pd->plugin_file);
+
+ rc = cui_send_plugin_install(cui, cod->pd->plugin_file);
+
+ if (rc) {
+ pb_log("cui_send_plugin_install failed!\n");
+ nc_scr_status_printf(cui->current,
+ _("Failed to send install request"));
+ } else
+ pb_debug("cui_send_plugin_install sent!\n");
+
+ return rc;
+}
+
+static void plugin_screen_setup_widgets(struct plugin_screen *screen)
+{
+ const struct plugin_option *opt = screen->opt;
+ struct nc_widgetset *set = screen->widgetset;
+ unsigned int i;
+
+ build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
+ == N_FIELDS);
+
+ screen->widgets.id_l = widget_new_label(set, 0, 0, _("ID:"));
+ screen->widgets.id_f = widget_new_label(set, 0, 0, opt->id);
+ screen->widgets.name_l = widget_new_label(set, 0, 0, _("Name:"));
+ screen->widgets.name_f = widget_new_label(set, 0, 0, opt->name);
+ screen->widgets.vendor_l = widget_new_label(set, 0, 0, _("Vendor:"));
+ screen->widgets.vendor_f = widget_new_label(set, 0, 0, opt->vendor);
+ screen->widgets.vendor_id_l = widget_new_label(set, 0, 0,
+ _("Vendor ID:"));
+ screen->widgets.vendor_id_f = widget_new_label(set, 0, 0,
+ opt->vendor_id);
+ screen->widgets.version_l = widget_new_label(set, 0, 0, _("Version:"));
+ screen->widgets.version_f = widget_new_label(set, 0, 0,
+ opt->version);
+ screen->widgets.date_l = widget_new_label(set, 0, 0, _("Date"));
+ screen->widgets.date_f = widget_new_label(set, 0, 0, opt->date);
+
+ screen->widgets.commands_l = widget_new_label(set, 0, 0,
+ _("Commands:"));
+ screen->widgets.commands_f = widget_new_select(set, 0, 0,
+ COLS - screen->field_x - 1);
+ for (i = 0; i < opt->n_executables; i++) {
+ widget_select_add_option(screen->widgets.commands_f, i,
+ basename(opt->executables[i]), i == 0);
+ }
+
+ screen->widgets.run_b = widget_new_button(set, 0, 0, 30,
+ _("Run selected command"), plugin_run_command, screen);
+}
+
+static int layout_pair(struct plugin_screen *screen, int y,
+ struct nc_widget_label *label,
+ struct nc_widget *field)
+{
+ struct nc_widget *label_w = widget_label_base(label);
+ widget_move(label_w, y, screen->label_x);
+ widget_move(field, y, screen->field_x);
+ return max(widget_height(label_w), widget_height(field));
+}
+
+static void plugin_screen_layout_widgets(struct plugin_screen *screen)
+{
+ unsigned int y;
+
+ /* list of details (static) */
+
+ y = 1;
+
+ layout_pair(screen, y++, screen->widgets.id_l,
+ widget_label_base(screen->widgets.id_f));
+ layout_pair(screen, y++, screen->widgets.name_l,
+ widget_label_base(screen->widgets.name_f));
+ layout_pair(screen, y++, screen->widgets.vendor_l,
+ widget_label_base(screen->widgets.vendor_f));
+ layout_pair(screen, y++, screen->widgets.vendor_id_l,
+ widget_label_base(screen->widgets.vendor_id_f));
+ layout_pair(screen, y++, screen->widgets.version_l,
+ widget_label_base(screen->widgets.version_f));
+ layout_pair(screen, y++, screen->widgets.date_l,
+ widget_label_base(screen->widgets.date_f));
+
+ y += 1;
+
+ /* available commands */
+ widget_move(widget_label_base(screen->widgets.commands_l), y,
+ screen->label_x);
+ widget_move(widget_select_base(screen->widgets.commands_f), y,
+ screen->field_x);
+
+ y += 2;
+
+ widget_move(widget_button_base(screen->widgets.run_b), y++, screen->field_x);
+
+}
+
+static void plugin_screen_draw(struct plugin_screen *screen,
+ struct pmenu_item *item)
+{
+ struct cui_opt_data *cod;
+ int height = N_FIELDS * 2;
+ bool repost = false;
+
+ if (item) {
+ /* First init or update */
+ cod = cod_from_item(item);
+ screen->opt = cod->pd->opt;
+ }
+
+ if (!screen->pad || getmaxy(screen->pad) < height) {
+ if (screen->pad)
+ delwin(screen->pad);
+ screen->pad = newpad(height, COLS);
+ }
+
+ if (screen->widgetset) {
+ widgetset_unpost(screen->widgetset);
+ talloc_free(screen->widgetset);
+ repost = true;
+ }
+
+ screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
+ screen->pad);
+ widgetset_set_widget_focus(screen->widgetset,
+ plugin_screen_widget_focus, screen);
+
+ plugin_screen_setup_widgets(screen);
+ plugin_screen_layout_widgets(screen);
+
+ if (repost)
+ widgetset_post(screen->widgetset);
+}
+
+static int plugin_screen_destroy(void *arg)
+{
+ struct plugin_screen *screen = arg;
+ if (screen->pad)
+ delwin(screen->pad);
+ return 0;
+}
+
+struct plugin_screen *plugin_screen_init(struct cui *cui,
+ struct pmenu_item *item,
+ void (*on_exit)(struct cui *))
+{
+ struct plugin_screen *screen = talloc_zero(cui, struct plugin_screen);
+ talloc_set_destructor(screen, plugin_screen_destroy);
+
+ nc_scr_init(&screen->scr, pb_plugin_screen_sig, 0,
+ cui, plugin_screen_process_key,
+ plugin_screen_post, plugin_screen_unpost,
+ plugin_screen_resize);
+
+
+ screen->cui = cui;
+ screen->on_exit = on_exit;
+ screen->label_x = 2;
+ screen->field_x = 25;
+
+ screen->scr.frame.ltitle = talloc_strdup(screen,
+ _("Petitboot Plugin"));
+ screen->scr.frame.rtitle = NULL;
+ screen->scr.frame.help = talloc_strdup(screen,
+ _("tab=next, shift+tab=previous, x=exit, h=help"));
+ nc_scr_frame_draw(&screen->scr);
+
+ scrollok(screen->scr.sub_ncw, true);
+
+ plugin_screen_draw(screen, item);
+
+ return screen;
+}
+
OpenPOWER on IntegriCloud