# error "Curses form.h not found."
#endif
-#include <string.h>
+#include <arpa/inet.h>
#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
#include <talloc/talloc.h>
#include <types/types.h>
#include <util/util.h>
#include <i18n/i18n.h>
#include <fold/fold.h>
+#include <url/url.h>
#include "nc-cui.h"
#include "nc-widgets.h"
FIELD *cur_field;
/* custom validators */
- FIELDTYPE *ipv4_multi_type;
+ FIELDTYPE *ip_multi_type;
+ FIELDTYPE *ip_type;
+ FIELDTYPE *url_type;
};
struct nc_widget {
return key == ' ' || key == '\r' || key == '\n' || key == KEY_ENTER;
}
-static bool key_is_minus(int key)
-{
- return key == 055;
-}
-
-static bool key_is_left(int key)
-{
- return key == KEY_LEFT;
-}
-
-static bool key_is_right(int key)
-{
- return key == KEY_RIGHT;
-}
-
static bool process_key_nop(struct nc_widget *widget __attribute__((unused)),
FORM *form __attribute((unused)),
int key __attribute__((unused)))
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
+ case '\t':
+ case KEY_BTAB:
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PPAGE:
+ case KEY_NPAGE:
+ /* Don't catch navigational keys */
+ return false;
default:
form_driver(form, key);
break;
set_field_type(textbox->widget.field, TYPE_INTEGER, 1, min, max);
}
-void widget_textbox_set_validator_ipv4(struct nc_widget_textbox *textbox)
+static bool check_url_field(FIELD *field,
+ const void *arg __attribute__((unused)))
+{
+ return is_url(field_buffer(field, 0));
+}
+
+void widget_textbox_set_validator_url(struct nc_widget_textbox *textbox)
{
- set_field_type(textbox->widget.field, TYPE_IPV4);
+ if (!textbox->set->url_type)
+ textbox->set->url_type = new_fieldtype(check_url_field, NULL);
+
+ set_field_type(textbox->widget.field, textbox->set->url_type);
}
-static bool check_ipv4_multi_char(int c,
+static bool check_ip_field(FIELD *field,
const void *arg __attribute__((unused)))
+{
+ char *str;
+ int rc;
+
+ str = strip_string(field_buffer(field, 0));
+
+ rc = addr_scheme(str);
+
+ return (rc == AF_INET || rc == AF_INET6);
+}
+
+
+static bool check_ipv6_multi_char(int c)
+{
+ return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ||
+ c == ':' || c == ' ';
+}
+
+static bool check_ipv4_multi_char(int c)
{
return isdigit(c) || c == '.' || c == ' ';
}
-static bool check_ipv4_multi_field(FIELD *field,
+static bool check_ip_multi_field(FIELD *field,
const void *arg __attribute__((unused)))
{
- char *buf = field_buffer(field, 0);
- unsigned int ip[4];
- int n, len;
-
- while (*buf != '\0') {
- n = sscanf(buf, "%u.%u.%u.%u%n",
- &ip[0], &ip[1], &ip[2], &ip[3], &len);
- if (n != 4)
- return false;
-
- if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255)
- return false;
-
- for (buf += len; *buf != '\0'; buf++) {
- if (isspace(*buf))
- continue;
- else if (isdigit(*buf))
- break;
- else
- return false;
- }
+ char *buf, *tok, *saveptr;
+ bool result;
+ int type;
+
+ /* Use strdup directly since we can't easily reach a talloc parent */
+ buf = strdup(strip_string(field_buffer(field, 0)));
+ if (!buf)
+ /* We tried */
+ return true;
+
+ result = false;
+ tok = strtok_r(buf, " ", &saveptr);
+ if (!tok || *tok == '\0')
+ goto err;
+
+ while (tok) {
+ type = addr_scheme(tok);
+ if (!(type == AF_INET || type == AF_INET6))
+ goto err;
+
+ tok = strtok_r(NULL, " ", &saveptr);
}
+ result = true;
- return true;
+err:
+ free(buf);
+ return result;
+}
+
+static bool check_ip_multi_char(int c, const void *arg __attribute__((unused)))
+{
+ return (check_ipv4_multi_char(c) || check_ipv6_multi_char(c));
+}
+
+void widget_textbox_set_validator_ip(struct nc_widget_textbox *textbox)
+{
+ if (!textbox->set->ip_type) {
+ textbox->set->ip_type = new_fieldtype(check_ip_field, NULL);
+ }
+ set_field_type(textbox->widget.field, textbox->set->ip_type);
}
-void widget_textbox_set_validator_ipv4_multi(struct nc_widget_textbox *textbox)
+/*
+ * In a perfect world we would use link_fieldtype() but segfaults do not
+ * enhance the user experience.
+ */
+void widget_textbox_set_validator_ip_multi(struct nc_widget_textbox *textbox)
{
- if (!textbox->set->ipv4_multi_type) {
- textbox->set->ipv4_multi_type = new_fieldtype(
- check_ipv4_multi_field,
- check_ipv4_multi_char);
+ if (!textbox->set->ip_multi_type) {
+ textbox->set->ip_multi_type = new_fieldtype(
+ check_ip_multi_field,
+ check_ip_multi_char);
}
- set_field_type(textbox->widget.field, textbox->set->ipv4_multi_type);
+ set_field_type(textbox->widget.field, textbox->set->ip_multi_type);
}
static void subset_update_order(struct nc_widget_subset *subset)
struct nc_widget *widget;
size_t rem;
int i, val;
+ uint32_t opts;
/* Shift field focus to nearest active option or next visible field */
if (subset->n_active > 1) {
} else {
for (i = 0; i < set->n_fields; i++)
if (field_visible(set->fields[i])) {
- set->cur_field = set->fields[i];
- break;
+ opts = field_opts(set->fields[i]);
+ if ((opts & O_ACTIVE) == O_ACTIVE) {
+ set->cur_field = set->fields[i];
+ break;
+ }
}
}
int i, val, opt_idx = -1;
FIELD *field;
- if (!key_is_minus(key) && !key_is_left(key) && !key_is_right(key))
+ if (key != '-' && key != '+' && key != KEY_DC && key != KEY_BACKSPACE)
return false;
field = current_field(form);
if (opt_idx < 0)
return false;
- if (key_is_minus(key))
+ if (key == KEY_DC || key == KEY_BACKSPACE)
subset_delete_active(subset, opt_idx);
- if (key_is_left(key)){
+ if (key == '-') {
if (opt_idx == 0)
return true;
subset->active[opt_idx - 1] = val;
}
- if (key_is_right(key)){
+ if (key == '+') {
if (opt_idx >= subset->n_active - 1)
return true;
field = current_field(set->form);
assert(field);
+ widget = field_userptr(field);
+
+ if (widget->process_key)
+ if (widget->process_key(widget, set->form, key))
+ return true;
+
tab = false;
/* handle field change events */
tab = true;
/* fall through */
case KEY_UP:
- case KEY_LEFT:
req = REQ_SPREV_FIELD;
break;
case '\t':
tab = true;
/* fall through */
case KEY_DOWN:
- case KEY_RIGHT:
req = REQ_SNEXT_FIELD;
break;
case KEY_PPAGE:
case KEY_NPAGE:
req = REQ_SLAST_FIELD;
break;
+ case KEY_LEFT:
+ req = REQ_LEFT_FIELD;
+ break;
+ case KEY_RIGHT:
+ req = REQ_RIGHT_FIELD;
+ break;
}
- widget = field_userptr(field);
if (req) {
widget_focus_change(widget, field, false);
form_driver(set->form, req);
return true;
}
- if (!widget->process_key)
- return false;
-
- return widget->process_key(widget, set->form, key);
+ return false;
}
static int widgetset_destructor(void *ptr)
{
struct nc_widgetset *set = ptr;
free_form(set->form);
- if (set->ipv4_multi_type)
- free_fieldtype(set->ipv4_multi_type);
+ if (set->ip_type)
+ free_fieldtype(set->ip_type);
+ if (set->ip_multi_type)
+ free_fieldtype(set->ip_multi_type);
+ if (set->url_type)
+ free_fieldtype(set->url_type);
return 0;
}