/** * Print printf-like formatted output to logfile and sends it to the client. * \note don't add a the "huh? " to the message. This is done by this * method * \param fd socket * \param format a printf format */ int sock_printf_error(int fd, const char *format, .../*args*/ ) { static const char huh[] = "huh? "; char buf[MAXMSG]; va_list ap; int size = 0; strncpy(buf, huh, sizeof(huh)); // note: sizeof(huh) < MAXMSG va_start(ap, format); size = vsnprintf(buf + (sizeof(huh)-1), sizeof(buf) - (sizeof(huh)-1), format, ap); buf[sizeof(buf)-1] = '\0'; va_end(ap); if (size < 0) { //report(RPT_ERR, "sock_printf_error: vsnprintf failed"); return -1; } //if (size >= sizeof(buf) - (sizeof(huh)-1)) //report(RPT_WARNING, "sock_printf_error: vsnprintf truncated message"); //report(RPT_ERR, "error: %s", buf); return sock_send_string(fd, buf); }
/************************************************************************* * 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; }
/** * Does nothing, returns "noop complete" message. * * This is useful for shell scripts or programs that want to talk * with LCDproc and not get deadlocked. Send a noop after each * command and look for the "noop complete" message. */ int noop_func(Client *c, int argc, char **argv) { if (c->state != ACTIVE) return 1; sock_send_string(c->sock, "noop complete\n"); return 0; }
/* Send the given line down the socket with CRLF appended. * Returns 0 on success or SOCK_* on failure. */ int sock_sendline(nsocket *sock, const char *line) { char *buffer; int ret; CONCAT2(buffer, line, "\r\n"); ret = sock_send_string(sock, buffer); free(buffer); return ret; }
/** * 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; }
void screenlist_switch(Screen *s) { Client *c; char str[256]; if (!s) return; report(RPT_DEBUG, "%s(s=[%.40s])", __FUNCTION__, s->id); if (s == current_screen) { /* Nothing to be done */ return; } if (current_screen) { c = current_screen->client; if (c) { /* Tell the client we're not listening any more...*/ snprintf(str, sizeof(str), "ignore %s\n", current_screen->id); sock_send_string(c->sock, str); } else { /* It's a server screen, no need to inform it. */ } } c = s->client; if (c) { /* Tell the client we're paying attention...*/ snprintf(str, sizeof(str), "listen %s\n", s->id); sock_send_string(c->sock, str); } else { /* It's a server screen, no need to inform it. */ } report(RPT_INFO, "%s: switched to screen [%.40s]", __FUNCTION__, s->id); current_screen = s; current_screen_start_time = timer; }
/** * MiniClock Screen displays the current time with hours & minutes only * *\verbatim * * +--------------------+ +--------------------+ * | | | 11:32 | * | 11:32 | | | * | | +--------------------+ * | | * +--------------------+ * *\endverbatim * * \param rep Time since last screen update * \param display 1 if screen is visible or data should be updated * \param flags_ptr Mode flags * \return Always 0 */ int mini_clock_screen(int rep, int display, int *flags_ptr) { char now[40]; time_t thetime; struct tm *rtime; static const char *timeFormat = NULL; static int heartbeat = 0; int xoffs; /* toggle colon display */ heartbeat ^= 1; if ((*flags_ptr & INITIALIZED) == 0) { *flags_ptr |= INITIALIZED; /* get config values */ timeFormat = config_get_string("MiniClock", "TimeFormat", 0, "%H:%M"); sock_send_string(sock, "screen_add N\n"); sock_send_string(sock, "screen_set N -name {Mini Clock Screen} -heartbeat off\n"); sock_send_string(sock, "widget_add N one string\n"); } time(&thetime); rtime = localtime(&thetime); if (strftime(now, sizeof(now), timeFormat, rtime) == 0) *now = '\0'; tickTime(now, heartbeat); xoffs = (lcd_wid > strlen(now)) ? (((lcd_wid - strlen(now)) / 2) + 1) : 1; sock_printf(sock, "widget_set N one %d %d {%s}\n", xoffs, (lcd_hgt / 2), now); return 0; } /* End mini_clock_screen() */
void input_send_to_client(Client *c, const char *key) { char *s; size_t size = strlen(key) + sizeof("key %s\n"); // this is large enough debug(RPT_DEBUG, "%s(client=[%d], key=\"%.40s\")", __FUNCTION__, c->sock, key); /* Allocate just as much as we need */ s = calloc(1, size); if (s != NULL) { snprintf(s, size, "key %s\n", key); sock_send_string(c->sock, s); free(s); } else report(RPT_ERR, "%s: malloc failure", __FUNCTION__); }
/** * Send printf-like formatted output. * \param fd Socket file descriptor * \param format Format string * \param ... Arguments to the format string * \return Number of bytes sent. */ int sock_printf(int fd, const char *format, .../*args*/ ) { char buf[MAXMSG]; va_list ap; int size = 0; va_start(ap, format); size = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); if (size < 0) { //report(RPT_ERR, "sock_printf: vsnprintf failed"); return -1; } //if (size > sizeof(buf)) //report(RPT_WARNING, "sock_printf: vsnprintf truncated message"); return sock_send_string(fd, buf); }
/*************************************************************** * 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; }
////////////////////////////////////////////////////////////////////////// // CPU screen shows info about percentage of the CPU being used // int cpu_smp_screen (int rep, int display, int *flags_ptr) { #undef CPU_BUF_SIZE #define CPU_BUF_SIZE 4 int z; static float cpu[MAX_CPUS][CPU_BUF_SIZE + 1]; // last buffer is scratch load_type load[MAX_CPUS]; int num_cpus = MAX_CPUS; int bar_size; int lines_used; // get SMP load - inform about max #CPUs allowed machine_get_smpload(load, &num_cpus); // restrict num_cpus to max. twice the display height if (num_cpus > 2 * lcd_hgt) num_cpus = 2 * lcd_hgt; // 2 CPUs per line if more CPUs than lines bar_size = (num_cpus > lcd_hgt) ? (lcd_wid / 2 - 6) : (lcd_wid - 6); lines_used = (num_cpus > lcd_hgt) ? (num_cpus + 1) / 2 : num_cpus; if ((*flags_ptr & INITIALIZED) == 0) { *flags_ptr |= INITIALIZED; sock_send_string(sock, "screen_add P\n"); // print title if he have room for it if (lines_used < lcd_hgt) { sock_send_string(sock, "widget_add P title title\n"); sock_printf(sock, "widget_set P title {SMP CPU %s}\n", get_hostname()); } else { sock_send_string(sock, "screen_set P -heartbeat off\n"); } sock_printf(sock, "screen_set P -name {CPU Use: %s}\n", get_hostname()); for (z = 0; z < num_cpus; z++) { int y_offs = (lines_used < lcd_hgt) ? 2 : 1; int x = (num_cpus > lcd_hgt) ? ((z % 2) * (lcd_wid/2) + 1) : 1; int y = (num_cpus > lcd_hgt) ? (z/2 + y_offs) : (z + y_offs); sock_printf(sock, "widget_add P cpu%d_title string\n", z); sock_printf(sock, "widget_set P cpu%d_title %d %d \"CPU%d[%*s]\"\n", z, x, y, z, bar_size, ""); sock_printf(sock, "widget_add P cpu%d_bar hbar\n", z); } return 0; } for (z = 0; z < num_cpus; z++) { int y_offs = (lines_used < lcd_hgt) ? 2 : 1; int x = (num_cpus > lcd_hgt) ? ((z % 2) * (lcd_wid/2) + 6) : 6; int y = (num_cpus > lcd_hgt) ? (z/2 + y_offs) : (z + y_offs); float value = 0.0; int i, n; // Shift values over by one for (i = 0; i < (CPU_BUF_SIZE - 1); i++) cpu[z][i] = cpu[z][i + 1]; // Read new data cpu[z][CPU_BUF_SIZE-1] = (load[z].total > 0L) ? (((float) load[z].user + (float) load[z].system + (float) load[z].nice) / (float) load[z].total) * 100.0 : 0.0; // Average values for final result for (i = 0; i < CPU_BUF_SIZE; i++) { value += cpu[z][i]; } value /= CPU_BUF_SIZE; n = (int) ((value * lcd_cellwid * bar_size) / 100.0 + 0.5); sock_printf(sock, "widget_set P cpu%d_bar %d %d %d\n", z, x, y, n); } return 0; } // End cpu_screen()
int menus_init() { int k; for (k = 0; sequence[k].which; k++) { if (sequence[k].longname) { sock_printf(sock, "menu_add_item {} %c checkbox {%s} -value %s\n", sequence[k].which, sequence[k].longname, (sequence[k].flags & ACTIVE) ? "on" : "off"); } } #ifdef LCDPROC_CLIENT_TESTMENUS /* * to be entered on escape from test_menu (but overwritten for * test_{checkbox,ring} */ sock_send_string(sock, "menu_add_item {} ask menu {Leave menus?} -is_hidden true\n"); sock_send_string(sock, "menu_add_item {ask} ask_yes action {Yes} -next _quit_\n"); sock_send_string(sock, "menu_add_item {ask} ask_no action {No} -next _close_\n"); sock_send_string(sock, "menu_add_item {} test menu {Test}\n"); sock_send_string(sock, "menu_add_item {test} test_action action {Action}\n"); sock_send_string(sock, "menu_add_item {test} test_checkbox checkbox {Checkbox}\n"); sock_send_string(sock, "menu_add_item {test} test_ring ring {Ring} -strings {one\ttwo\tthree}\n"); sock_send_string(sock, "menu_add_item {test} test_slider slider {Slider} -mintext < -maxtext > -value 50\n"); sock_send_string(sock, "menu_add_item {test} test_numeric numeric {Numeric} -value 42\n"); sock_send_string(sock, "menu_add_item {test} test_alpha alpha {Alpha} -value abc\n"); sock_send_string(sock, "menu_add_item {test} test_ip ip {IP} -v6 false -value 192.168.1.1\n"); sock_send_string(sock, "menu_add_item {test} test_menu menu {Menu}\n"); sock_send_string(sock, "menu_add_item {test_menu} test_menu_action action {Submenu's action}\n"); /* * no successor for menus. Since test_checkbox and test_ring have * their own predecessors defined the "ask" rule will not work for * them. */ sock_send_string(sock, "menu_set_item {} test -prev {ask}\n"); sock_send_string(sock, "menu_set_item {test} test_action -next {test_checkbox}\n"); sock_send_string(sock, "menu_set_item {test} test_checkbox -next {test_ring} -prev test_action\n"); sock_send_string(sock, "menu_set_item {test} test_ring -next {test_slider} -prev {test_checkbox}\n"); sock_send_string(sock, "menu_set_item {test} test_slider -next {test_numeric} -prev {test_ring}\n"); sock_send_string(sock, "menu_set_item {test} test_numeric -next {test_alpha} -prev {test_slider}\n"); sock_send_string(sock, "menu_set_item {test} test_alpha -next {test_ip} -prev {test_numeric}\n"); sock_send_string(sock, "menu_set_item {test} test_ip -next {test_menu} -prev {test_alpha}\n"); sock_send_string(sock, "menu_set_item {test} test_menu_action -next {_close_}\n"); #endif /* LCDPROC_CLIENT_TESTMENUS */ return 0; }
int main(int argc, char **argv) { int cfgresult; int c; /* set locale for cwdate & time formatting in chrono.c */ setlocale(LC_TIME, ""); /* get uname information */ if (uname(&unamebuf) == -1) { perror("uname"); return (EXIT_FAILURE); } /* setup error handlers */ signal(SIGINT, exit_program); /* Ctrl-C */ signal(SIGTERM, exit_program); /* "regular" kill */ signal(SIGHUP, exit_program); /* kill -HUP */ signal(SIGPIPE, exit_program); /* write to closed socket */ signal(SIGKILL, exit_program); /* kill -9 [cannot be trapped; but ...] */ /* No error output from getopt */ opterr = 0; /* get options from command line */ while ((c = getopt(argc, argv, "s:p:e:c:fhv")) > 0) { char *end; switch (c) { /* c is for config file */ case 'c': configfile = optarg; break; /* s is for server */ case 's': server = optarg; break; /* p is for port */ case 'p': port = strtol(optarg, &end, 0); if ((*optarg == '\0') || (*end != '\0') || (port <= 0) || (port >= 0xFFFF)) { fprintf(stderr, "Illegal port value %s\n", optarg); exit(EXIT_FAILURE); } break; case 'e': islow = strtol(optarg, &end, 0); if ((*optarg == '\0') || (*end != '\0') || (islow < 0)) { fprintf(stderr, "Illegal delay value %s\n", optarg); exit(EXIT_FAILURE); } break; case 'f': foreground = TRUE; break; case 'h': HelpScreen(EXIT_SUCCESS); break; case 'v': fprintf(stderr, "LCDproc %s\n", version); exit(EXIT_SUCCESS); break; /* otherwise... Get help! */ case '?': /* unknown option or missing argument */ /* FALLTHROUGH */ default: HelpScreen(EXIT_FAILURE); break; } } /* Read config file */ cfgresult = process_configfile(configfile); if (cfgresult < 0) { fprintf(stderr, "Error reading config file\n"); exit(EXIT_FAILURE); } /* Set default reporting options */ if (report_dest == UNSET_INT) report_dest = DEFAULT_REPORTDEST; if (report_level == UNSET_INT) report_level = DEFAULT_REPORTLEVEL; /* Set reporting settings */ set_reporting("lcdproc", report_level, report_dest); /* parse non-option arguments: modes to add/delete */ if (argc > max(optind, 1)) { int i; /* * if no config file was read, ignore hard coded default * modes */ if (cfgresult == 0) clear_modes(); /* turn additional options on or off (using ! as prefix) */ for (i = max(optind, 1); i < argc; i++) { int state = (*argv[i] == '!') ? 0 : 1; char *name = (state) ? argv[i] : argv[i] + 1; int shortname = (strlen(name) == 1) ? name[0] : '\0'; int found = set_mode(shortname, name, state); if (!found) { fprintf(stderr, "Invalid Screen: %s\n", name); return (EXIT_FAILURE); } } } if (server == NULL) server = DEFAULT_SERVER; /* Connect to the server... */ sock = sock_connect(server, port); if (sock < 0) { fprintf(stderr, "Error connecting to LCD server %s on port %d.\n" "Check to see that the server is running and operating normally.\n", server, port); return (EXIT_FAILURE); } sock_send_string(sock, "hello\n"); usleep(500000); /* wait for the server to say hi. */ /* We grab the real values below, from the "connect" line. */ lcd_wid = 20; lcd_hgt = 4; lcd_cellwid = 5; lcd_cellhgt = 8; if (foreground != TRUE) { if (daemon(1, 0) != 0) { fprintf(stderr, "Error: daemonize failed\n"); return (EXIT_FAILURE); } if (pidfile != NULL) { FILE *pidf = fopen(pidfile, "w"); if (pidf) { fprintf(pidf, "%d\n", (int)getpid()); fclose(pidf); pidfile_written = TRUE; } else { fprintf(stderr, "Error creating pidfile %s: %s\n", pidfile, strerror(errno)); return (EXIT_FAILURE); } } } /* Init the status gatherers... */ mode_init(); /* And spew stuff! */ main_loop(); exit_program(EXIT_SUCCESS); /* NOTREACHED */ return EXIT_SUCCESS; }
/** * TimeDate Screen displays current time and date, uptime, OS ver... * *\verbatim * * +--------------------+ +--------------------+ * |## Linux 2.6.11 ###@| |### TIME: myhost ##@| * |Up xxx days hh:mm:ss| |17.05.2005 11:32:57a| * | Wed May 17, 1998 | +--------------------+ * |11:32:57a 100% idle| * +--------------------+ * *\endverbatim * * \param rep Time since last screen update * \param display 1 if screen is visible or data should be updated * \param flags_ptr Mode flags * \return Always 0 */ int time_screen(int rep, int display, int *flags_ptr) { char now[40]; char today[40]; int xoffs; int days, hour, min, sec; static int heartbeat = 0; static const char *timeFormat = NULL; static const char *dateFormat = NULL; time_t thetime; struct tm *rtime; double uptime, idle; if ((*flags_ptr & INITIALIZED) == 0) { *flags_ptr |= INITIALIZED; /* get config values */ timeFormat = config_get_string("TimeDate", "TimeFormat", 0, "%H:%M:%S"); dateFormat = config_get_string("TimeDate", "DateFormat", 0, "%b %d %Y"); sock_send_string(sock, "screen_add T\n"); sock_printf(sock, "screen_set T -name {Time Screen: %s}\n", get_hostname()); sock_send_string(sock, "widget_add T title title\n"); sock_send_string(sock, "widget_add T one string\n"); if (lcd_hgt >= 4) { sock_send_string(sock, "widget_add T two string\n"); sock_send_string(sock, "widget_add T three string\n"); /* write title bar: OS name, OS version, hostname */ sock_printf(sock, "widget_set T title {%s %s: %s}\n", get_sysname(), get_sysrelease(), get_hostname()); } else { /* write title bar: hostname */ sock_printf(sock, "widget_set T title {TIME: %s}\n", get_hostname()); } } /* toggle colon display */ heartbeat ^= 1; time(&thetime); rtime = localtime(&thetime); if (strftime(today, sizeof(today), dateFormat, rtime) == 0) *today = '\0'; if (strftime(now, sizeof(now), timeFormat, rtime) == 0) *now = '\0'; tickTime(now, heartbeat); if (lcd_hgt >= 4) { char tmp[40]; /* should be large enough */ machine_get_uptime(&uptime, &idle); /* display the uptime... */ days = (int) uptime / 86400; hour = ((int) uptime % 86400) / 3600; min = ((int) uptime % 3600) / 60; sec = ((int) uptime % 60); if (lcd_wid >= 20) sprintf(tmp, "Up %3d day%s %02d:%02d:%02d", days, ((days != 1) ? "s" : ""), hour, min, sec); else sprintf(tmp, "Up %dd %02d:%02d:%02d", days, hour, min, sec); xoffs = (lcd_wid > strlen(tmp)) ? ((lcd_wid - strlen(tmp)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set T one %i 2 {%s}\n", xoffs, tmp); /* display the date */ xoffs = (lcd_wid > strlen(today)) ? ((lcd_wid - strlen(today)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set T two %i 3 {%s}\n", xoffs, today); /* display the time & idle time... */ sprintf(tmp, "%s %3i%% idle", now, (int) idle); xoffs = (lcd_wid > strlen(tmp)) ? ((lcd_wid - strlen(tmp)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set T three %i 4 {%s}\n", xoffs, tmp); } else { /* 2 line version of the screen */ xoffs = (lcd_wid > (strlen(today) + strlen(now) + 1)) ? ((lcd_wid - ((strlen(today) + strlen(now) + 1))) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set T one %i 2 {%s %s}\n", xoffs, today, now); } return 0; } /* End time_screen() */
/** * Big Clock Screen displays current time... * *\verbatim * * +--------------------+ * | _ _ _ _ | * | ||_ . _||_|. _| || * | ||_|. _| |.|_ || * | | * +--------------------+ * *\endverbatim * * \param rep Time since last screen update * \param display 1 if screen is visible or data should be updated * \param flags_ptr Mode flags * \return Always 0 */ int big_clock_screen(int rep, int display, int *flags_ptr) { time_t thetime; struct tm *rtime; int pos[] = {1, 4, 8, 11, 15, 18}; char fulltxt[16]; static char old_fulltxt[16]; static int heartbeat = 0; static int TwentyFourHour = 1; int j = 0; int digits = (lcd_wid >= 20) ? 6 : 4; int xoffs = (lcd_wid + 1 - (pos[digits - 1] + 2)) / 2; /* toggle colon display */ heartbeat ^= 1; if ((*flags_ptr & INITIALIZED) == 0) { *flags_ptr |= INITIALIZED; sock_send_string(sock, "screen_add K\n"); sock_send_string(sock, "screen_set K -name {Big Clock Screen} -heartbeat off\n"); sock_send_string(sock, "widget_add K d0 num\n"); sock_send_string(sock, "widget_add K d1 num\n"); sock_send_string(sock, "widget_add K d2 num\n"); sock_send_string(sock, "widget_add K d3 num\n"); sock_send_string(sock, "widget_add K c0 num\n"); if (digits > 4) { sock_send_string(sock, "widget_add K d4 num\n"); sock_send_string(sock, "widget_add K d5 num\n"); sock_send_string(sock, "widget_add K c1 num\n"); } strcpy(old_fulltxt, " "); } time(&thetime); rtime = localtime(&thetime); sprintf(fulltxt, "%02d%02d%02d", ((TwentyFourHour) ? rtime->tm_hour : (((rtime->tm_hour + 11) % 12) + 1)), rtime->tm_min, rtime->tm_sec); for (j = 0; j < digits; j++) { if (fulltxt[j] != old_fulltxt[j]) { sock_printf(sock, "widget_set K d%d %d %c\n", j, xoffs+pos[j], fulltxt[j]); old_fulltxt[j] = fulltxt[j]; } } if (heartbeat) { /* 10 means: colon */ sock_printf(sock, "widget_set K c0 %d 10\n", xoffs + 7); if (digits > 4) sock_printf(sock, "widget_set K c1 %d 10\n", xoffs + 14); } else { /* kludge: use illegal number to clear colon display */ sock_printf(sock, "widget_set K c0 %d 11\n", xoffs + 7); if (digits > 4) sock_printf(sock, "widget_set K c1 %d 11\n", xoffs + 14); } return 0; } /* End big_clock_screen() */
/** * Uptime Screen shows info about system uptime and OS version * *\verbatim * * +--------------------+ +--------------------+ * |## SYSTEM UPTIME ##@| |# Linux 2.6.11: my#@| * | myhost | | xxx days hh:mm:ss | * | xxx days hh:mm:ss | +--------------------+ * | Linux 2.6.11 | * +--------------------+ * *\endverbatim * * \param rep Time since last screen update * \param display 1 if screen is visible or data should be updated * \param flags_ptr Mode flags * \return Always 0 */ int uptime_screen(int rep, int display, int *flags_ptr) { int xoffs; int days, hour, min, sec; double uptime, idle; static int heartbeat = 0; char tmp[257]; /* should be large enough for host name */ if ((*flags_ptr & INITIALIZED) == 0) { *flags_ptr |= INITIALIZED; sock_send_string(sock, "screen_add U\n"); sock_printf(sock, "screen_set U -name {Uptime Screen: %s}\n", get_hostname()); sock_send_string(sock, "widget_add U title title\n"); if (lcd_hgt >= 4) { sock_send_string(sock, "widget_add U one string\n"); sock_send_string(sock, "widget_add U two string\n"); sock_send_string(sock, "widget_add U three string\n"); sock_send_string(sock, "widget_set U title {SYSTEM UPTIME}\n"); sprintf(tmp, "%s", get_hostname()); xoffs = (lcd_wid > strlen(tmp)) ? (((lcd_wid - strlen(tmp)) / 2) + 1) : 1; sock_printf(sock, "widget_set U one %i 2 {%s}\n", xoffs, tmp); sprintf(tmp, "%s %s", get_sysname(), get_sysrelease()); xoffs = (lcd_wid > strlen(tmp)) ? (((lcd_wid - strlen(tmp)) / 2) + 1) : 1; sock_printf(sock, "widget_set U three %i 4 {%s}\n", xoffs, tmp); } else { sock_send_string(sock, "widget_add U one string\n"); sock_printf(sock, "widget_set U title {%s %s: %s}\n", get_sysname(), get_sysrelease(), get_hostname()); } } /* toggle colon display */ heartbeat ^= 1; machine_get_uptime(&uptime, &idle); days = (int) uptime / 86400; hour = ((int) uptime % 86400) / 3600; min = ((int) uptime % 3600) / 60; sec = ((int) uptime % 60); if (lcd_wid >= 20) sprintf(tmp, "%d day%s %02d:%02d:%02d", days, ((days != 1) ? "s" : ""), hour, min, sec); else sprintf(tmp, "%dd %02d:%02d:%02d", days, hour, min, sec); if (display) { xoffs = (lcd_wid > strlen(tmp)) ? (((lcd_wid - strlen(tmp)) / 2) + 1) : 1; if (lcd_hgt >= 4) sock_printf(sock, "widget_set U two %d 3 {%s}\n", xoffs, tmp); else sock_printf(sock, "widget_set U one %d 2 {%s}\n", xoffs, tmp); } return 0; } /* End uptime_screen() */
/** * 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; }
/** * Gives disk stats. * Stays onscreen until it is done; rolls over all mounted file systems * *\verbatim * * +--------------------+ +--------------------+ * |## DISKS: myhost ##@| |## DISKS: myhost ##@| * |/ 18.3G E-- F| |-local 18.3G E--- F| * |-local 18.3G E--- F| +--------------------+ * |/boot 949.6M E- F| * +--------------------+ * *\endverbatim * * \param rep Time since last screen update * \param display 1 if screen is visible or data should be updated * \param flags_ptr Mode flags * \return Always 0 */ int disk_screen(int rep, int display, int *flags_ptr) { static mounts_type mnt[256]; static int count = 0; /* Holds info to display (avoid recalculating it) */ struct disp { char dev[16]; char cap[8]; int full; } table[256]; int i; static int num_disks = 0; static int dev_wid = 6; static int gauge_wid = 6; #define huge long long int huge size; if ((*flags_ptr & INITIALIZED) == 0) { *flags_ptr |= INITIALIZED; dev_wid = (lcd_wid >= 20) ? (lcd_wid - 8) / 2 : (lcd_wid / 2) - 1; gauge_wid = (lcd_wid >= 20) ? (lcd_wid - dev_wid - 10) : (lcd_wid - dev_wid - 3); sock_send_string(sock, "screen_add D\n"); sock_printf(sock, "screen_set D -name {Disk Use: %s}\n", get_hostname()); sock_send_string(sock, "widget_add D title title\n"); sock_printf(sock, "widget_set D title {DISKS: %s}\n", get_hostname()); sock_send_string(sock, "widget_add D f frame\n"); sock_printf(sock, "widget_set D f 1 2 %i %i %i %i v 12\n", lcd_wid, lcd_hgt, lcd_wid, lcd_hgt - 1); sock_send_string(sock, "widget_add D err1 string\n"); sock_send_string(sock, "widget_add D err2 string\n"); sock_send_string(sock, "widget_set D err1 5 2 { Reading }\n"); sock_send_string(sock, "widget_set D err2 5 3 {Filesystems}\n"); } /* Get rid of old, unmounted filesystems... */ machine_get_fs(mnt, &count); /* Fill the display structure... */ if (count) { sock_send_string(sock, "widget_set D err1 0 0 .\n"); sock_send_string(sock, "widget_set D err2 0 0 .\n"); for (i = 0; i < count; i++) { if (strlen(mnt[i].mpoint) > dev_wid) sprintf(table[i].dev, "-%s", (mnt[i].mpoint) + (strlen(mnt[i].mpoint) - (dev_wid - 1))); else sprintf(table[i].dev, "%s", mnt[i].mpoint); table[i].full = (huge) (lcd_cellwid * gauge_wid) * (huge) (mnt[i].blocks - mnt[i].bfree) / (huge) mnt[i].blocks; size = (huge) mnt[i].bsize * (huge) mnt[i].blocks; memset(table[i].cap, '\0', 8); sprintf_memory(table[i].cap, (double) size, 1); } } else { sock_send_string(sock, "widget_set D err1 1 2 {Error Retrieving}\n"); sock_send_string(sock, "widget_set D err2 1 3 {Filesystem Stats}\n"); return 0; } /* * Display stuff... (show for two seconds, then scroll once per * second, then hold at the end for two seconds) */ sock_printf(sock, "widget_set D f 1 2 %i %i %i %i v 12\n", lcd_wid, lcd_hgt, lcd_wid, count); for (i = 0; i < count; i++) { char tmp[lcd_wid + 1]; /* should be large enough */ if (table[i].dev[0] == '\0') continue; if (i >= num_disks) { /* Make sure we have enough lines... */ sock_printf(sock, "widget_add D s%i string -in f\n", i); sock_printf(sock, "widget_add D h%i hbar -in f\n", i); } if (lcd_wid >= 20) { /* 20+x columns */ sprintf(tmp, "%-*s %6s E%*sF", dev_wid, table[i].dev, table[i].cap, gauge_wid, ""); sock_printf(sock, "widget_set D s%i 1 %i {%s}\n", i, i + 1, tmp); sock_printf(sock, "widget_set D h%i %i %i %i\n", i, 10 + dev_wid, i + 1, table[i].full); } else { /* < 20 columns */ sprintf(tmp, "%-*s E%*sF", dev_wid, table[i].dev, gauge_wid, ""); sock_printf(sock, "widget_set D s%i 1 %i {%s}\n", i, i + 1, tmp); sock_printf(sock, "widget_set D h%i %i %i %i\n", i, 3 + dev_wid, i + 1, table[i].full); } } /* Now remove extra widgets... */ for (; i < num_disks; i++) { sock_printf(sock, "widget_del D s%i\n", i); sock_printf(sock, "widget_del D h%i\n", i); } num_disks = count; #undef huge 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; }
/************************************************************************* * 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; }
/** * OldTime Screen displays current time and date... * *\verbatim * * +--------------------+ +--------------------+ * |## DATE & TIME ####@| |### TIME: myhost ##@| * | myhost | |2005-05-17 11:32:57a| * |11:32:75a Wednesday,| +--------------------+ * | May 17, 2005 | * +--------------------+ * * Alternate 2-line version without the title bar: * * +----------------+ * | 2012-12-27 @| * | 15:07:01 | * +----------------+ * *\endverbatim * * \param rep Time since last screen update * \param display 1 if screen is visible or data should be updated * \param flags_ptr Mode flags * \return Always 0 */ int clock_screen(int rep, int display, int *flags_ptr) { char now[40]; char today[40]; int xoffs; static int heartbeat = 0; static int showTitle = 1; static const char *timeFormat = NULL; static const char *dateFormat = NULL; time_t thetime; struct tm *rtime; if ((*flags_ptr & INITIALIZED) == 0) { char tmp[257]; /* should be large enough for host name */ *flags_ptr |= INITIALIZED; /* get config values */ timeFormat = config_get_string("OldTime", "TimeFormat", 0, "%H:%M:%S"); dateFormat = config_get_string("OldTime", "DateFormat", 0, "%b %d %Y"); showTitle = config_get_bool("OldTime", "ShowTitle", 0, 1); sock_send_string(sock, "screen_add O\n"); sock_printf(sock, "screen_set O -name {Old Clock Screen: %s}\n", get_hostname()); if (!showTitle) sock_send_string(sock, "screen_set O -heartbeat off\n"); sock_send_string(sock, "widget_add O one string\n"); if (lcd_hgt >= 4) { sock_send_string(sock, "widget_add O title title\n"); sock_send_string(sock, "widget_add O two string\n"); sock_send_string(sock, "widget_add O three string\n"); sock_printf(sock, "widget_set O title {DATE & TIME}\n"); sprintf(tmp, "%s", get_hostname()); xoffs = (lcd_wid > strlen(tmp)) ? (((lcd_wid - strlen(tmp)) / 2) + 1) : 1; sock_printf(sock, "widget_set O one %i 2 {%s}\n", xoffs, tmp); } else { if (showTitle) { sock_send_string(sock, "widget_add O title title\n"); sock_printf(sock, "widget_set O title {TIME: %s}\n", get_hostname()); } else { sock_send_string(sock, "widget_add O two string\n"); } } } /* toggle colon display */ heartbeat ^= 1; time(&thetime); rtime = localtime(&thetime); if (strftime(today, sizeof(today), dateFormat, rtime) == 0) *today = '\0'; if (strftime(now, sizeof(now), timeFormat, rtime) == 0) *now = '\0'; tickTime(now, heartbeat); if (lcd_hgt >= 4) { /* 4-line version of the screen */ xoffs = (lcd_wid > strlen(today)) ? ((lcd_wid - strlen(today)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set O two %i 3 {%s}\n", xoffs, today); xoffs = (lcd_wid > strlen(now)) ? ((lcd_wid - strlen(now)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set O three %i 4 {%s}\n", xoffs, now); } else { /* 2-line version of the screen */ if (showTitle) { xoffs = (lcd_wid > (strlen(today) + strlen(now) + 1)) ? ((lcd_wid - ((strlen(today) + strlen(now) + 1))) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set O one %i 2 {%s %s}\n", xoffs, today, now); } else { xoffs = (lcd_wid > strlen(today)) ? ((lcd_wid - strlen(today)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set O one %i 1 {%s}\n", xoffs, today); xoffs = (lcd_wid > strlen(now)) ? ((lcd_wid - strlen(now)) / 2) + 1 : 1; if (display) sock_printf(sock, "widget_set O two %i 2 {%s}\n", xoffs, now); } } return 0; } /* End clock_screen() */
/** * 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; }