ui/ncurses: Add nc-auth and authenticate when required.
[petitboot] / ui / ncurses / nc-add-url.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 <talloc/talloc.h>
27 #include <types/types.h>
28 #include <i18n/i18n.h>
29 #include <log/log.h>
30
31 #include "ui/common/discover-client.h"
32 #include "nc-cui.h"
33 #include "nc-add-url.h"
34 #include "nc-widgets.h"
35
36 #define N_FIELDS        5
37
38 extern const struct help_text add_url_help_text;
39
40 struct add_url_screen {
41         struct nc_scr           scr;
42         struct cui              *cui;
43         struct nc_widgetset     *widgetset;
44         WINDOW                  *pad;
45
46         bool                    exit;
47         bool                    show_help;
48         bool                    need_redraw;
49         void                    (*on_exit)(struct cui *);
50
51         int                     scroll_y;
52
53         int                     label_x;
54         int                     field_x;
55
56         struct {
57                 struct nc_widget_textbox        *url_f;
58                 struct nc_widget_label          *url_l;
59
60                 struct nc_widget_button         *ok_b;
61                 struct nc_widget_button         *help_b;
62                 struct nc_widget_button         *cancel_b;
63         } widgets;
64 };
65
66 static struct add_url_screen *add_url_screen_from_scr(struct nc_scr *scr)
67 {
68         struct add_url_screen *add_url_screen;
69
70         assert(scr->sig == pb_add_url_screen_sig);
71         add_url_screen = (struct add_url_screen *)
72                 ((char *)scr - (size_t)&((struct add_url_screen *)0)->scr);
73         assert(add_url_screen->scr.sig == pb_add_url_screen_sig);
74         return add_url_screen;
75 }
76
77 static void pad_refresh(struct add_url_screen *screen)
78 {
79         int y, x, rows, cols;
80
81         getmaxyx(screen->scr.sub_ncw, rows, cols);
82         getbegyx(screen->scr.sub_ncw, y, x);
83
84         prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
85 }
86
87 static void add_url_screen_process_key(struct nc_scr *scr, int key)
88 {
89         struct add_url_screen *screen = add_url_screen_from_scr(scr);
90         bool handled;
91
92         handled = widgetset_process_key(screen->widgetset, key);
93
94         if (!handled) {
95                 switch (key) {
96                 case 'x':
97                 case 27: /* esc */
98                         screen->exit = true;
99                         break;
100                 case 'h':
101                         screen->show_help = true;
102                         break;
103                 }
104         }
105
106         if (screen->exit) {
107                 screen->on_exit(screen->cui);
108
109         } else if (screen->show_help) {
110                 screen->show_help = false;
111                 screen->need_redraw = true;
112                 cui_show_help(screen->cui, _("Retrieve Config"),
113                         &add_url_help_text);
114
115         } else if (handled && (screen->cui->current == scr)) {
116                 pad_refresh(screen);
117         }
118 }
119
120 static int screen_process_form(struct add_url_screen *screen)
121 {
122         char *url;
123         int rc;
124
125         url = widget_textbox_get_value(screen->widgets.url_f);
126         if (!url || !strlen(url))
127                 return 0;
128
129         /* Once we have all the info we need, tell the server */
130         rc = cui_send_url(screen->cui, url);
131
132         if (rc)
133                 pb_log("cui_send_retreive failed!\n");
134         else
135                 pb_debug("add_url url sent!\n");
136         return 0;
137 }
138
139 static int add_url_screen_post(struct nc_scr *scr)
140 {
141         struct add_url_screen *screen = add_url_screen_from_scr(scr);
142
143         if (screen->exit)
144                 screen->on_exit(screen->cui);
145
146         widgetset_post(screen->widgetset);
147         nc_scr_frame_draw(scr);
148         if (screen->need_redraw) {
149                 redrawwin(scr->main_ncw);
150                 screen->need_redraw = false;
151         }
152         wrefresh(screen->scr.main_ncw);
153         pad_refresh(screen);
154         return 0;
155 }
156
157 static int add_url_screen_unpost(struct nc_scr *scr)
158 {
159         struct add_url_screen *screen = add_url_screen_from_scr(scr);
160         widgetset_unpost(screen->widgetset);
161         return 0;
162 }
163
164 struct nc_scr *add_url_screen_scr(struct add_url_screen *screen)
165 {
166         return &screen->scr;
167 }
168
169 static void add_url_process_cb(struct nc_scr *scr)
170 {
171         struct add_url_screen *screen = add_url_screen_from_scr(scr);
172
173         if (!screen_process_form(screen))
174                 screen->exit = true;
175 }
176
177 static void ok_click(void *arg)
178 {
179         struct add_url_screen *screen = arg;
180
181         if (discover_client_authenticated(screen->cui->client)) {
182                 if (screen_process_form(screen))
183                         /* errors are written to the status line, so we'll need
184                          * to refresh */
185                         wrefresh(screen->scr.main_ncw);
186                 else
187                         screen->exit = true;
188         } else {
189                 cui_show_auth(screen->cui, screen->scr.main_ncw, false,
190                                 add_url_process_cb);
191         }
192 }
193
194 static void help_click(void *arg)
195 {
196         struct add_url_screen *screen = arg;
197         screen->show_help = true;
198 }
199
200 static void cancel_click(void *arg)
201 {
202         struct add_url_screen *screen = arg;
203         screen->exit = true;
204 }
205
206 static int layout_pair(struct add_url_screen *screen, int y,
207         struct nc_widget_label *label,
208         struct nc_widget *field)
209 {
210         struct nc_widget *label_w = widget_label_base(label);
211         widget_move(label_w, y, screen->label_x);
212         widget_move(field, y, screen->field_x);
213         return max(widget_height(label_w), widget_height(field));
214 }
215
216 static void add_url_screen_layout_widgets(struct add_url_screen *screen)
217 {
218         int y = 2;
219
220         /* url field */
221         y += layout_pair(screen, y, screen->widgets.url_l,
222                          widget_textbox_base(screen->widgets.url_f));
223
224         /* ok, help, cancel */
225         y += 1;
226
227         widget_move(widget_button_base(screen->widgets.ok_b),
228                 y, screen->field_x);
229         widget_move(widget_button_base(screen->widgets.help_b),
230                 y, screen->field_x + 14);
231         widget_move(widget_button_base(screen->widgets.cancel_b),
232                 y, screen->field_x + 28);
233 }
234
235 static void add_url_screen_widget_focus(struct nc_widget *widget, void *arg)
236 {
237         struct add_url_screen *screen = arg;
238         int w_y, w_height, w_focus, s_max, adjust;
239
240         w_height = widget_height(widget);
241         w_focus = widget_focus_y(widget);
242         w_y = widget_y(widget) + w_focus;
243         s_max = getmaxy(screen->scr.sub_ncw) - 1;
244
245         if (w_y < screen->scroll_y)
246                 screen->scroll_y = w_y;
247
248         else if (w_y + screen->scroll_y + 1 > s_max) {
249                 /* Fit as much of the widget into the screen as possible */
250                 adjust = min(s_max - 1, w_height - w_focus);
251                 if (w_y + adjust >= screen->scroll_y + s_max)
252                         screen->scroll_y = max(0, 1 + w_y + adjust - s_max);
253         } else
254                 return;
255
256         pad_refresh(screen);
257 }
258
259 static void add_url_screen_setup_widgets(struct add_url_screen *screen)
260 {
261         struct nc_widgetset *set = screen->widgetset;
262
263         build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
264                         == N_FIELDS);
265
266         screen->widgets.url_l = widget_new_label(set, 0, 0,
267                         _("Configuration URL:"));
268         screen->widgets.url_f = widget_new_textbox(set, 0, 0, 50, NULL);
269
270         screen->widgets.ok_b = widget_new_button(set, 0, 0, 10, _("OK"),
271                         ok_click, screen);
272         screen->widgets.help_b = widget_new_button(set, 0, 0, 10, _("Help"),
273                         help_click, screen);
274         screen->widgets.cancel_b = widget_new_button(set, 0, 0, 10, _("Cancel"),
275                         cancel_click, screen);
276 }
277
278 static int add_url_screen_destroy(void *arg)
279 {
280         struct add_url_screen *screen = arg;
281         if (screen->pad)
282                 delwin(screen->pad);
283         return 0;
284 }
285
286 struct add_url_screen *add_url_screen_init(struct cui *cui,
287                 void (*on_exit)(struct cui *))
288 {
289         struct add_url_screen *screen;
290
291         screen = talloc_zero(cui, struct add_url_screen);
292         talloc_set_destructor(screen, add_url_screen_destroy);
293
294         screen->cui = cui;
295         screen->on_exit = on_exit;
296         screen->label_x = 2;
297         screen->field_x = 25;
298         screen->need_redraw = false;
299
300         nc_scr_init(&screen->scr, pb_add_url_screen_sig, 0,
301                 cui, add_url_screen_process_key,
302                 add_url_screen_post, add_url_screen_unpost,
303                 NULL);
304
305         screen->scr.frame.ltitle = talloc_strdup(screen,
306                         _("Petitboot Config Retrieval"));
307         screen->scr.frame.rtitle = NULL;
308         screen->scr.frame.help = talloc_strdup(screen,
309                         _("tab=next, shift+tab=previous, x=exit, h=help"));
310         nc_scr_frame_draw(&screen->scr);
311
312         screen->pad = newpad(LINES, COLS);
313         screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
314                         screen->pad);
315         widgetset_set_widget_focus(screen->widgetset,
316                         add_url_screen_widget_focus, screen);
317
318         add_url_screen_setup_widgets(screen);
319         add_url_screen_layout_widgets(screen);
320
321         return screen;
322 }
323