better support for IPv6 inpu: not perfect, but on its way;
support IP input in 4 key mode
This commit is contained in:
+102
-89
@@ -62,6 +62,29 @@ MenuResult menuitem_process_input_alpha (MenuItem *item, MenuToken token, char *
|
|||||||
MenuResult menuitem_process_input_ip (MenuItem *item, MenuToken token, char * key, bool extended);
|
MenuResult menuitem_process_input_ip (MenuItem *item, MenuToken token, char * key, bool extended);
|
||||||
|
|
||||||
|
|
||||||
|
/* information about string representation of IP addresses */
|
||||||
|
typedef struct {
|
||||||
|
int maxlen; // max length of the string represenation;
|
||||||
|
char sep; // separators between numeric strings
|
||||||
|
int base; // numeric base
|
||||||
|
int width; // width of each numeric string
|
||||||
|
int limit; // upper limit of each numeric string
|
||||||
|
int posValue[5]; // digit-value of the digits at the approp. position in the numeric string
|
||||||
|
char format[5]; // printf-format string to print a numeric string
|
||||||
|
int (*verify)(const char *); // verify function
|
||||||
|
char dummy[16]; // dummy value (if provided value is no IP address)
|
||||||
|
} IpSstringProperties;
|
||||||
|
|
||||||
|
|
||||||
|
const IpSstringProperties IPinfo[] = {
|
||||||
|
// IPv4: 15 char long ':'-separated sequence of 4-digit hex strings
|
||||||
|
{ 15, '.', 10, 3, 255, { 100, 10, 1, 0, 0 }, "%03d", verify_ipv4, "0.0.0.0" },
|
||||||
|
// IPv6: 39 char long ':'-separated sequence of 4-digit hex strings
|
||||||
|
{ 39, ':', 16, 4, 65535, { 4096, 256, 16, 1, 0 }, "%04x", verify_ipv6, "0:0:0:0:0:0:0:0" }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/******** FUNCTION TABLES ********/
|
/******** FUNCTION TABLES ********/
|
||||||
/* Tables with functions to call for all different item types */
|
/* Tables with functions to call for all different item types */
|
||||||
|
|
||||||
@@ -296,20 +319,25 @@ MenuItem *menuitem_create_ip (char *id, MenuEventFunc(*event_func),
|
|||||||
char *text, Client *client, bool v6, char *value)
|
char *text, Client *client, bool v6, char *value)
|
||||||
{
|
{
|
||||||
MenuItem *new_item;
|
MenuItem *new_item;
|
||||||
|
const IpSstringProperties *ipinfo;
|
||||||
|
|
||||||
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", v6=%d, value=\"%s\" )",
|
debug (RPT_DEBUG, "%s( id=\"%s\", event_func=%p, text=\"%s\", v6=%d, value=\"%s\" )",
|
||||||
__FUNCTION__, id, event_func, text, v6, value);
|
__FUNCTION__, id, event_func, text, v6, value);
|
||||||
|
|
||||||
new_item = menuitem_create (MENUITEM_IP, id, event_func, text, client);
|
new_item = menuitem_create (MENUITEM_IP, id, event_func, text, client);
|
||||||
new_item->data.ip.v6 = v6;
|
new_item->data.ip.v6 = v6;
|
||||||
if (v6)
|
ipinfo = (v6) ? &IPinfo[1] : &IPinfo[0];
|
||||||
new_item->data.ip.maxlength = 39;
|
|
||||||
else
|
|
||||||
new_item->data.ip.maxlength = 15;
|
|
||||||
|
|
||||||
|
new_item->data.ip.maxlength = ipinfo->maxlen;;
|
||||||
new_item->data.ip.value = malloc (new_item->data.ip.maxlength + 1);
|
new_item->data.ip.value = malloc (new_item->data.ip.maxlength + 1);
|
||||||
strncpy (new_item->data.ip.value, value, new_item->data.ip.maxlength);
|
if (ipinfo->verify(value)) {
|
||||||
new_item->data.ip.value[new_item->data.ip.maxlength] = 0;
|
strncpy(new_item->data.ip.value, value, new_item->data.ip.maxlength);
|
||||||
|
new_item->data.ip.value[new_item->data.ip.maxlength] = '\0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy(new_item->data.ip.value, ipinfo->dummy, new_item->data.ip.maxlength);
|
||||||
|
new_item->data.ip.value[new_item->data.ip.maxlength] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
new_item->data.ip.edit_str = malloc (new_item->data.ip.maxlength + 1);
|
new_item->data.ip.edit_str = malloc (new_item->data.ip.maxlength + 1);
|
||||||
|
|
||||||
@@ -452,29 +480,31 @@ void menuitem_reset_alpha (MenuItem *item)
|
|||||||
|
|
||||||
void menuitem_reset_ip (MenuItem *item)
|
void menuitem_reset_ip (MenuItem *item)
|
||||||
{
|
{
|
||||||
char *s;
|
char *start = item->data.ip.value;
|
||||||
int count,index,i,j;
|
const IpSstringProperties *ipinfo = (item->data.ip.v6) ? &IPinfo[1] : &IPinfo[0];
|
||||||
|
|
||||||
debug (RPT_DEBUG, "%s( item=[%s] )", __FUNCTION__,
|
debug (RPT_DEBUG, "%s( item=[%s] )", __FUNCTION__,
|
||||||
((item != NULL) ? item->id : "(null)"));
|
((item != NULL) ? item->id : "(null)"));
|
||||||
|
|
||||||
item->data.ip.edit_pos = 0;
|
item->data.ip.edit_pos = 0;
|
||||||
memset (item->data.ip.edit_str, '\0', item->data.ip.maxlength+1);
|
memset (item->data.ip.edit_str, '\0', item->data.ip.maxlength+1);
|
||||||
// strcpy (item->data.ip.edit_str, item->data.ip.value);
|
|
||||||
index = 0;
|
// normalize IP address string to 010.002.250.002 / 00:01:02:04:05:06:07:08:09:0a:0b:0c:0e:0f
|
||||||
s = item->data.ip.value;
|
while (start != NULL)
|
||||||
for (j = 0; j < 4; j++) {
|
{
|
||||||
count = strcspn (s, ".");
|
char *end;
|
||||||
for (i = 3; i > 0; i--) {
|
char tmpstr[5];
|
||||||
if (i == count) {
|
int num = (int) strtol(start, (char **) NULL, ipinfo->base);
|
||||||
item->data.ip.edit_str[index++] = *s++;
|
|
||||||
count--;
|
snprintf(tmpstr, 5, ipinfo->format, num);
|
||||||
} else {
|
strcat(item->data.ip.edit_str, tmpstr);
|
||||||
item->data.ip.edit_str[index++] = ' ';
|
end = strchr(start, ipinfo->sep);
|
||||||
}
|
start = (end != NULL) ? (end + 1) : NULL;
|
||||||
}
|
if (start != NULL) {
|
||||||
/* copy period or null */
|
tmpstr[0] = ipinfo->sep;
|
||||||
item->data.ip.edit_str[index++] = *s++;
|
tmpstr[1] = '\0';
|
||||||
|
strcat(item->data.ip.edit_str, tmpstr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1173,40 +1203,15 @@ MenuResult menuitem_process_input_alpha (MenuItem *item, MenuToken token, char *
|
|||||||
return MENURESULT_ERROR;
|
return MENURESULT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct valueProperties {
|
|
||||||
int start; /* index of first digit of this number */
|
|
||||||
int place; /* is this the 1s, 10s or 100s digit */
|
|
||||||
} tValueProperties;
|
|
||||||
|
|
||||||
MenuResult menuitem_process_input_ip (MenuItem *item, MenuToken token, char * key, bool extended)
|
MenuResult menuitem_process_input_ip (MenuItem *item, MenuToken token, char * key, bool extended)
|
||||||
{
|
{
|
||||||
char * p;
|
|
||||||
tValueProperties valueProperties[] = {
|
|
||||||
{0, 100 },
|
|
||||||
{0, 10 },
|
|
||||||
{0, 1 },
|
|
||||||
{0, 0 },
|
|
||||||
|
|
||||||
{4, 100 },
|
|
||||||
{4, 10 },
|
|
||||||
{4, 1 },
|
|
||||||
{0, 0 },
|
|
||||||
|
|
||||||
{8, 100 },
|
|
||||||
{8, 10 },
|
|
||||||
{8, 1 },
|
|
||||||
{0, 0 },
|
|
||||||
|
|
||||||
{12, 100 },
|
|
||||||
{12, 10 },
|
|
||||||
{12, 1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* To make life easy... */
|
/* To make life easy... */
|
||||||
char *str = item->data.ip.edit_str;
|
char *str = item->data.ip.edit_str;
|
||||||
char numstr[4];
|
char numstr[5];
|
||||||
int num;
|
int num;
|
||||||
int pos = item->data.ip.edit_pos;
|
int pos = item->data.ip.edit_pos;
|
||||||
|
const IpSstringProperties *ipinfo = (item->data.ip.v6) ? &IPinfo[1] : &IPinfo[0];
|
||||||
|
|
||||||
debug (RPT_DEBUG, "%s( item=[%s], token=%d, key=\"%s\" )", __FUNCTION__,
|
debug (RPT_DEBUG, "%s( item=[%s], token=%d, key=\"%s\" )", __FUNCTION__,
|
||||||
((item != NULL) ? item->id : "(null)"), token, key);
|
((item != NULL) ? item->id : "(null)"), token, key);
|
||||||
@@ -1228,66 +1233,74 @@ MenuResult menuitem_process_input_ip (MenuItem *item, MenuToken token, char * ke
|
|||||||
}
|
}
|
||||||
return MENURESULT_NONE;
|
return MENURESULT_NONE;
|
||||||
case MENUTOKEN_ENTER:
|
case MENUTOKEN_ENTER:
|
||||||
/* remove the spaces */
|
if (extended || (pos >= item->data.ip.maxlength - 1)) {
|
||||||
p = str;
|
/* remove the loading spaces/zeros in each octet-representing string */
|
||||||
while (*p) {
|
char *start = str;
|
||||||
if (*p == ' ') {
|
|
||||||
memccpy(p, p+1, '\0', item->data.ip.maxlength + 1);
|
|
||||||
} else {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->data.ip.v6) {
|
while (start != NULL) {
|
||||||
if (verify_ipv6(item->data.ip.edit_str)) {
|
char *skip = start;
|
||||||
item->data.ip.error_code = 4;
|
|
||||||
return MENURESULT_NONE;
|
while ((*skip == ' ') || ((*skip == '0') && (skip[1] != ipinfo->sep) && (skip[1] != '\0')))
|
||||||
|
skip++;
|
||||||
|
memccpy(start, skip, '\0', item->data.ip.maxlength + 1);
|
||||||
|
skip = strchr(start, ipinfo->sep);
|
||||||
|
start = (skip != NULL) ? (skip + 1) : NULL;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (verify_ipv4(item->data.ip.edit_str)) {
|
if (ipinfo->verify(item->data.ip.edit_str)) {
|
||||||
item->data.ip.error_code = 4;
|
item->data.ip.error_code = 4;
|
||||||
return MENURESULT_NONE;
|
return MENURESULT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Store value */
|
||||||
|
strcpy (item->data.ip.value, item->data.ip.edit_str);
|
||||||
|
|
||||||
|
/* Inform client */
|
||||||
|
if (item->event_func)
|
||||||
|
item->event_func (item, MENUEVENT_UPDATE);
|
||||||
|
|
||||||
|
return MENURESULT_CLOSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item->data.ip.edit_pos++;
|
||||||
|
if (str[item->data.ip.edit_pos] == ipinfo->sep)
|
||||||
|
item->data.ip.edit_pos++;
|
||||||
|
return MENURESULT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store value */
|
|
||||||
strcpy (item->data.ip.value, item->data.ip.edit_str);
|
|
||||||
|
|
||||||
/* Inform client */
|
|
||||||
if (item->event_func)
|
|
||||||
item->event_func (item, MENUEVENT_UPDATE);
|
|
||||||
|
|
||||||
return MENURESULT_CLOSE;
|
|
||||||
case MENUTOKEN_UP:
|
case MENUTOKEN_UP:
|
||||||
num = atoi(&str[(valueProperties[pos].start)]);
|
// convert string starting at the beginning / previous dot into a number
|
||||||
num += valueProperties[pos].place;
|
num = (int) strtol(&str[pos - (pos % (ipinfo->width + 1))], (char **) NULL, ipinfo->base);
|
||||||
if (num <= 255) {
|
// increase the number depending on the position
|
||||||
sprintf(numstr,"%3d", num);
|
num += ipinfo->posValue[(pos - (pos / (ipinfo->width + 1))) % ipinfo->width];
|
||||||
memcpy(&str[valueProperties[pos].start], numstr, 3);
|
if (num <= ipinfo->limit) {
|
||||||
|
snprintf(numstr, 5, ipinfo->format, num);
|
||||||
|
memcpy(&str[pos - (pos % (ipinfo->width + 1))], numstr, ipinfo->width);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MENURESULT_NONE;
|
return MENURESULT_NONE;
|
||||||
case MENUTOKEN_DOWN:
|
case MENUTOKEN_DOWN:
|
||||||
num = atoi(&str[valueProperties[pos].start]);
|
// convert string starting at the beginning / previous dot into a number
|
||||||
num -= valueProperties[pos].place;
|
num = (int) strtol(&str[pos - (pos % (ipinfo->width + 1))], (char **) NULL, ipinfo->base);
|
||||||
|
// decrease the number depending on the position
|
||||||
|
num -= ipinfo->posValue[(pos - (pos / (ipinfo->width + 1))) % ipinfo->width];
|
||||||
if (num >= 0) {
|
if (num >= 0) {
|
||||||
sprintf(numstr,"%3d", num);
|
snprintf(numstr, 5, ipinfo->format, num);
|
||||||
memcpy(&str[valueProperties[pos].start], numstr, 3);
|
memcpy(&str[pos - (pos % (ipinfo->width + 1))], numstr, ipinfo->width);
|
||||||
}
|
}
|
||||||
return MENURESULT_NONE;
|
return MENURESULT_NONE;
|
||||||
case MENUTOKEN_RIGHT:
|
case MENUTOKEN_RIGHT:
|
||||||
if (pos < item->data.ip.maxlength - 1) {
|
if (pos < item->data.ip.maxlength - 1) {
|
||||||
item->data.ip.edit_pos ++;
|
item->data.ip.edit_pos++;
|
||||||
if (str[item->data.ip.edit_pos] == '.')
|
if (str[item->data.ip.edit_pos] == ipinfo->sep)
|
||||||
item->data.ip.edit_pos ++;
|
item->data.ip.edit_pos++;
|
||||||
}
|
}
|
||||||
return MENURESULT_NONE;
|
return MENURESULT_NONE;
|
||||||
case MENUTOKEN_LEFT:
|
case MENUTOKEN_LEFT:
|
||||||
/* The user wants to go to back a digit */
|
/* The user wants to go to back a digit */
|
||||||
if (pos > 0) {
|
if (pos > 0) {
|
||||||
item->data.ip.edit_pos --;
|
item->data.ip.edit_pos--;
|
||||||
if (str[item->data.ip.edit_pos] == '.')
|
if (str[item->data.ip.edit_pos] == ipinfo->sep)
|
||||||
item->data.ip.edit_pos --;
|
item->data.ip.edit_pos--;
|
||||||
}
|
}
|
||||||
return MENURESULT_NONE;
|
return MENURESULT_NONE;
|
||||||
case MENUTOKEN_OTHER:
|
case MENUTOKEN_OTHER:
|
||||||
|
|||||||
Reference in New Issue
Block a user