/** * The sleep_func was intended to make the server sleep for some seconds. * This function is currently ignored as making the server sleep actually * stalls it and disrupts other clients. * *\verbatim * Usage: sleep <seconds> *\endverbatim */ int sleep_func(Client *c, int argc, char **argv) { int secs; long out; char *endptr; #define MAX_SECS 60 #define MIN_SECS 1 if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: sleep <secs>\n"); return 0; } /* set errno to be able to detect errors in strtol() */ errno = 0; out = strtol(argv[1], &endptr, 0); /* From the man page for strtol(3) * * In particular, if *nptr is not `\0' but **endptr is * `\0' on return, the entire string is valid. * * In this case, argv[1] is *nptr, and &endptr is **endptr. */ if (errno) { sock_printf_error(c->sock, "number argument: %s\n", strerror(errno)); return 0; } else if ((*argv[1] != '\0') && (*endptr == '\0')) { /* limit seconds to range: MIN_SECS - MAX_SECS */ out = (out > MAX_SECS) ? MAX_SECS : out; out = (out < MIN_SECS) ? MIN_SECS : out; secs = out; } else { sock_send_error(c->sock, "invalid parameter...\n"); return 0; } /* Repeat until no more remains - should normally be zero * on exit the first time...*/ sock_printf(c->sock, "sleeping %d seconds\n", secs); /* whoops.... if this takes place as planned, ALL screens * will "freeze" for the alloted time... * * while ((secs = sleep(secs)) > 0) */ ; sock_send_error(c->sock, "ignored (not fully implemented)\n"); return 0; }
/************************************************************************* * menu_del_item_func * * Deletes an item from a menu * * 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; if (argc != 3 ) { sock_send_error(c->sock, "Usage: menu_del_item <menuid> <itemid>\n"); return 0; } menu_id = argv[1]; item_id = argv[2]; /* Does the client have a menu already ? */ if (!c->menu) { sock_send_error(c->sock, "Client has no menu\n"); return 0; } 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_error(c->sock, "Cannot find menu id\n"); return 0; } item = menu_find_item (c->menu, item_id, true); if (!item) { sock_send_error(c->sock, "Cannot find item\n"); return 0; } menuscreen_inform_item_destruction (item); menu_remove_item (menu, item); menuscreen_inform_item_modified (item->parent); menuitem_destroy (item); /* Was it the last item in the client's menu ? */ if (menu_getfirst_item(c->menu) == NULL) { menuscreen_inform_item_destruction (c->menu); menu_remove_item (main_menu, c->menu); menuscreen_inform_item_modified (main_menu); menu_destroy (c->menu); c->menu = NULL; } sock_send_string(c->sock, "success\n"); return 0; }
/** * Sets the state of the output port (such as on MtxOrb LCDs) * *\verbatim * Usage: output <on|off|int> *\endverbatim */ int output_func(Client *c, int argc, char **argv) { if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: output {on|off|<num>}\n"); return 0; } if (0 == strcmp(argv[1], "on")) output_state = ALL_OUTPUTS_ON; else if (0 == strcmp(argv[1], "off")) output_state = ALL_OUTPUTS_OFF; else { long out; char *endptr; /* Note that there is no valid range set for * output_state; thus a value in the 12 digits * is not considered out of range. */ /* set errno to be able to detect errors in strtol() */ errno = 0; out = strtol(argv[1], &endptr, 0); if (errno) { sock_printf_error(c->sock, "number argument: %s\n", strerror(errno)); return 0; } else if ((*argv[1] != '\0') && (*endptr == '\0')) { output_state = out; } else { sock_send_error(c->sock, "invalid parameter...\n"); return 0; } } sock_send_string(c->sock, "success\n"); /* Makes sense to me to set the output immediately; * however, the outputs are currently set in * draw_screen(screen *s, int timer) * Whatever for? */ /* drivers_output(output_state); */ report(RPT_NOTICE, "output states changed"); return 0; }
/*************************************************************** * Requests the menu system to set the entry point into the menu system. * * Usage: menu_set_main <id> */ int menu_set_main_func (Client * c, int argc, char **argv) { char * menu_id; Menu * menu; debug (RPT_DEBUG, "%s( Client [%d], %s, %s )", __FUNCTION__, c->sock, (argc > 1 ? argv[1] : "<null>"), (argc > 2 ? argv[2] : "<null>") ); if (!c->ack) return 1; if (argc != 2 ) { sock_send_error(c->sock, "Usage: menu_set_main <menuid>\n"); return 0; } menu_id = argv[1]; if ( menu_id[0] == 0 ) { /* No menu specified = client's main menu */ menu = c->menu; } else if (strcmp(menu_id, "_main_") == 0) { menu = NULL; } else { /* A specified menu */ menu = menu_find_item (c->menu, menu_id, true); if ( ! menu) { sock_send_error(c->sock, "Cannot find menu id\n"); return 0; } } menuscreen_set_main(menu); sock_send_string(c->sock, "success\n"); return 0; }
/*************************************************************** * Requests the menu system to display the given menu screen. Depending on * the setting of the LCDPROC_PERMISSIVE_MENU_GOTO it is impossible * to go to a menu of another client (or the server menus). Same * restriction applies to the optional predecessor_id * * Usage: menu_goto <id> [<predecessor_id>] */ int menu_goto_func (Client * c, int argc, char **argv) { char * menu_id; Menu * menu; debug (RPT_DEBUG, "%s( Client [%d], %s, %s )", __FUNCTION__, c->sock, (argc > 1 ? argv[1] : "<null>"), (argc > 2 ? argv[2] : "<null>") ); if (!c->ack) return 1; if ((argc < 2 ) || (argc > 3)) { sock_send_error(c->sock, "Usage: menu_goto <menuid> [<predecessor_id>]\n"); return 0; } menu_id = argv[1]; if ( menu_id[0] == 0 ) { /* No menu specified = client's main menu */ menu = c->menu; } else { /* A specified menu */ menu = menuitem_search(menu_id, c); } if (!menu) { sock_send_error(c->sock, "Cannot find menu id\n"); return 0; } if (argc > 2 ) set_predecessor(menu, argv[2], c); menuscreen_goto (menu); /* Failure is not returned (Robijn) */ sock_send_string(c->sock, "success\n"); return 0; }
/** * The client requests that the server forget about a screen * *\verbatim * Usage: screen_del <screenid> *\endverbatim */ int screen_del_func(Client *c, int argc, char **argv) { int err = 0; Screen *s; if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: screen_del <screenid>\n"); return 0; } debug(RPT_DEBUG, "screen_del: Deleting screen %s", argv[1]); s = client_find_screen(c, argv[1]); if (s == NULL) { sock_send_error(c->sock, "Unknown screen id\n"); return 0; } err = client_remove_screen(c, s); if (err == 0) { sock_send_string(c->sock, "success\n"); } else if (err < 0) { sock_send_error(c->sock, "failed to remove screen\n"); } else { sock_send_error(c->sock, "Unknown screen id\n"); } report(RPT_INFO, "Client on socket %d removed screen \"%s\"", c->sock, s->id); screen_destroy(s); return 0; }
/** * Tells the server the client has another screen to offer * *\verbatim * Usage: screen_add <id> *\endverbatim */ int screen_add_func(Client *c, int argc, char **argv) { int err = 0; Screen *s; if (c->state != ACTIVE) return 1; if (argc != 2) { sock_send_error(c->sock, "Usage: screen_add <screenid>\n"); return 0; } debug(RPT_DEBUG, "screen_add: Adding screen %s", argv[1]); s = client_find_screen(c, argv[1]); if (s != NULL) { sock_send_error(c->sock, "Screen already exists\n"); return 0; } s = screen_create(argv[1], c); if (s == NULL) { sock_send_error(c->sock, "failed to create screen\n"); return 0; } err = client_add_screen(c, s); if (err == 0) { sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "failed to add screen\n"); } report(RPT_INFO, "Client on socket %d added added screen \"%s\"", c->sock, s->id); return 0; }
static int parse_message(const char *str, Client *c) { typedef enum { ST_INITIAL, ST_WHITESPACE, ST_ARGUMENT, ST_FINAL } State; State state = ST_INITIAL; int error = 0; char quote = '\0'; /* The quote used to open a quote string */ int pos = 0; char *arg_space; int argc = 0; char *argv[MAX_ARGUMENTS]; int argpos = 0; CommandFunc function = NULL; debug(RPT_DEBUG, "%s(str=\"%.120s\", client=[%d])", __FUNCTION__, str, c->sock); /* We will create a list of strings that is shorter or equally long as * the original string str. */ arg_space = malloc(strlen(str)+1); if (arg_space == NULL) { report(RPT_ERR, "%s: Could not allocate memory", __FUNCTION__); sock_send_error(c->sock, "error allocating memory!\n"); } argv[0] = arg_space; while ((state != ST_FINAL) && !error) { char ch = str[pos++]; switch (state) { case ST_INITIAL: case ST_WHITESPACE: if (is_whitespace(ch)) break; if (is_final(ch)) { state = ST_FINAL; break; } /* otherwise fall through */ state = ST_ARGUMENT; case ST_ARGUMENT: if (is_final(ch)) { if (quote) error = 2; if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_FINAL; } else if (ch == '\\') { if (str[pos]) { /* We solve quoted chars here right away */ const char escape_chars[] = "nrt"; const char escape_trans[] = "\n\r\t"; char *p = strchr(escape_chars, str[pos]); /* Is it wise to have the characters \n, \r & \t expanded ? * Can the displays deal with them ? */ if (p != NULL) { /* Insert a replacement for the code */ argv[argc][argpos++] = escape_trans[p - escape_chars]; } else { /* Copy char literally */ argv[argc][argpos++] = str[pos]; } pos++; } else { error = 2; /* alternative: argv[argc][argpos++] = ch; */ if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_FINAL; } } else if (is_opening_quote(ch, quote)) { quote = ch; } else if (is_closing_quote(ch, quote)) { quote = '\0'; if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_WHITESPACE; } else if (is_whitespace(ch) && (quote == '\0')) { if (argc >= MAX_ARGUMENTS-1) { error = 1; } else { argv[argc][argpos] = '\0'; argv[argc+1] = argv[argc] + argpos + 1; argc++; argpos = 0; } state = ST_WHITESPACE; } else { argv[argc][argpos++] = ch; } break; case ST_FINAL: /* This will never be reached */ break; } } if (argc < MAX_ARGUMENTS) argv[argc] = NULL; else error = 1; if (error) { sock_send_error(c->sock, "Could not parse command\n"); free(arg_space); return 0; } #if 0 /* show what we have parsed */ int i; for (i = 0; i < argc; i++) { printf("%s%c", argv[i], (i == argc-1) ? '\n' : ' '); } #endif /* Now find and call the appropriate function...*/ function = get_command_function(argv[0]); if (function != NULL) { error = function(c, argc, argv); if (error) { sock_printf_error(c->sock, "Function returned error \"%.40s\"\n", argv[0]); report(RPT_WARNING, "Command function returned an error after command from client on socket %d: %.40s", c->sock, str); } } else { sock_printf_error(c->sock, "Invalid command \"%.40s\"\n", argv[0]); report(RPT_WARNING, "Invalid command from client on socket %d: %.40s", c->sock, str); } free(arg_space); return 0; }
/************************************************************************* * menu_add_item_func * * Adds an item to a menu * * 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 * - ip */ 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; char** argv_set = NULL; debug (RPT_DEBUG, "%s( Client [%d], %s, %s )", __FUNCTION__, c->sock, argv[1], argv[2]); if (!c->ack) return 1; if (!c->name) { sock_send_error(c->sock, "You need to give your client a name first\n"); return 0; } if ((argc < 4 )) { sock_send_error(c->sock, "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 */ report( RPT_INFO, "Client [%d] is using the menu", c->sock ); 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_error(c->sock, "Cannot find menu id\n"); return 0; } item = menu_find_item (c->menu, item_id, true); if (item) { sock_send_error(c->sock, "Item id already in use\n"); return 0; } /* Find menuitem type */ itemtype = menuitem_typename_to_type (argv[3]); if (itemtype == -1) { sock_send_error(c->sock, "Invalid menuitem type\n"); return 0; } /* Is a text given (options don't count)? */ if (argc >= 5 && argv[4][0] != '-') { 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, c, MENURESULT_NONE); break; case MENUITEM_CHECKBOX: item = menuitem_create_checkbox (item_id, menu_commands_handler, text, c, false, false); break; case MENUITEM_RING: item = menuitem_create_ring (item_id, menu_commands_handler, text, c, "", 0); break; case MENUITEM_SLIDER: item = menuitem_create_slider (item_id, menu_commands_handler, text, c, "", "", 0, 100, 1, 25); break; case MENUITEM_NUMERIC: item = menuitem_create_numeric (item_id, menu_commands_handler, text, c, 0, 100, 0); break; case MENUITEM_ALPHA: item = menuitem_create_alpha (item_id, menu_commands_handler, text, c, 0, 0, 10, true, false, true, "-./", ""); break; case MENUITEM_IP: item = menuitem_create_ip (item_id, menu_commands_handler, text, c, 0, "192.168.1.245"); break; default: assert(!"unexpected menuitem type"); } menu_add_item (menu, item); menuscreen_inform_item_modified (menu); sock_send_string(c->sock, "success\n"); /* are there any options (starting with '-')? * - create a temporary argv for menu_set_item() call */ if (argc > 5 || argv[4][0] == '-') { // menu_add_item <menuid> <newitemid> <type> [<text>] // menu_set_item <menuid> <itemid> {<option>}+ int i, j; argv_set = malloc(argc * sizeof(char*)); assert(argv_set); argv_set[0] = "menu_set_item"; for (i = j = 1; i < argc; ++i) { /* skip "type" */ if (i == 3) continue; /* skip "text" */ if (i == 4 && argv[4][0] != '-') continue; argv_set[j++] = argv[i]; } menu_set_item_func(c, j, argv_set); free(argv_set); } return 0; }
/************************************************************************** * menu_set_item_func * Sets the info about a menu item * * For example, text displayed, value, etc... * * 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. * -is_hidden false|true (false) * If the item currently should not appear in a menu. * -prev id () * Sets the predecessor of this item (what happens after "Escape") * * For all except menus: * -next id () * Sets the successor of this item (what happens after "Enter") * * 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. * * ip: * -value <string> * Sets its current value. ("") * -v6 false|true * * 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; /* This table generalizes the options. * The table lists which options can exist for which menu items, * what kind of parameter they should have and where this scanned * parameter should be stored. */ 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 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) }, { -1, "is_hidden", BOOLEAN, offsetof(MenuItem,is_hidden) }, { -1, "prev", STRING, -1 }, { -1, "next", STRING, -1 }, { 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, -1 /*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) }, { MENUITEM_IP, "v6", BOOLEAN, offsetof(MenuItem,data.ip.v6) }, { MENUITEM_IP, "value", STRING, -1 /*offsetof(MenuItem,data.ip.value)*/ }, { -1, NULL, -1, -1 } }; debug (RPT_DEBUG, "%s( Client [%d]: %s)", __FUNCTION__, c->sock, argv2string(argc, argv)); 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; if (!c->ack) return 1; if (argc < 4 ) { sock_send_error(c->sock, "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_error(c->sock, "Cannot find menu id\n"); return 0; } item = menu_find_item (c->menu, item_id, true); if (!item) { sock_send_error(c->sock, "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 { sock_printf_error(c->sock, "Found non-option: \"%.40s\"\n", argv[argnr]); continue; /* Skip to next arg */ } if( option_nr == -1 ) { if( found_option_name ) { sock_printf_error(c->sock, "Option not valid for menuitem type: \"%.40s\"\n", argv[argnr]); } else { sock_printf_error(c->sock, "Unknown option: \"%.40s\"\n", argv[argnr]); } 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 ) { sock_printf_error(c->sock, "Missing value at option: \"%.40s\"\n", argv[argnr]); 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 ); } else if (strcmp(argv[argnr], "-prev") == 0) { set_predecessor(item, string_value, c); } else if (strcmp(argv[argnr], "-next") == 0) { set_successor(item, string_value, c); } break; } switch( error ) { case 1: sock_printf_error(c->sock, "Could not interpret value at option: \"%.40s\"\n", argv[argnr]); 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 ) { set_successor(item, "_none_", c); } else if( strcmp( argv[argnr+1], "close" ) == 0 ) { set_successor(item, "_close_", c); } else if( strcmp( argv[argnr+1], "quit" ) == 0 ) { set_successor(item, "_quit_", c); } 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; case MENUITEM_IP: if( strcmp( argv[argnr]+1, "v6" ) == 0 ) { char * new_buf; /* set max lenth depending ob boolean option v6 */ item->data.ip.maxlength = (bool_value == 0) ? 15 : 39; new_buf = malloc(item->data.ip.maxlength + 1 ); strncpy( new_buf, item->data.ip.value, item->data.ip.maxlength); new_buf[item->data.ip.maxlength] = '\0'; /* terminate */ free( item->data.ip.value ); item->data.ip.value = new_buf; free( item->data.ip.edit_str ); item->data.ip.edit_str = malloc( item->data.ip.maxlength +1); item->data.ip.edit_str[0] = '\0'; } else if( strcmp( argv[argnr]+1, "value" ) == 0 ) { strncpy( item->data.ip.value, string_value, item->data.ip.maxlength ); item->data.ip.value[item->data.ip.maxlength] = '\0'; /* terminate */ } menuitem_reset (item); break; default: break; } switch( error ) { case 1: sock_printf_error(c->sock, "Could not interpret value at option: \"%.40s\"\n", argv[argnr]); continue; /* Skip to next arg and retry it as an option */ case 2: sock_printf_error(c->sock, "Value out of range at option: \"%.40s\"\n", argv[argnr]); argnr ++; continue; /* Skip current option and the invalid value */ } menuscreen_inform_item_modified (item); if( option_table[option_nr].attr_type != NOVALUE ) { /* Skip the now used argument */ argnr ++; } } sock_send_string(c->sock, "success\n"); return 0; }
/** * Tells the server the client would NOT like to accept keypresses * of a particular type when the given screen is active on the display * *\verbatim * Usage: screen_del_key <screenid> <keylist> *\endverbatim */ int screen_del_key_func(Client *c, int argc, char **argv) { Screen *s; /* Attached to a specific screen */ char *id; /* Screen ID */ char *keys; /* Keys wanted */ if (c->state != ACTIVE) return 1; if (argc != 3) { switch (argc) { case 1: sock_send_error(c->sock, "Usage: screen_del_key <screenid> <keylist>\n"); break; case 2: sock_send_error(c->sock, "You must specify a key list\n"); break; default: sock_send_error(c->sock, "Too many parameters\n"); break; } return 0; } id = argv[1]; keys = argv[2]; debug(RPT_DEBUG, "screen_del_key: Deleting key(s) %s from screen %s", keys, id); /* Find the screen*/ s = client_find_screen(c, id); if (s == NULL) { sock_send_error(c->sock, "Unknown screen id\n"); return 0; } /* Do we have keys?*/ if (s->keys != NULL) { /* Have 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 s->keys */ char *from; char *to; to = from = s->keys; while (*from != '\0') { /* Is this key to be deleted from the list? */ if (strchr(keys, *from) == 0) { /* Yes, skip it */ ++from; } else { /* No, save it */ *to++ = *from++; } } to = '\0'; /* terminates the new keys string...*/ } sock_send_string(c->sock, "success\n"); return 0; }
/** * Tells the server the client would like to accept keypresses * of a particular type when the given screen is active on the display * *\verbatim * Usage: screen_add_key <screenid> <keylist> *\endverbatim */ int screen_add_key_func(Client *c, int argc, char **argv) { Screen *s; /* Attached to a specific screen */ char *id; /* Screen ID */ char *keys; /* Keys wanted */ if (c->state != ACTIVE) return 1; if (argc != 3) { switch (argc) { case 1: sock_send_error(c->sock, "Usage: screen_add_key <screenid> <keylist>\n"); break; case 2: sock_send_error(c->sock, "You must specify a key list\n"); break; default: sock_send_error(c->sock, "Too many parameters...\n"); break; } return 0; } id = argv[1]; keys = argv[2]; debug(RPT_DEBUG, "screen_add_key: Adding key(s) %s to screen %s", keys, id); /* Find the screen*/ s = client_find_screen(c, id); if (!s) { sock_send_error(c->sock, "Unknown screen id\n"); return 0; } /* Save the keys*/ if (s->keys == NULL) { /* Save supplied key list*/ s->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_keys; new_keys = realloc(s->keys, strlen(s->keys) + strlen(keys) +1); if (new_keys) { strcpy(new_keys, s->keys); strcat(new_keys, keys); free(s->keys); s->keys = new_keys; } else { sock_send_error(c->sock, "Could not add new keys\n"); return 0; } } if (s->keys == NULL) sock_send_error(c->sock, "failed\n"); else sock_send_string(c->sock, "success\n"); return 0; }
/** * Configures info about a particular screen, such as its * name, priority, or duration * *\verbatim * Usage: screen_set <id> [-name <name>] [-wid <width>] [-hgt <height>] * [-priority <prio>] [-duration <int>] [-timeout <int>] * [-heartbeat <type>] [-backlight <type>] * [-cursor <type>] [-cursor_x <xpos>] [-cursor_y <ypos>] *\endverbatim */ int screen_set_func(Client *c, int argc, char **argv) { int i; int number; char *id; Screen * s; if (c->state != ACTIVE) return 1; if (argc == 1) { sock_send_error(c->sock, "Usage: screen_set <id> [-name <name>]" " [-wid <width>] [-hgt <height>] [-priority <prio>]" " [-duration <int>] [-timeout <int>]" " [-heartbeat <type>] [-backlight <type>]" " [-cursor <type>]" " [-cursor_x <xpos>] [-cursor_y <ypos>]\n"); return 0; } else if (argc == 2) { sock_send_error(c->sock, "What do you want to set?\n"); return 0; } id = argv[1]; s = client_find_screen(c, id); if (s == NULL) { sock_send_error(c->sock, "Unknown screen id\n"); return 0; } /* Handle the rest of the parameters*/ for (i = 2; i < argc; i++) { char *p = argv[i]; /* ignore leading '-' in options: we allow both forms */ if (*p == '-') p++; /* Handle the "name" parameter*/ if (strcmp(p, "name") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: name=\"%s\"", argv[i]); /* set the name...*/ if (s->name != NULL) free(s->name); s->name = strdup(argv[i]); sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-name requires a parameter\n"); } } /* Handle the "priority" parameter*/ else if (strcmp(p, "priority") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: priority=\"%s\"", argv[i]); /* first try to interpret it as a number */ number = atoi(argv[i]); if (number > 0) { if (number <= 64) number = PRI_FOREGROUND; else if (number < 192) number = PRI_INFO; else number = PRI_BACKGROUND; } else { /* Try if it is a priority class */ number = screen_pri_name_to_pri(argv[i]); } if (number >= 0) { s->priority = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "invalid argument at -priority\n"); } } else { sock_send_error(c->sock, "-priority requires a parameter\n"); } } /* Handle the "duration" parameter*/ else if (strcmp(p, "duration") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: duration=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); if (number > 0) s->duration = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-duration requires a parameter\n"); } } /* Handle the "heartbeat" parameter*/ else if (strcmp(p, "heartbeat") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: heartbeat=\"%s\"", argv[i]); /* set the heartbeat type...*/ if (0 == strcmp(argv[i], "on")) s->heartbeat = HEARTBEAT_ON; else if (0 == strcmp(argv[i], "off")) s->heartbeat = HEARTBEAT_OFF; else if (0 == strcmp(argv[i], "open")) s->heartbeat = HEARTBEAT_OPEN; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-heartbeat requires a parameter\n"); } } /* Handle the "wid" parameter*/ else if (strcmp(p, "wid") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: wid=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); if (number > 0) s->width = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-wid requires a parameter\n"); } } /* Handle the "hgt" parameter*/ else if (strcmp(p, "hgt") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: hgt=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); if (number > 0) s->height = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-hgt requires a parameter\n"); } } /* Handle the "timeout" parameter*/ else if (strcmp(p, "timeout") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: timeout=\"%s\"", argv[i]); /* set the duration...*/ number = atoi(argv[i]); /* Add the timeout value (count of TIME_UNITS) * to struct, TIME_UNIT is 1/8th of a second */ if (number > 0) { s->timeout = number; report(RPT_NOTICE, "Timeout set."); } sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-timeout requires a parameter\n"); } } /* Handle the "backlight" parameter*/ else if (strcmp(p, "backlight") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: backlight=\"%s\"", argv[i]); /* set the backlight status based on what the client has set*/ switch(c->backlight) { case BACKLIGHT_OPEN: if (strcmp("on", argv[i]) == 0) s->backlight = BACKLIGHT_ON; if (strcmp("off", argv[i]) == 0) s->backlight = BACKLIGHT_OFF; if (strcmp("toggle", argv[i]) == 0) { if (s->backlight == BACKLIGHT_ON) s->backlight = BACKLIGHT_OFF; else if (s-backlight == BACKLIGHT_OFF) s->backlight = BACKLIGHT_ON; } if (strcmp("blink", argv[i]) == 0) s->backlight |= BACKLIGHT_BLINK; if (strcmp("flash", argv[i]) == 0) s->backlight |= BACKLIGHT_FLASH; break; default: /*If the backlight is not OPEN then inherit its state*/ s->backlight = c->backlight; break; } sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-backlight requires a parameter\n"); } } /* Handle the "cursor" parameter */ else if (strcmp(p, "cursor") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: cursor=\"%s\"", argv[i]); /* set the heartbeat type...*/ if (0 == strcmp(argv[i], "off")) s->cursor = CURSOR_OFF; if (0 == strcmp(argv[i], "on")) s->cursor = CURSOR_DEFAULT_ON; if (0 == strcmp(argv[i], "under")) s->cursor = CURSOR_UNDER; if (0 == strcmp(argv[i], "block")) s->cursor = CURSOR_BLOCK; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "-cursor requires a parameter\n"); } } /* Handle the "cursor_x" parameter */ else if (strcmp(p, "cursor_x") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: cursor_x=\"%s\"", argv[i]); /* set the position...*/ number = atoi(argv[i]); if (number > 0 && number <= s->width) { s->cursor_x = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "Cursor position outside screen\n"); } } else { sock_send_error(c->sock, "-cursor_x requires a parameter\n"); } } /* Handle the "cursor_y" parameter */ else if (strcmp(p, "cursor_y") == 0) { if (argc > i + 1) { i++; debug(RPT_DEBUG, "screen_set: cursor_y=\"%s\"", argv[i]); /* set the position...*/ number = atoi(argv[i]); if (number > 0 && number <= s->height) { s->cursor_y = number; sock_send_string(c->sock, "success\n"); } else { sock_send_error(c->sock, "Cursor position outside screen\n"); } } else { sock_send_error(c->sock, "-cursor_y requires a parameter\n"); } } else sock_send_error(c->sock, "invalid parameter\n"); }/* done checking argv*/ return 0; }