Added support for client supplied menus.
Also modified existing menustuff slightly (on some points I made some things more consistent).
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
#include "drivers.h"
|
||||
#include "render.h"
|
||||
#include "client.h"
|
||||
#include "input.h"
|
||||
|
||||
/***************************************************************
|
||||
* Debugging only.. prints out a list of arguments it receives
|
||||
@@ -165,59 +166,51 @@ client_set_func (Client * c, int argc, char **argv)
|
||||
* Tells the server the client would like to accept keypresses
|
||||
* of a particular type
|
||||
*
|
||||
* usage: client_add_key <keylist>
|
||||
* usage: client_add_key [-exclusively|-shared] {<key>}+
|
||||
*/
|
||||
#define BUFLEN 80
|
||||
int
|
||||
client_add_key_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
char * keys ;
|
||||
int exclusively = 0;
|
||||
int argnr;
|
||||
char errmsg[BUFLEN];
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
if (argc != 2) {
|
||||
if (argc < 2) {
|
||||
switch (argc) {
|
||||
case 1:
|
||||
sock_send_string (c->sock, "huh? usage: client_add_key <keylist>\n");
|
||||
break;
|
||||
default:
|
||||
sock_send_string (c->sock, "huh? Too many parameters...\n");
|
||||
sock_send_string (c->sock, "huh? Usage: client_add_key [-exclusively|-shared] {<key>}+\n");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
keys = argv[1];
|
||||
debug(RPT_DEBUG, "client_add_key: current client will handle key(s) %s", keys);
|
||||
|
||||
if (!c->client_keys) {
|
||||
/* No keys list, create a new one*/
|
||||
c->client_keys = strdup( keys );
|
||||
} else {
|
||||
/* Add supplied keys to existing list
|
||||
* NOTE: There could be duplicates in the resulting list
|
||||
* That's OK, it's the existence of the key in the list
|
||||
* that's important. We'll be more careful in the delete
|
||||
* key function.
|
||||
*/
|
||||
char * new ;
|
||||
int new_len = strlen(c->client_keys) + strlen(keys) + 1 ;
|
||||
|
||||
new = realloc( c->client_keys, new_len );
|
||||
if( new ) {
|
||||
c->client_keys = new ;
|
||||
strcat( new, keys );
|
||||
} else {
|
||||
sock_send_string(c->sock, "huh? could not allocate memory for new keys\n");
|
||||
return 0;
|
||||
argnr = 1;
|
||||
if( argv[argnr][0] == '-' ) {
|
||||
if( strcmp( argv[argnr], "-shared") == 0 ) {
|
||||
exclusively = 0;
|
||||
}
|
||||
else if( strcmp( argv[argnr], "-exclusively") == 0 ) {
|
||||
exclusively = 1;
|
||||
}
|
||||
else {
|
||||
snprintf( errmsg, BUFLEN-1, "huh? Invalid option: %s\n", argv[argnr] );
|
||||
errmsg[BUFLEN-1] = 0;
|
||||
sock_send_string( c->sock, errmsg );
|
||||
}
|
||||
argnr ++;
|
||||
}
|
||||
for ( ; argnr < argc; argnr++ ) {
|
||||
if( input_reserve_key( argv[argnr], exclusively, c ) < 0 ) {
|
||||
snprintf( errmsg, BUFLEN-1, "huh? Could not reserve key \"%s\"\n", argv[argnr] );
|
||||
errmsg[BUFLEN-1] = 0;
|
||||
sock_send_string( c->sock, errmsg );
|
||||
}
|
||||
}
|
||||
|
||||
if (c->client_keys) {
|
||||
sock_send_string(c->sock, "success\n");
|
||||
} else {
|
||||
sock_send_string(c->sock, "huh? failed\n");
|
||||
}
|
||||
sock_send_string(c->sock, "success\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -226,52 +219,24 @@ client_add_key_func (Client * c, int argc, char **argv)
|
||||
* Tells the server the client would NOT like to accept keypresses
|
||||
* of a particular type
|
||||
*
|
||||
* usage: client_del_key <keylist>
|
||||
* usage: client_del_key {<key>}+
|
||||
*/
|
||||
int
|
||||
client_del_key_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
char * keys ;
|
||||
int argnr;
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
if (argc != 2) {
|
||||
if (argc == 1) {
|
||||
sock_send_string (c->sock, "huh? usage: client_del_key <keylist>\n");
|
||||
return 0;
|
||||
} else {
|
||||
sock_send_string (c->sock, "huh? Too many parameters...\n");
|
||||
return 0;
|
||||
}
|
||||
if (argc < 2) {
|
||||
sock_send_string (c->sock, "huh? Usage: client_del_key {<key>}+\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
keys = argv[1] ;
|
||||
debug(RPT_DEBUG, "client_del_key: Deleting key(s) %s from client_keys", keys);
|
||||
|
||||
if (c->client_keys) {
|
||||
/* Client has keys, remove keys from the list
|
||||
* NOTE: We let malloc/realloc remember the length
|
||||
* of the allocated storage. If keys are later
|
||||
* added, realloc (in add_key above) will make
|
||||
* sure there is enough space at c->data->client_keys
|
||||
*/
|
||||
char * from ;
|
||||
char * to ;
|
||||
|
||||
to = from = c->client_keys ;
|
||||
while( *from ) {
|
||||
/* Is this key to be deleted from the list?*/
|
||||
if( strchr( keys, *from ) ) {
|
||||
/* Yes, skip it*/
|
||||
++from ;
|
||||
} else {
|
||||
/* No, save it*/
|
||||
*to++ = *from++ ;
|
||||
}
|
||||
}
|
||||
for( argnr=1; argnr < argc; argnr++) {
|
||||
input_release_key( argv[argnr], c );
|
||||
}
|
||||
|
||||
sock_send_string(c->sock, "success\n");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
* The functions here are to be called only from parse.c's interpreter.
|
||||
*
|
||||
* The client's available function set is defined here, as is the syntax
|
||||
* for each command.
|
||||
* for each command. <-- TODO !
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -39,9 +39,6 @@ client_function commands[] = {
|
||||
{"widget_add", widget_add_func},
|
||||
{"widget_del", widget_del_func},
|
||||
{"widget_set", widget_set_func},
|
||||
{"menu_add", menu_add_func},
|
||||
{"menu_del", menu_del_func},
|
||||
{"menu_set", menu_set_func},
|
||||
{"menu_add_item", menu_add_item_func},
|
||||
{"menu_del_item", menu_del_item_func},
|
||||
{"menu_set_item", menu_set_item_func},
|
||||
|
||||
+579
-60
@@ -19,121 +19,640 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "shared/report.h"
|
||||
#include "shared/sockets.h"
|
||||
|
||||
#include "menu.h"
|
||||
#include "menuitem.h"
|
||||
#include "menuscreens.h"
|
||||
#include "client.h"
|
||||
|
||||
/*************************************************************
|
||||
* Adds a menu to the client; handled by the server...
|
||||
*
|
||||
* usage: menu_add ...?
|
||||
*/
|
||||
int
|
||||
menu_add_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
sock_send_string (c->sock, "huh? Not implemented yet.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Removes a client's menu and all contents from the server
|
||||
*
|
||||
* usage: menu_del ...?
|
||||
*/
|
||||
int
|
||||
menu_del_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
sock_send_string (c->sock, "huh? Not implemented yet.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Sets info about a menu, but not its items
|
||||
*
|
||||
* For example, should the menu be top-level, or buried somewhere?
|
||||
*
|
||||
* usage: menu_set ...?
|
||||
*/
|
||||
int
|
||||
menu_set_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
sock_send_string (c->sock, "huh? Not implemented yet.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
MenuEventFunc(menu_commands_handler);
|
||||
|
||||
/*************************************************************************
|
||||
* menu_add_item_func
|
||||
*
|
||||
* Adds an item to a menu
|
||||
*
|
||||
* usage: menu_add_item ...?
|
||||
* Usage: menu_add_item <menuid> <newitemid> <type> [<text>]
|
||||
* You should use "" as id for the client's main menu. This menu will be
|
||||
* created automatically when you add an item to it the first time.
|
||||
* You (currently?) cannot create a menu in the main level yourself.
|
||||
* The names you use for items should be unique for your client.
|
||||
* The text is the visible text for the item.
|
||||
*
|
||||
* The following types are available:
|
||||
* - menu
|
||||
* - action
|
||||
* - checkbox
|
||||
* - ring (a kind of listbox of one line)
|
||||
* - slider
|
||||
* - numeric
|
||||
* - alpha
|
||||
*/
|
||||
|
||||
int
|
||||
menu_add_item_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
char * menu_id;
|
||||
char * item_id;
|
||||
char * text = NULL;
|
||||
Menu * menu = NULL;
|
||||
MenuItem * item;
|
||||
MenuItemType itemtype;
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
sock_send_string (c->sock, "huh? Not implemented yet.\n");
|
||||
if (!c->name) {
|
||||
sock_send_string (c->sock, "huh? You need to give your client a name first\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((argc < 4 )) {
|
||||
sock_send_string (c->sock, "huh? Usage: menu_add_item <menuid> <newitemid> <type> [<text>]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
menu_id = argv[1];
|
||||
item_id = argv[2];
|
||||
|
||||
/* Does the client have a menu already ? */
|
||||
if (!c->menu) {
|
||||
/* We need to create it */
|
||||
c->menu = menu_create ("_client_menu_", menu_commands_handler, c->name, c);
|
||||
menu_add_item (main_menu, c->menu);
|
||||
}
|
||||
|
||||
if ( menu_id[0] == 0 ) {
|
||||
/* No menu specified = client's main menu */
|
||||
menu = c->menu;
|
||||
} else {
|
||||
/* A specified menu */
|
||||
menu = menu_find_item (c->menu, menu_id, true);
|
||||
}
|
||||
if (!menu) {
|
||||
sock_send_string (c->sock, "huh? Cannot find menu id\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = menu_find_item (c->menu, item_id, true);
|
||||
if (item) {
|
||||
sock_send_string (c->sock, "huh? Item id already in use\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find menuitem type */
|
||||
itemtype = menuitem_typename_to_type (argv[3]);
|
||||
if (itemtype == -1) {
|
||||
sock_send_string (c->sock, "huh? Invalid menuitem type\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is a text given ? */
|
||||
if (argc >= 5) {
|
||||
text = argv[4];
|
||||
}
|
||||
else {
|
||||
text = "";
|
||||
}
|
||||
|
||||
/* Create the menuitem */
|
||||
switch (itemtype) {
|
||||
case MENUITEM_MENU:
|
||||
item = menu_create (item_id, menu_commands_handler, text, c);
|
||||
break;
|
||||
case MENUITEM_ACTION:
|
||||
item = menuitem_create_action (item_id, menu_commands_handler, text,
|
||||
MENURESULT_NONE);
|
||||
break;
|
||||
case MENUITEM_CHECKBOX:
|
||||
item = menuitem_create_checkbox (item_id, menu_commands_handler, text,
|
||||
false, false);
|
||||
break;
|
||||
case MENUITEM_RING:
|
||||
item = menuitem_create_ring (item_id, menu_commands_handler, text,
|
||||
"", 0);
|
||||
break;
|
||||
case MENUITEM_SLIDER:
|
||||
item = menuitem_create_slider (item_id, menu_commands_handler, text,
|
||||
"", "", 0, 100, 1, 25);
|
||||
break;
|
||||
case MENUITEM_NUMERIC:
|
||||
item = menuitem_create_numeric (item_id, menu_commands_handler, text,
|
||||
0, 100, 0);
|
||||
break;
|
||||
case MENUITEM_ALPHA:
|
||||
item = menuitem_create_alpha (item_id, menu_commands_handler, text,
|
||||
0, 0, 10, true, false, true, "-./", "");
|
||||
break;
|
||||
}
|
||||
menu_add_item (menu, item);
|
||||
sock_send_string(c->sock, "success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* menu_del_item_func
|
||||
*
|
||||
* Deletes an item from a menu
|
||||
*
|
||||
+ usage: menu_del_item ...?
|
||||
* Usage: menu_del_item <menuid> <itemid>
|
||||
* The given item in the given menu will be deleted. If you have deleted all
|
||||
* the items from your client menu, that menu will automatically be removed.
|
||||
*/
|
||||
int
|
||||
menu_del_item_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
Menu * menu;
|
||||
MenuItem * item;
|
||||
char * menu_id;
|
||||
char * item_id;
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
sock_send_string (c->sock, "huh? Not implemented yet.\n");
|
||||
if ((argc < 4 )) {
|
||||
sock_send_string (c->sock, "huh? Usage: menu_del_item <menuid> <itemid>\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
menu_id = argv[1];
|
||||
item_id = argv[2];
|
||||
|
||||
if ( menu_id[0] == 0 ) {
|
||||
/* No menu specified = client's main menu */
|
||||
menu = c->menu;
|
||||
} else {
|
||||
/* A specified menu */
|
||||
menu = menu_find_item (c->menu, menu_id, true);
|
||||
}
|
||||
if (!menu) {
|
||||
sock_send_string (c->sock, "huh? Cannot find menu id\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = menu_find_item (c->menu, item_id, true);
|
||||
if (!item) {
|
||||
sock_send_string (c->sock, "huh? Cannot find item\n");
|
||||
return 0;
|
||||
}
|
||||
menu_remove_item (menu, item);
|
||||
menuitem_destroy (item);
|
||||
|
||||
sock_send_string(c->sock, "success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* menu_set_item_func
|
||||
* Sets the info about a menu item
|
||||
*
|
||||
* For example, text displayed, widget type, value, etc...
|
||||
* For example, text displayed, value, etc...
|
||||
*
|
||||
* usage: menu_set_item ...?
|
||||
* Usage: menu_set_item <menuid> <itemid> {<option>}+
|
||||
* The following parameters can be set per item:
|
||||
* (you should include the - in the option)
|
||||
*
|
||||
* For all types:
|
||||
* -text "text" ("")
|
||||
* Sets the visible text.
|
||||
*
|
||||
* menu:
|
||||
* (has no extra settable options)
|
||||
*
|
||||
* action:
|
||||
* -menu_result none|close|quit (none)
|
||||
* Sets what to do with the menu when this action is selected:
|
||||
* - none: the menu stays as it is.
|
||||
* - close: the menu closes and returns to a higher level.
|
||||
* - quit: quits the menu completely so you can foreground your app.
|
||||
*
|
||||
* checkbox:
|
||||
* -value off|on|gray (off)
|
||||
* Sets its current value.
|
||||
* -allow_gray false|true (false)
|
||||
* Sets if a grayed checkbox is allowed.
|
||||
*
|
||||
* ring:
|
||||
* -value <int> (0)
|
||||
* Sets the index in the stringlist that is currently selected.
|
||||
* -strings <string> (empty)
|
||||
* The subsequent strings that can be selected. They should be
|
||||
* tab-separated in ONE string.
|
||||
*
|
||||
* slider:
|
||||
* -value <int> (0)
|
||||
* Sets its current value.
|
||||
* -mintext <string> ("")
|
||||
* -maxtex <string> ("")
|
||||
* Text at the minimal and maximal side. On small displays these might
|
||||
* not be displayed.
|
||||
* -minvalue <int> (0)
|
||||
* -maxvalue <int> (100)
|
||||
* The minimum and maximum value of the slider.
|
||||
* -stepsize <int> (1)
|
||||
* The stepsize of the slider. If you use 0, you can control it yourself
|
||||
* completely.
|
||||
*
|
||||
* numeric:
|
||||
* -value <int> (0)
|
||||
* Sets its current value.
|
||||
* -minvalue <int> (0)
|
||||
* -maxvalue <int> (100)
|
||||
* The minimum and maximum value that are allowed. If you make one of
|
||||
* them negative, the user will be able to enter negative numbers too.
|
||||
* Maybe floats will work too in the future.
|
||||
*
|
||||
* alpha:
|
||||
* -value <string>
|
||||
* Sets its current value. ("")
|
||||
* -password_char <char> (none)
|
||||
* -minlength <int> (0)
|
||||
* -maxlength <int> (10)
|
||||
* Set the minimum and maximum allowed length.
|
||||
* -allow_caps false|true (true)
|
||||
* -allow_noncaps false|true (false)
|
||||
* -allow_numbers false|true (true)
|
||||
* Allows these groups of characters.
|
||||
* -allowed_extra <string> ("")
|
||||
* The chars in this string are also allowed.
|
||||
*
|
||||
* Hmm, this is getting very big. We might need a some real parser after all.
|
||||
*/
|
||||
|
||||
int
|
||||
menu_set_item_func (Client * c, int argc, char **argv)
|
||||
{
|
||||
typedef enum AttrType { NOVALUE, BOOLEAN, CHECKBOX_VALUE, SHORT, INT,
|
||||
FLOAT, STRING } AttrType;
|
||||
|
||||
struct OptionTable {
|
||||
MenuItemType menuitem_type; /* For what MenuItem type is
|
||||
the option ?
|
||||
Use -1 for ALL types. */
|
||||
char * name; /* The option concerned */
|
||||
AttrType attr_type; /* Type of value */
|
||||
int attr_offset; /* Where to put it the value
|
||||
in the structure.
|
||||
Use -1 to process it
|
||||
yourself. */
|
||||
/* Watch out with STRING, it will free() the current value
|
||||
* and reallocate for the new value !! If you don't want
|
||||
* that, use -1 for offset, to process it yourself. */
|
||||
} option_table[] = {
|
||||
{ -1, "text", STRING, offsetof(MenuItem,text) },
|
||||
{ MENUITEM_ACTION, "menu_result", STRING, -1 },
|
||||
{ MENUITEM_CHECKBOX, "value", CHECKBOX_VALUE, offsetof(MenuItem,data.checkbox.value) },
|
||||
{ MENUITEM_CHECKBOX, "allow_gray", BOOLEAN, offsetof(MenuItem,data.checkbox.allow_gray) },
|
||||
{ MENUITEM_RING, "value", SHORT, offsetof(MenuItem,data.ring.value) },
|
||||
{ MENUITEM_RING, "strings", STRING, -1 },
|
||||
{ MENUITEM_SLIDER, "value", INT, offsetof(MenuItem,data.slider.value) },
|
||||
{ MENUITEM_SLIDER, "minvalue", INT, offsetof(MenuItem,data.slider.minvalue) },
|
||||
{ MENUITEM_SLIDER, "maxvalue", INT, offsetof(MenuItem,data.slider.maxvalue) },
|
||||
{ MENUITEM_SLIDER, "stepsize", INT, offsetof(MenuItem,data.slider.stepsize) },
|
||||
{ MENUITEM_SLIDER, "mintext", STRING, offsetof(MenuItem,data.slider.mintext) },
|
||||
{ MENUITEM_SLIDER, "maxtext", STRING, offsetof(MenuItem,data.slider.maxtext) },
|
||||
{ MENUITEM_NUMERIC, "value", INT, offsetof(MenuItem,data.numeric.value) },
|
||||
{ MENUITEM_NUMERIC, "minvalue", INT, offsetof(MenuItem,data.numeric.minvalue) },
|
||||
{ MENUITEM_NUMERIC, "maxvalue", INT, offsetof(MenuItem,data.numeric.maxvalue) },
|
||||
/*{ MENUITEM_NUMERIC, "allow_decimals",BOOLEAN, offsetof(MenuItem,data.numeric.allow_decimals) },*/
|
||||
{ MENUITEM_ALPHA, "value", STRING, offsetof(MenuItem,data.alpha.value) },
|
||||
{ MENUITEM_ALPHA, "minlength", SHORT, offsetof(MenuItem,data.alpha.minlength) },
|
||||
{ MENUITEM_ALPHA, "maxlength", SHORT, offsetof(MenuItem,data.alpha.maxlength) },
|
||||
{ MENUITEM_ALPHA, "password_char",STRING, -1 },
|
||||
{ MENUITEM_ALPHA, "allow_caps", BOOLEAN, offsetof(MenuItem,data.alpha.allow_caps) },
|
||||
{ MENUITEM_ALPHA, "allow_noncaps",BOOLEAN, offsetof(MenuItem,data.alpha.allow_noncaps) },
|
||||
{ MENUITEM_ALPHA, "allow_numbers",BOOLEAN, offsetof(MenuItem,data.alpha.allow_numbers) },
|
||||
{ MENUITEM_ALPHA, "allowed_extra",STRING, offsetof(MenuItem,data.alpha.allowed_extra) },
|
||||
{ -1, NULL, -1, -1 }
|
||||
};
|
||||
|
||||
bool bool_value = false;
|
||||
CheckboxValue checkbox_value = CHECKBOX_OFF;
|
||||
short short_value = 0;
|
||||
int int_value = 0;
|
||||
float float_value = 0;
|
||||
char * string_value = NULL;
|
||||
|
||||
Menu * menu;
|
||||
MenuItem * item;
|
||||
char * menu_id;
|
||||
char * item_id;
|
||||
int argnr;
|
||||
char buf[80];
|
||||
|
||||
if (!c->ack)
|
||||
return 1;
|
||||
|
||||
sock_send_string (c->sock, "huh? Not implemented yet.\n");
|
||||
if ((argc < 4 )) {
|
||||
sock_send_string (c->sock, "huh? Usage: menu_set_item <menuid> <itemid> {<option>}+\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
menu_id = argv[1];
|
||||
item_id = argv[2];
|
||||
|
||||
if ( menu_id[0] == 0 ) {
|
||||
/* No menu specified = client's main menu */
|
||||
menu = c->menu;
|
||||
} else {
|
||||
/* A specified menu */
|
||||
menu = menu_find_item (c->menu, menu_id, true);
|
||||
}
|
||||
if (!menu) {
|
||||
sock_send_string (c->sock, "huh? Cannot find menu id\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = menu_find_item (c->menu, item_id, true);
|
||||
if (!item) {
|
||||
sock_send_string (c->sock, "huh? Cannot find item\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Scan all arguments */
|
||||
for( argnr = 3; argnr < argc; argnr ++) {
|
||||
int option_nr = -1;
|
||||
int found_option_name = 0;
|
||||
int error = 0;
|
||||
void * location;
|
||||
char * p;
|
||||
|
||||
/* Find the option in the table */
|
||||
if( argv[argnr][0] == '-' ) {
|
||||
int i;
|
||||
for( i=0; option_table[i].name; i++ ) {
|
||||
if( strcmp( argv[argnr]+1, option_table[i].name ) == 0 ) {
|
||||
found_option_name = 1;
|
||||
if( item->type == option_table[i].menuitem_type
|
||||
|| option_table[i].menuitem_type == -1 ) {
|
||||
option_nr = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
snprintf( buf, sizeof(buf), "huh? Found non-option: \"%.40s\"\n", argv[argnr] );
|
||||
sock_send_string (c->sock, buf);
|
||||
continue; /* Skip to next arg */
|
||||
}
|
||||
if( option_nr == -1 ) {
|
||||
if( found_option_name ) {
|
||||
snprintf( buf, sizeof(buf), "huh? Option not valid for menuitem type: \"%.40s\"\n", argv[argnr] );
|
||||
} else {
|
||||
snprintf( buf, sizeof(buf), "huh? Unknown option: \"%.40s\"\n", argv[argnr] );
|
||||
}
|
||||
sock_send_string (c->sock, buf);
|
||||
continue; /* Skip to next arg */
|
||||
}
|
||||
|
||||
/* OK, we now know we have an option that is valid for the item type. */
|
||||
|
||||
/* Check for value */
|
||||
if( option_table[option_nr].attr_type != NOVALUE ) {
|
||||
if( argnr + 1 >= argc ) {
|
||||
snprintf( buf, sizeof(buf), "huh? Missing value at option: \"%.40s\"\n", argv[argnr] );
|
||||
sock_send_string (c->sock, buf);
|
||||
continue; /* Skip to next arg (probably is not existing :) */
|
||||
}
|
||||
}
|
||||
/* Process the value that goes with the option */
|
||||
location = (void*)item + option_table[option_nr].attr_offset;
|
||||
switch( option_table[option_nr].attr_type ) {
|
||||
case NOVALUE:
|
||||
break;
|
||||
case BOOLEAN:
|
||||
if( strcmp( argv[argnr+1], "false" ) == 0 ) {
|
||||
bool_value = false;
|
||||
} else if( strcmp( argv[argnr+1], "true" ) == 0 ) {
|
||||
bool_value = true;
|
||||
} else {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if( option_table[option_nr].attr_offset != -1 ) {
|
||||
*(bool *)location = bool_value;
|
||||
}
|
||||
break;
|
||||
case CHECKBOX_VALUE:
|
||||
if( strcmp( argv[argnr+1], "off" ) == 0 ) {
|
||||
checkbox_value = CHECKBOX_OFF;
|
||||
} else if( strcmp( argv[argnr+1], "on" ) == 0 ) {
|
||||
checkbox_value = CHECKBOX_ON;
|
||||
} else if( strcmp( argv[argnr+1], "gray" ) == 0 ) {
|
||||
checkbox_value = CHECKBOX_GRAY;
|
||||
} else {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if( option_table[option_nr].attr_offset != -1 ) {
|
||||
*(CheckboxValue *)location = checkbox_value;
|
||||
}
|
||||
break;
|
||||
case SHORT:
|
||||
short_value = strtol( argv[argnr+1], &p, 0 );
|
||||
if( argv[argnr+1][0] == 0
|
||||
|| *p != 0 ) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if( option_table[option_nr].attr_offset != -1 ) {
|
||||
*(short*)location = short_value;
|
||||
}
|
||||
break;
|
||||
case INT:
|
||||
int_value = strtol( argv[argnr+1], &p, 0 );
|
||||
if( argv[argnr+1][0] == 0
|
||||
|| *p != 0 ) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if( option_table[option_nr].attr_offset != -1 ) {
|
||||
*(int*)location = int_value;
|
||||
}
|
||||
break;
|
||||
case FLOAT:
|
||||
float_value = strtod( argv[argnr+1], &p );
|
||||
if( argv[argnr+1][0] == 0
|
||||
|| *p != 0 ) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
if( option_table[option_nr].attr_offset != -1 ) {
|
||||
*(float*)location = float_value;
|
||||
}
|
||||
break;
|
||||
case STRING:
|
||||
string_value = argv[argnr+1];
|
||||
if( option_table[option_nr].attr_offset != -1 ) {
|
||||
free( *(char**)location );
|
||||
*(char**)location = strdup( string_value );
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch( error ) {
|
||||
case 1:
|
||||
snprintf( buf, sizeof(buf), "huh? Could not interpret value at option: \"%.40s\"\n", argv[argnr] );
|
||||
sock_send_string (c->sock, buf);
|
||||
argnr ++;
|
||||
continue; /* Skip current option and the invalid value */
|
||||
}
|
||||
|
||||
/* And at last process extra things for certain options.
|
||||
* Most useful for the attr_offset==-1 stuff. */
|
||||
switch (item->type) {
|
||||
case MENUITEM_ACTION:
|
||||
if( strcmp( argv[argnr]+1, "menu_result" ) == 0 ) {
|
||||
if( strcmp( argv[argnr+1], "none" ) == 0 ) {
|
||||
item->data.action.menu_result = MENURESULT_NONE;
|
||||
} else if( strcmp( argv[argnr+1], "close" ) == 0 ) {
|
||||
item->data.action.menu_result = MENURESULT_CLOSE;
|
||||
} else if( strcmp( argv[argnr+1], "quit" ) == 0 ) {
|
||||
item->data.action.menu_result = MENURESULT_QUIT;
|
||||
} else {
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MENUITEM_SLIDER:
|
||||
if( item->data.slider.value < item->data.slider.minvalue ) {
|
||||
item->data.slider.value = item->data.slider.minvalue;
|
||||
} else if( item->data.slider.value > item->data.slider.maxvalue ) {
|
||||
item->data.slider.value = item->data.slider.maxvalue;
|
||||
}
|
||||
break;
|
||||
case MENUITEM_RING:
|
||||
if( strcmp( argv[argnr]+1, "strings" ) == 0 ) {
|
||||
free (item->data.ring.strings);
|
||||
item->data.ring.strings = tablist2linkedlist (string_value);
|
||||
}
|
||||
item->data.ring.value %= LL_Length( item->data.ring.strings );
|
||||
break;
|
||||
case MENUITEM_NUMERIC:
|
||||
menuitem_reset (item);
|
||||
break;
|
||||
case MENUITEM_ALPHA:
|
||||
if( strcmp( argv[argnr]+1, "password_char" ) == 0 ) {
|
||||
item->data.alpha.password_char = string_value[0];
|
||||
}
|
||||
else if( strcmp( argv[argnr]+1, "maxlength" ) == 0 ) {
|
||||
char * new_buf;
|
||||
if( short_value < 0 || short_value > 1000 ) {
|
||||
error = 2;
|
||||
break;
|
||||
}
|
||||
new_buf = malloc( short_value + 1 );
|
||||
strncpy( new_buf, item->data.alpha.value, short_value );
|
||||
new_buf[short_value] = 0; /* terminate */
|
||||
free( item->data.alpha.value );
|
||||
item->data.alpha.value = new_buf;
|
||||
free( item->data.alpha.edit_str );
|
||||
item->data.alpha.edit_str = malloc( short_value + 1 );
|
||||
item->data.alpha.edit_str[0] = 0;
|
||||
}
|
||||
else if( strcmp( argv[argnr]+1, "value" ) == 0 ) {
|
||||
strncpy( item->data.alpha.value, string_value, item->data.alpha.maxlength );
|
||||
item->data.alpha.value[ item->data.alpha.maxlength ] = 0; /* terminate */
|
||||
}
|
||||
menuitem_reset (item);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch( error ) {
|
||||
case 1:
|
||||
snprintf( buf, sizeof(buf), "huh? Could not interpret value at option: \"%.40s\"\n", argv[argnr] );
|
||||
sock_send_string (c->sock, buf);
|
||||
continue; /* Skip to next arg and retry it as an option */
|
||||
case 2:
|
||||
snprintf( buf, sizeof(buf), "huh? Value out of range at option: \"%.40s\"\n", argv[argnr] );
|
||||
sock_send_string (c->sock, buf);
|
||||
argnr ++;
|
||||
continue; /* Skip current option and the invalid value */
|
||||
}
|
||||
if( active_menuitem && menuscreen ) {
|
||||
/* We need to rebuild the screen */
|
||||
menuitem_build_screen( active_menuitem, menuscreen );
|
||||
menuitem_update_screen( active_menuitem, menuscreen );
|
||||
}
|
||||
if( option_table[option_nr].attr_type != NOVALUE ) {
|
||||
/* Skip the now used argument */
|
||||
argnr ++;
|
||||
}
|
||||
}
|
||||
sock_send_string(c->sock, "success\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
MenuEventFunc (menu_commands_handler)
|
||||
{
|
||||
char buf[80] = "";
|
||||
Client * c;
|
||||
MenuItem * i;
|
||||
|
||||
/* Compose message */
|
||||
if( event == MENUEVENT_UPDATE
|
||||
|| event == MENUEVENT_MINUS
|
||||
|| event == MENUEVENT_PLUS ) {
|
||||
switch( item->type ) {
|
||||
case MENUITEM_CHECKBOX:
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s %s\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id, ((char*[]){"off","on","gray"})[item->data.checkbox.value] );
|
||||
break;
|
||||
case MENUITEM_SLIDER:
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s %d\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id, item->data.slider.value );
|
||||
break;
|
||||
case MENUITEM_RING:
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s %d\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id, item->data.ring.value );
|
||||
break;
|
||||
case MENUITEM_NUMERIC:
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s %d\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id, item->data.numeric.value );
|
||||
break;
|
||||
case MENUITEM_ALPHA:
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s %.40s\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id, item->data.alpha.value );
|
||||
break;
|
||||
default:
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id);
|
||||
}
|
||||
}
|
||||
else {
|
||||
snprintf (buf, sizeof(buf)-1, "menuevent %s %.40s\n",
|
||||
menuitem_eventtype_to_eventtypename(event),
|
||||
item->id);
|
||||
}
|
||||
|
||||
buf[sizeof(buf)-1] = 0;
|
||||
|
||||
/* Where should the message go to ? */
|
||||
for( i = item; i && i->parent != main_menu; i = item->parent );
|
||||
c = (Client *) i->data.menu.association;
|
||||
if( !c ) {
|
||||
report( RPT_ERR, "%s: Could not find client of item \"%s\"", __FUNCTION__, item->id );
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Send it */
|
||||
sock_send_string (c->sock, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user