2 * Copyright (C) 2017 IBM Corporation
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.
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.
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
18 #if defined(HAVE_CONFIG_H)
26 #include <talloc/talloc.h>
27 #include <types/types.h>
28 #include <i18n/i18n.h>
32 #include "nc-plugin.h"
33 #include "nc-widgets.h"
35 #include "ui/common/discover-client.h"
36 #include "process/process.h"
37 #include "system/system.h"
41 extern const struct help_text plugin_help_text;
43 struct plugin_screen {
46 struct nc_widgetset *widgetset;
52 void (*on_exit)(struct cui *);
58 const struct plugin_option *opt;
61 struct nc_widget_label *id_l;
62 struct nc_widget_label *id_f;
63 struct nc_widget_label *name_l;
64 struct nc_widget_label *name_f;
65 struct nc_widget_label *vendor_l;
66 struct nc_widget_label *vendor_f;
67 struct nc_widget_label *vendor_id_l;
68 struct nc_widget_label *vendor_id_f;
69 struct nc_widget_label *version_l;
70 struct nc_widget_label *version_f;
71 struct nc_widget_label *date_l;
72 struct nc_widget_label *date_f;
74 struct nc_widget_label *commands_l;
75 struct nc_widget_select *commands_f;
77 struct nc_widget_button *run_b;
81 static void plugin_screen_draw(struct plugin_screen *screen,
82 struct pmenu_item *item);
84 static struct plugin_screen *plugin_screen_from_scr(struct nc_scr *scr)
86 struct plugin_screen *plugin_screen;
88 assert(scr->sig == pb_plugin_screen_sig);
89 plugin_screen = (struct plugin_screen *)
90 ((char *)scr - (size_t)&((struct plugin_screen *)0)->scr);
91 assert(plugin_screen->scr.sig == pb_plugin_screen_sig);
95 struct nc_scr *plugin_screen_scr(struct plugin_screen *screen)
100 static void pad_refresh(struct plugin_screen *screen)
102 int y, x, rows, cols;
104 getmaxyx(screen->scr.sub_ncw, rows, cols);
105 getbegyx(screen->scr.sub_ncw, y, x);
107 prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
110 static void plugin_screen_widget_focus(struct nc_widget *widget, void *arg)
112 struct plugin_screen *screen = arg;
113 int w_y, w_height, w_focus, s_max, adjust;
115 w_height = widget_height(widget);
116 w_focus = widget_focus_y(widget);
117 w_y = widget_y(widget) + w_focus;
118 s_max = getmaxy(screen->scr.sub_ncw) - 1;
120 if (w_y < screen->scroll_y)
121 screen->scroll_y = w_y;
123 else if (w_y + screen->scroll_y + 1 > s_max) {
124 /* Fit as much of the widget into the screen as possible */
125 adjust = min(s_max - 1, w_height - w_focus);
126 if (w_y + adjust >= screen->scroll_y + s_max)
127 screen->scroll_y = max(0, 1 + w_y + adjust - s_max);
134 static void plugin_screen_process_key(struct nc_scr *scr, int key)
136 struct plugin_screen *screen = plugin_screen_from_scr(scr);
139 handled = widgetset_process_key(screen->widgetset, key);
142 pb_log("Not handled by widgetset\n");
149 screen->show_help = true;
155 screen->on_exit(screen->cui);
157 } else if (screen->show_help) {
158 screen->show_help = false;
159 screen->need_redraw = true;
160 cui_show_help(screen->cui, _("Petitboot Plugin"),
163 } else if (handled) {
168 static int plugin_screen_post(struct nc_scr *scr)
170 struct plugin_screen *screen = plugin_screen_from_scr(scr);
172 widgetset_post(screen->widgetset);
174 nc_scr_frame_draw(scr);
175 if (screen->need_redraw) {
176 redrawwin(scr->main_ncw);
177 screen->need_redraw = false;
179 wrefresh(screen->scr.main_ncw);
184 static int plugin_screen_unpost(struct nc_scr *scr)
186 widgetset_unpost(plugin_screen_from_scr(scr)->widgetset);
190 static void plugin_screen_resize(struct nc_scr *scr)
192 /* FIXME: forms can't be resized, need to recreate here */
193 plugin_screen_unpost(scr);
194 plugin_screen_post(scr);
197 static void plugin_run_command(void *arg)
199 struct plugin_screen *screen = arg;
203 i = widget_select_get_value(screen->widgets.commands_f);
204 /* pb-plugin copies all executables to the wrapper directory */
205 cmd = talloc_asprintf(screen, "%s/%s", "/var/lib/pb-plugins/bin",
206 basename(screen->opt->executables[i]));
209 pb_log("nc-plugin: plugin option has missing command %d\n", i);
213 const char *argv[] = {
214 pb_system_apps.pb_exec,
219 /* Drop our pad before running plugin */
223 result = cui_run_cmd(screen->cui, argv);
226 pb_log("Failed to run plugin command %s\n", cmd);
228 nc_scr_status_printf(screen->cui->current, _("Finished: %s"), cmd);
230 plugin_screen_draw(screen, NULL);
235 /* Call pb-plugin to install a plugin specified by plugin_file */
236 int plugin_install_plugin(struct pmenu_item *item)
238 struct cui *cui = cui_from_item(item);
239 struct cui_opt_data *cod = cod_from_item(item);
242 assert(cui->current == &cui->plugin_menu->scr);
244 nc_scr_status_printf(cui->current, _("Installing plugin %s"),
245 cod->pd->plugin_file);
247 rc = cui_send_plugin_install(cui, cod->pd->plugin_file);
250 pb_log("cui_send_plugin_install failed!\n");
251 nc_scr_status_printf(cui->current,
252 _("Failed to send install request"));
254 pb_debug("cui_send_plugin_install sent!\n");
259 static void plugin_screen_setup_widgets(struct plugin_screen *screen)
261 const struct plugin_option *opt = screen->opt;
262 struct nc_widgetset *set = screen->widgetset;
265 build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
268 screen->widgets.id_l = widget_new_label(set, 0, 0, _("ID:"));
269 screen->widgets.id_f = widget_new_label(set, 0, 0, opt->id);
270 screen->widgets.name_l = widget_new_label(set, 0, 0, _("Name:"));
271 screen->widgets.name_f = widget_new_label(set, 0, 0, opt->name);
272 screen->widgets.vendor_l = widget_new_label(set, 0, 0, _("Vendor:"));
273 screen->widgets.vendor_f = widget_new_label(set, 0, 0, opt->vendor);
274 screen->widgets.vendor_id_l = widget_new_label(set, 0, 0,
276 screen->widgets.vendor_id_f = widget_new_label(set, 0, 0,
278 screen->widgets.version_l = widget_new_label(set, 0, 0, _("Version:"));
279 screen->widgets.version_f = widget_new_label(set, 0, 0,
281 screen->widgets.date_l = widget_new_label(set, 0, 0, _("Date"));
282 screen->widgets.date_f = widget_new_label(set, 0, 0, opt->date);
284 screen->widgets.commands_l = widget_new_label(set, 0, 0,
286 screen->widgets.commands_f = widget_new_select(set, 0, 0,
287 COLS - screen->field_x - 1);
288 for (i = 0; i < opt->n_executables; i++) {
289 widget_select_add_option(screen->widgets.commands_f, i,
290 basename(opt->executables[i]), i == 0);
293 screen->widgets.run_b = widget_new_button(set, 0, 0, 30,
294 _("Run selected command"), plugin_run_command, screen);
297 static int layout_pair(struct plugin_screen *screen, int y,
298 struct nc_widget_label *label,
299 struct nc_widget *field)
301 struct nc_widget *label_w = widget_label_base(label);
302 widget_move(label_w, y, screen->label_x);
303 widget_move(field, y, screen->field_x);
304 return max(widget_height(label_w), widget_height(field));
307 static void plugin_screen_layout_widgets(struct plugin_screen *screen)
311 /* list of details (static) */
315 layout_pair(screen, y++, screen->widgets.id_l,
316 widget_label_base(screen->widgets.id_f));
317 layout_pair(screen, y++, screen->widgets.name_l,
318 widget_label_base(screen->widgets.name_f));
319 layout_pair(screen, y++, screen->widgets.vendor_l,
320 widget_label_base(screen->widgets.vendor_f));
321 layout_pair(screen, y++, screen->widgets.vendor_id_l,
322 widget_label_base(screen->widgets.vendor_id_f));
323 layout_pair(screen, y++, screen->widgets.version_l,
324 widget_label_base(screen->widgets.version_f));
325 layout_pair(screen, y++, screen->widgets.date_l,
326 widget_label_base(screen->widgets.date_f));
330 /* available commands */
331 widget_move(widget_label_base(screen->widgets.commands_l), y,
333 widget_move(widget_select_base(screen->widgets.commands_f), y,
338 widget_move(widget_button_base(screen->widgets.run_b), y++, screen->field_x);
342 static void plugin_screen_draw(struct plugin_screen *screen,
343 struct pmenu_item *item)
345 struct cui_opt_data *cod;
346 int height = N_FIELDS * 2;
350 /* First init or update */
351 cod = cod_from_item(item);
352 screen->opt = cod->pd->opt;
355 if (!screen->pad || getmaxy(screen->pad) < height) {
358 screen->pad = newpad(height, COLS);
361 if (screen->widgetset) {
362 widgetset_unpost(screen->widgetset);
363 talloc_free(screen->widgetset);
367 screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
369 widgetset_set_widget_focus(screen->widgetset,
370 plugin_screen_widget_focus, screen);
372 plugin_screen_setup_widgets(screen);
373 plugin_screen_layout_widgets(screen);
376 widgetset_post(screen->widgetset);
379 static int plugin_screen_destroy(void *arg)
381 struct plugin_screen *screen = arg;
387 struct plugin_screen *plugin_screen_init(struct cui *cui,
388 struct pmenu_item *item,
389 void (*on_exit)(struct cui *))
391 struct plugin_screen *screen = talloc_zero(cui, struct plugin_screen);
392 talloc_set_destructor(screen, plugin_screen_destroy);
394 nc_scr_init(&screen->scr, pb_plugin_screen_sig, 0,
395 cui, plugin_screen_process_key,
396 plugin_screen_post, plugin_screen_unpost,
397 plugin_screen_resize);
401 screen->on_exit = on_exit;
403 screen->field_x = 25;
405 screen->scr.frame.ltitle = talloc_strdup(screen,
406 _("Petitboot Plugin"));
407 screen->scr.frame.rtitle = NULL;
408 screen->scr.frame.help = talloc_strdup(screen,
409 _("tab=next, shift+tab=previous, x=exit, h=help"));
410 nc_scr_frame_draw(&screen->scr);
412 scrollok(screen->scr.sub_ncw, true);
414 plugin_screen_draw(screen, item);