diff --git a/clients/lcdproc/main.c b/clients/lcdproc/main.c index d53193a..7deee68 100644 --- a/clients/lcdproc/main.c +++ b/clients/lcdproc/main.c @@ -153,7 +153,7 @@ main (int argc, char **argv) usleep (500000); // wait for the server to start up sock = sock_connect (server, port); if (sock <= 0) { - printf ("Error connecting to server %s on port %i.\n", server, port); + printf ("Error connecting to LCD server %s on port %i.\nCheck to see that the server is running and operating normally.\n", server, port); return 0; } sock_send_string (sock, "hello\n"); diff --git a/server/client_data.c b/server/client_data.c index c442a6c..482df46 100644 --- a/server/client_data.c +++ b/server/client_data.c @@ -16,6 +16,12 @@ #include "screen.h" #include "screenlist.h" +#define ResetScreenList(a) LL_Rewind(a) +#define NewScreen LL_new +#define NextScreen(a) (screen *)LL_Get(a) +#define MoreScreens(a) (LL_Next(a) == 0) +#define DestroyScreenList(a) LL_Destroy(a) + int client_data_init (client_data * d) { @@ -26,7 +32,7 @@ client_data_init (client_data * d) d->name = NULL; d->client_keys = NULL; - d->screenlist = LL_new (); + d->screenlist = NewScreen(); if (!d->screenlist) { fprintf (stderr, "client_data_init: Error allocating screenlist\n"); return -1; @@ -64,9 +70,9 @@ client_data_destroy (client_data * d) // Clean up the screenlist... debug ("client_data_destroy: Cleaning screenlist\n"); - LL_Rewind (d->screenlist); + ResetScreenList (d->screenlist); do { - s = (screen *) LL_Get (d->screenlist); + s = NextScreen(d->screenlist); if (s) { debug ("client_data_destroy: removing screen %s\n", s->id); @@ -80,8 +86,8 @@ client_data_destroy (client_data * d) // Free its memory... screen_destroy (s); } - } while (LL_Next (d->screenlist) == 0); - LL_Destroy (d->screenlist); + } while (MoreScreens(d->screenlist)); + DestroyScreenList(d->screenlist); // TODO: clean up the rest of the data... diff --git a/server/client_functions.c b/server/client_functions.c index f961e8b..e19a49c 100644 --- a/server/client_functions.c +++ b/server/client_functions.c @@ -9,11 +9,13 @@ */ +#include #include #include #include #include #include +#include #include "shared/debug.h" #include "shared/sockets.h" @@ -28,6 +30,9 @@ #include "widget.h" #include "client_functions.h" +int info_func (client * c, int argc, char **argv); +int sleep_func (client * c, int argc, char **argv); + client_function commands[] = { {"test_func", test_func_func}, {"hello", hello_func}, @@ -52,9 +57,19 @@ client_function commands[] = { {"backlight", backlight_func}, {"output", output_func}, {"noop", noop_func}, + {"info", info_func}, + {"sleep", sleep_func}, {NULL, NULL}, }; +// Remember: argc counts all arguments, including the command name; +// so it will actually be one more than the number of arguments given +// to the command... + +#define NoArguments (argc == 1) +#define AnyArguments (argc != 1) +#define MoreArgumentsThan(a) (argc > (a)) + // TODO: Maybe more error-checking for "->"'s? /////////////////////////////////////////////////////////////////////////// @@ -67,7 +82,7 @@ test_func_func (client * c, int argc, char **argv) char str[256]; for (i = 0; i < argc; i++) { - sprintf (str, "test_func_func: %i -> %s\n", i, argv[i]); + snprintf (str, sizeof(str), "test_func_func: %i -> %s\n", i, argv[i]); printf (str); sock_send_string (c->sock, str); } @@ -79,6 +94,8 @@ test_func_func (client * c, int argc, char **argv) // // It returns a string of info about the server to the client // +// usage: hello +// int hello_func (client * c, int argc, char **argv) { @@ -86,9 +103,20 @@ hello_func (client * c, int argc, char **argv) // TODO: Give *real* info about the server/lcd... + if (AnyArguments) { + sock_send_string (c->sock, "huh? extra parameters ignored\n"); + } + debug ("Hello!\n"); - sprintf (str, "connect LCDproc %s protocol %s lcd wid %i hgt %i cellwid %i cellhgt %i\n", version, protocol_version, lcd.wid, lcd.hgt, lcd.cellwid, lcd.cellhgt); + memset(str, '\0', sizeof(str)); + sprintf (str, "connect LCDproc %s protocol %s lcd wid %i hgt %i cellwid %i cellhgt %i\n", + version, protocol_version, lcd.wid, lcd.hgt, lcd.cellwid, lcd.cellhgt); + +// lcdproc (client) depends on the above format... +// snprintf (str, sizeof(str), "connect LCDproc %s protocol %s LCD %ix%i with cells %ix%i\n", +// version, protocol_version, lcd.wid, lcd.hgt, lcd.cellwid, lcd.cellhgt); + sock_send_string (c->sock, str); if (c->data) @@ -100,38 +128,76 @@ hello_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // sets info about the client, such as its name // +// usage: client_set -name +// int client_set_func (client * c, int argc, char **argv) { int i; + char str[16], buf[80]; + memset(str, '\0', sizeof(str)); if (!c->data->ack) return 1; - for (i = 1; i < argc; i++) { + if (argc != 3) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: client_set -name \n"); + break; + case 2: + sock_send_string (c->sock, "huh? Not enough parameters\n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters\n"); + break; + } + return 0; + } + + i = 1; + do { + char *p; + + // This bit of code means that "-name" is the same as "name"... + p = argv[i]; + if (*p == '-') + p++; + // Handle the "name" parameter - if (0 == strcmp (argv[i], "-name") - || 0 == strcmp (argv[i], "name")) { - if (argc > i + 1) { - i++; + if (strcmp (p, "name") == 0) { + i++; + if (argv[i] == '\0') { + snprintf (buf, sizeof(buf), "huh? internal error: no parameter #%d\n", i); + sock_send_string (c->sock, buf); + continue; + } + + if (strlen(argv[i]) > sizeof(str) -1) { + sock_send_string (c->sock, "huh? name too long\n"); + } else { + strncpy(str, argv[i], sizeof(str) - 1); + debug ("client_set: name=\"%s\"\n", argv[i]); + syslog(LOG_INFO, "client set name to %s", str); + // set the name... if (c->data->name) free (c->data->name); - c->data->name = strdup (argv[i]); - sock_send_string(c->sock, "success\n"); - } else { - sock_send_string (c->sock, "huh? name requires a parameter\n"); + + if ((c->data->name = strdup (str)) == NULL) { + sock_send_string(c->sock, "huh? error allocating memory!\n"); + } else { + sock_send_string(c->sock, "success\n"); + i++; // bypass argument (name string) + } } } else { - sock_send_string (c->sock, "huh? invalid parameter\n"); + snprintf (buf, sizeof(buf), "huh? invalid parameter (%s)\n", p); + sock_send_string (c->sock, buf); } - } - - // If there were no parameters... - if (argc == 1) - sock_send_string (c->sock, "huh? What do you want to set?\n"); + } while (++i < argc); return 0; } @@ -140,6 +206,8 @@ client_set_func (client * c, int argc, char **argv) // Tells the server the client would like to accept keypresses // of a particular type // +// usage: client_add_key +// int client_add_key_func (client * c, int argc, char **argv) { @@ -148,16 +216,20 @@ client_add_key_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a key list\n"); - return 0; - } - if (argc > 2) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 2) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: client_add_key \n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters...\n"); + break; + } return 0; } + keys = argv[1]; - debug ("client_add_key: Adding key(s) %s to client_keys\n", keys); + debug ("client_add_key: current client will handle key(s) %s\n", keys); if (!c->data->client_keys) { // No keys list, create a new one @@ -175,13 +247,17 @@ client_add_key_func (client * c, int argc, char **argv) if( new ) { c->data->client_keys = new ; strcat( new, keys ); + } else { + sock_send_string(c->sock, "huh? could not allocate memory for new keys\n"); + return 0; } } - if (!c->data->client_keys) { - sock_send_string(c->sock, "huh? failed\n"); - } else + if (c->data->client_keys) { sock_send_string(c->sock, "success\n"); + } else { + sock_send_string(c->sock, "huh? failed\n"); + } return 0; } @@ -190,6 +266,8 @@ client_add_key_func (client * c, int argc, char **argv) // Tells the server the client would NOT like to accept keypresses // of a particular type // +// usage: client_del_key +// int client_del_key_func (client * c, int argc, char **argv) { @@ -198,14 +276,16 @@ client_del_key_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a key list\n"); - return 0; - } - if (argc > 2) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); - return 0; + if (argc != 2) { + if (argc == 1) { + sock_send_string (c->sock, "huh? usage: client_del_key \n"); + return 0; + } else { + sock_send_string (c->sock, "huh? Too many parameters...\n"); + return 0; + } } + keys = argv[1] ; debug ("client_del_key: Deleting key(s) %s from client_keys\n", keys); @@ -240,6 +320,8 @@ client_del_key_func (client * c, int argc, char **argv) // Tells the server the client would like to accept keypresses // of a particular type when the given screen is active on the display // +// screen_add_key +// int screen_add_key_func (client * c, int argc, char **argv) { @@ -251,18 +333,21 @@ screen_add_key_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a screen id\n"); - return 0; - } - if (argc < 3) { - sock_send_string (c->sock, "huh? You must specify a key list\n"); - return 0; - } - if (argc > 3) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 3) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: screen_add_key \n"); + break; + case 2: + sock_send_string (c->sock, "huh? You must specify a key list\n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters...\n"); + break; + } return 0; } + id = argv[1]; keys = argv[2]; debug ("screen_add_key: Adding key(s) %s to screen %s\n", keys, id); @@ -289,6 +374,9 @@ screen_add_key_func (client * c, int argc, char **argv) if( new ) { s->keys = new ; strcat( new, keys ); + } else { + sock_send_string(c->sock, "huh? could not allocate memory for new keys\n"); + return 0; } } @@ -304,6 +392,8 @@ screen_add_key_func (client * c, int argc, char **argv) // Tells the server the client would NOT like to accept keypresses // of a particular type when the given screen is active on the display // +// usage: screen_del_key +// int screen_del_key_func (client * c, int argc, char **argv) { @@ -315,27 +405,33 @@ screen_del_key_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a screen id\n"); - return 0; - } - if (argc < 3) { - sock_send_string (c->sock, "huh? You must specify a key list\n"); - return 0; - } - if (argc > 3) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 3) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: screen_del_key \n"); + break; + case 2: + sock_send_string (c->sock, "huh? You must specify a key list\n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters\n"); + break; + } return 0; } + id = argv[1] ; keys = argv[2] ; debug ("screen_del_key: Deleting key(s) %s from screen %s\n", keys, id); + // Find the screen s = screen_find (c, id); + if (!s) { sock_send_string (c->sock, "huh? Invalid screen id\n"); return 0; } + // Do we have keys? if (s->keys) { // Have keys, remove keys from the list @@ -357,6 +453,7 @@ screen_del_key_func (client * c, int argc, char **argv) *to++ = *from++ ; } } + to = '\0'; // terminates the new keys string... } sock_send_string(c->sock, "success\n"); @@ -367,68 +464,85 @@ screen_del_key_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Tells the server the client has another screen to offer // +// usage: screen_add +// int screen_add_func (client * c, int argc, char **argv) { int err = 0; + char scr[128]; if (!c->data->ack) return 1; - if (argc < 2) { - sock_send_string (c->sock, "huh? Specify a screen #id\n"); - return 0; - } - if (argc > 2) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 2) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: screen_add \n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters...\n"); + break; + } return 0; } debug ("screen_add: Adding screen %s\n", argv[1]); - err = screen_add (c, argv[1]); - if (err < 0) { - fprintf (stderr, "screen_add_func: Error adding screen\n"); - sock_send_string (c->sock, "huh? failed to add screen id#\n"); - } - if (err > 0) - sock_send_string (c->sock, "huh? You already have a screen with that id#\n"); + + memset(scr, '\0', sizeof(scr)); + strncpy(scr, argv[1], sizeof(scr) - 1); + + err = screen_add (c, scr); if (err == 0) sock_send_string(c->sock, "success\n"); + else if (err < 0) { + fprintf (stderr, "screen_add_func: Error adding screen\n"); + sock_send_string (c->sock, "huh? failed to add screen id#\n"); + } else + sock_send_string (c->sock, "huh? You already have a screen with that id#\n"); + syslog(LOG_NOTICE, "added a screen (%s) to the display", scr); return 0; } /////////////////////////////////////////////////////////////////////////// // Client requests that the server forget about a screen // +// usage: screen_del +// int screen_del_func (client * c, int argc, char **argv) { int err = 0; + char scr[128]; if (!c->data->ack) return 1; - if (argc < 2) { - sock_send_string (c->sock, "huh? Specify a screen #id\n"); - return 0; - } - if (argc > 2) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 2) { + if (NoArguments) + sock_send_string (c->sock, "huh? usage: screen_del \n"); + else + sock_send_string (c->sock, "huh? Too many parameters...\n"); return 0; } debug ("screen_del: Deleting screen %s\n", argv[1]); - err = screen_remove (c, argv[1]); - if (err < 0) { - fprintf (stderr, "screen_del_func: Error removing screen\n"); - sock_send_string(c->sock, "huh? failed to remove screen\n"); - } - if (err > 0) - sock_send_string (c->sock, "huh? You don't have a screen with that id#\n"); + + // Enforce bounds limits on argv[1] + memset(scr, '\0', sizeof(scr)); + strncpy(scr, argv[1], sizeof(scr) - 1); + + err = screen_remove (c, scr); if ( err == 0 ) sock_send_string(c->sock, "success\n"); + else if (err < 0) { + fprintf (stderr, "screen_del_func: Error removing screen\n"); + sock_send_string(c->sock, "huh? failed to remove screen\n"); + } else + sock_send_string (c->sock, "huh? You don't have a screen with that id#\n"); + syslog(LOG_NOTICE, "removed a screen (%s) from the display", scr); return 0; } @@ -436,6 +550,8 @@ screen_del_func (client * c, int argc, char **argv) // Configures info about a particular screen, such as its // name, priority, or duration // +// usage: screen_set [ -priority ] [ -name ] [ -duration ] +// [ -wid ] [ -hgt ] [ -heartbeat ] int screen_set_func (client * c, int argc, char **argv) { @@ -448,13 +564,10 @@ screen_set_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - // If there weren't enough parameters... - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a screen id\n"); + if (NoArguments) { + sock_send_string (c->sock, "huh? usage: screen_set [ -priority ] [ -name ] [ -duration ] [ -wid ] [ -hgt ] [ -heartbeat ]\n"); return 0; - } - - if (argc == 2) { + } else if (argc == 2) { sock_send_string (c->sock, "huh? What do you want to set?\n"); return 0; } @@ -467,9 +580,18 @@ screen_set_func (client * c, int argc, char **argv) } // Handle the rest of the parameters for (i = 2; i < argc; i++) { + char *p; + + // The following code allows us to use p for comparisions, + // ignoring a (valid) single leading '-' - reduces string comparisons + // by half. + + p = argv[i]; + if (*p == '-') + p++; + // Handle the "name" parameter - if (0 == strcmp (argv[i], "-name") - || 0 == strcmp (argv[i], "name")) { + if (strcmp (p, "name")) { if (argc > i + 1) { i++; debug ("screen_set: name=\"%s\"\n", argv[i]); @@ -484,8 +606,7 @@ screen_set_func (client * c, int argc, char **argv) } } // Handle the "priority" parameter - else if (0 == strcmp (argv[i], "-priority") - || 0 == strcmp (argv[i], "priority")) { + else if (strcmp (p, "priority")) { if (argc > i + 1) { i++; debug ("screen_set: priority=\"%s\"\n", argv[i]); @@ -500,8 +621,7 @@ screen_set_func (client * c, int argc, char **argv) } } // Handle the "duration" parameter - else if (0 == strcmp (argv[i], "-duration") - || 0 == strcmp (argv[i], "duration")) { + else if (strcmp (p, "duration")) { if (argc > i + 1) { i++; debug ("screen_set: duration=\"%s\"\n", argv[i]); @@ -516,35 +636,33 @@ screen_set_func (client * c, int argc, char **argv) } } // Handle the "heartbeat" parameter - else if (0 == strcmp (argv[i], "-heartbeat") - || 0 == strcmp (argv[i], "heartbeat")) { + else if (strcmp (p, "heartbeat")) { if (argc > i + 1) { i++; debug ("screen_set: heartbeat=\"%s\"\n", argv[i]); // set the heartbeat type... if (0 == strcmp (argv[i], "on")) - s->heartbeat = 1; + s->heartbeat = HEART_ON; if (0 == strcmp (argv[i], "heart")) - s->heartbeat = 1; + s->heartbeat = HEART_ON; if (0 == strcmp (argv[i], "normal")) - s->heartbeat = 1; + s->heartbeat = HEART_ON; if (0 == strcmp (argv[i], "default")) - s->heartbeat = 1; + s->heartbeat = HEART_ON; if (0 == strcmp (argv[i], "off")) - s->heartbeat = 0; + s->heartbeat = HEART_OFF; if (0 == strcmp (argv[i], "none")) - s->heartbeat = 0; + s->heartbeat = HEART_OFF; if (0 == strcmp (argv[i], "slash")) - s->heartbeat = 2; + s->heartbeat = HEART_OPEN; sock_send_string(c->sock, "success\n"); } else { sock_send_string (c->sock, "huh? -heartbeat requires a parameter\n"); } } // Handle the "wid" parameter - else if (0 == strcmp (argv[i], "-wid") - || 0 == strcmp (argv[i], "wid")) { + else if (strcmp (p, "wid")) { if (argc > i + 1) { i++; debug ("screen_set: wid=\"%s\"\n", argv[i]); @@ -559,8 +677,7 @@ screen_set_func (client * c, int argc, char **argv) } } // Handle the "hgt" parameter - else if (0 == strcmp (argv[i], "-hgt") - || 0 == strcmp (argv[i], "hgt")) { + else if (strcmp (p, "hgt")) { if (argc > i + 1) { i++; debug ("screen_set: hgt=\"%s\"\n", argv[i]); @@ -584,6 +701,8 @@ screen_set_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Adds a widget to a screen, but doesn't give it a value // +// usage: widget_add [ -in ] +// int widget_add_func (client * c, int argc, char **argv) { @@ -598,21 +717,21 @@ widget_add_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - // If there weren't enough parameters... - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a screen id\n"); - return 0; - } - if (argc < 3) { - sock_send_string (c->sock, "huh? You must specify a widget id\n"); - return 0; - } - if (argc < 4) { - sock_send_string (c->sock, "huh? You must specify a widget type\n"); - return 0; - } - if (argc > 6) { - sock_send_string (c->sock, "huh? Too many parameters\n"); + if ((argc < 4) || (argc > 6)) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: widget_add [ -in ]\n"); + break; + case 2: + sock_send_string (c->sock, "huh? Widget ID and Widget Type not specified!\n"); + break; + case 3: + sock_send_string (c->sock, "huh? Widget Type not specified!\n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters\n"); + break; + } return 0; } @@ -629,9 +748,14 @@ widget_add_func (client * c, int argc, char **argv) // Check for additional flags... if (argc > 4) { + char *p; + + p = argv[4]; + if (*p == '-') + p++; + // Handle the "in" flag to place widgets in a container... - if (0 == strcmp (argv[4], "-in") - || 0 == strcmp (argv[4], "in")) { + if (strcmp (p, "in")) { if (argc < 6) { sock_send_string (c->sock, "huh? Specify a frame to place widget in\n"); return 0; @@ -639,14 +763,15 @@ widget_add_func (client * c, int argc, char **argv) in = argv[5]; } } + // Add the widget and set its type... err = widget_add (s, wid, type, in, c->sock); - if (err < 0) { + if (err == 0) + sock_send_string(c->sock, "success\n"); + else { fprintf (stderr, "widget_add_func: Error adding widget\n"); sock_send_string(c->sock, "huh? failed\n"); } - else - sock_send_string(c->sock, "success\n"); return 0; } @@ -654,6 +779,8 @@ widget_add_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Removes a widget from a screen, and forgets about it // +// usage: widget_del +// int widget_del_func (client * c, int argc, char **argv) { @@ -666,17 +793,18 @@ widget_del_func (client * c, int argc, char **argv) if (!c->data->ack) return 1; - // Check the number of parameters... - if (argc < 2) { - sock_send_string (c->sock, "huh? Specify a screen #id\n"); - return 0; - } - if (argc < 3) { - sock_send_string (c->sock, "huh? Specify a widget #id\n"); - return 0; - } - if (argc > 3) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 3) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: widget_del \n"); + break; + case 2: + sock_send_string (c->sock, "huh? Specify a widget #id\n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters...\n"); + break; + } return 0; } @@ -691,12 +819,12 @@ widget_del_func (client * c, int argc, char **argv) } err = widget_remove (s, wid, c->sock); - if (err < 0) { + if (err == 0) + sock_send_string(c->sock, "success\n"); + else { fprintf (stderr, "widget_del_func: Error removing widget\n"); sock_send_string(c->sock, "huh? failed\n"); } - else - sock_send_string(c->sock, "success\n"); return 0; } @@ -706,6 +834,9 @@ widget_del_func (client * c, int argc, char **argv) // contents, position, speed, etc... // // Ack! This is long! +// +// widget_set +// int widget_set_func (client * c, int argc, char **argv) { @@ -724,16 +855,22 @@ widget_set_func (client * c, int argc, char **argv) return 1; // If there weren't enough parameters... - if (argc < 2) { - sock_send_string (c->sock, "huh? You must specify a screen id\n"); - return 0; - } - if (argc < 3) { - sock_send_string (c->sock, "huh? You must specify a widget id\n"); - return 0; - } + // We can't test for too many, since each widget may have a + // different number - plus, if the argument count is wrong, what ELSE + // could be wrong...? + if (argc < 4) { - sock_send_string (c->sock, "huh? You must send some widget data\n"); + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: widget_set \n"); + break; + case 2: + sock_send_string (c->sock, "huh? You must specify a widget id\n"); + break; + case 3: + sock_send_string (c->sock, "huh? You must send some widget data\n"); + break; + } return 0; } @@ -965,6 +1102,8 @@ widget_set_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Adds a menu to the client; handled by the server... // +// usage: menu_add ...? +// int menu_add_func (client * c, int argc, char **argv) { @@ -980,6 +1119,8 @@ menu_add_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Removes a client's menu and all contents from the server // +// usage: menu_del ...? +// int menu_del_func (client * c, int argc, char **argv) { @@ -997,6 +1138,8 @@ menu_del_func (client * c, int argc, char **argv) // // For example, should the menu be top-level, or buried somewhere? // +// usage: menu_set ...? +// int menu_set_func (client * c, int argc, char **argv) { @@ -1012,6 +1155,8 @@ menu_set_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Adds an item to a menu // +// usage: menu_add_item ...? +// int menu_add_item_func (client * c, int argc, char **argv) { @@ -1027,6 +1172,7 @@ menu_add_item_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Deletes an item from a menu // +// usage: menu_del_item ...? int menu_del_item_func (client * c, int argc, char **argv) { @@ -1044,6 +1190,8 @@ menu_del_item_func (client * c, int argc, char **argv) // // For example, text displayed, widget type, value, etc... // +// usage: menu_set_item ...? +// int menu_set_item_func (client * c, int argc, char **argv) { @@ -1059,49 +1207,59 @@ menu_set_item_func (client * c, int argc, char **argv) /////////////////////////////////////////////////////////////////////////// // Toggles the backlight, if enabled. // +// usage: backlight +// int backlight_func (client * c, int argc, char **argv) { if (!c->data->ack) return 1; - // Check the number of parameters... - if (argc < 2) { - sock_send_string (c->sock, "huh? Specify a screen #id\n"); - return 0; - } - - if (argc > 2) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); + if (argc != 2) { + switch (argc) { + case 1: + sock_send_string (c->sock, "huh? usage: backlight \n"); + break; + default: + sock_send_string (c->sock, "huh? Too many parameters...\n"); + break; + } return 0; } debug ("backlight(%s)\n", argv[1]); - switch (backlight) { - case BACKLIGHT_OPEN: - if (0 == strcmp ("on", argv[1])) { - backlight_state = BACKLIGHT_ON; - } - if (0 == strcmp ("off", argv[1])) { + // TODO: The following don't seem to be used; + // either use them or lose them: + // + // #define BACKLIGHT_LOAD 3 + // #define BACKLIGHT_VIS 4 + // + // TODO: The meaning of this one isn't clear; make it so... + // + // #define BACKLIGHT_OPEN 2 + + backlight = (backlight && 1); // only preserves ON/OFF bit + + if (strcmp ("on", argv[1]) == 0) { + backlight_state = BACKLIGHT_ON; + + } else if (strcmp ("off", argv[1]) == 0) { + backlight_state = BACKLIGHT_OFF; + + } else if (strcmp ("toggle", argv[1]) == 0) { + if (backlight_state == BACKLIGHT_ON) backlight_state = BACKLIGHT_OFF; - } - if (0 == strcmp ("toggle", argv[1])) { - if (backlight_state == BACKLIGHT_ON) - backlight_state = BACKLIGHT_OFF; - else if (backlight_state == BACKLIGHT_OFF) - backlight_state = BACKLIGHT_ON; - } - if (0 == strcmp ("blink", argv[1])) { - backlight_state |= BACKLIGHT_BLINK; - } - if (0 == strcmp ("flash", argv[1])) { - backlight_state |= BACKLIGHT_FLASH; - } - break; - case BACKLIGHT_VIS: - break; + else if (backlight_state == BACKLIGHT_OFF) + backlight_state = BACKLIGHT_ON; + + } else if (strcmp ("blink", argv[1]) == 0) { + backlight_state |= BACKLIGHT_BLINK; + + } else if (0 == strcmp ("flash", argv[1])) { + backlight_state |= BACKLIGHT_FLASH; } + sock_send_string(c->sock, "success\n"); return 0; @@ -1109,41 +1267,182 @@ backlight_func (client * c, int argc, char **argv) } //////////////////////////////////////////////////////////////////////////// -// Sets the output port on MtxOrb LCDs +// Sets the state of the output port (such as on MtxOrb LCDs) +// +// usage: output +// +// +#define ALL_OUTPUTS_ON -1 +#define ALL_OUTPUTS_OFF 0 + int output_func (client * c, int argc, char **argv) { int rc = 0; - if (argc != 2) { - sock_send_string (c->sock, "huh? Too many parameters...\n"); - rc = 1; - } else { - if (0 == strcmp (argv[1], "on")) - /* switch all ouputs on */ - output_state = -1; - else if (0 == strcmp (argv[1], "off")) - /* switch all ouputs off */ - output_state = 0; - else { - long out; - char *endptr; + char str[128]; - out = strtol(argv[1], &endptr, 0); - if ( (out == 0) && (errno != 0) ) { - sock_send_string (c->sock, - "huh? invalid parameter...\n"); - rc = 1; - } - else { - output_state = out; - } + if (argc != 2) { + if (NoArguments) + sock_send_string (c->sock, "huh? usage: output -- num may be decimal, hex, or octal\n"); + else + sock_send_string (c->sock, "huh? Too many parameters...\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, *p; + + // Note that there is no valid range set for + // output_state; thus a value in the 12 digits + // is not considered out of range. + + errno = 0; + + // errno is set here, because if strtol does not result in + // ERANGE (out of range error) it will not set errno (!). + // At least, this is the case with glibc 2.1.3 ... + + p = argv[1]; + out = strtol(p, &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) { + int space; + + strcat(str, "huh? number argument: "); + space = sizeof(str) - 3 - strlen(str); + + strncat(str, strerror(errno), space); + strcat(str, "\n"); + + sock_send_string (c->sock, str); + return 0; + } else if (*p != '\0' && *endptr == '\0') { + output_state = out; + } else { + sock_send_string (c->sock, "huh? invalid parameter...\n"); + return 0; } } - if ( rc == 0 ) { - sock_send_string(c->sock, "success\n"); + 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? + + // lcd.output (output_state); + + syslog(LOG_NOTICE, "output states changed"); + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// info_func +// +// usage: info +// +int +info_func (client * c, int argc, char **argv) +{ + char str[1024]; + + if (! NoArguments) { + sock_send_string (c->sock, "huh? Extra arguments ignored...\n"); } + memset(str, '\0', sizeof(str)); + snprintf (str, sizeof(str), (char*) lcd.getinfo()); + + sock_send_string (c->sock, str); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// sleep_func +// +// usage: sleep +// +int +sleep_func (client * c, int argc, char **argv) +{ + int secs; + long out; + char *endptr, *p; + char str[120]; + +#define MAX_SECS 60 +#define MIN_SECS 1 + + if (argc != 2) { + if (NoArguments) + sock_send_string (c->sock, "huh? usage: sleep \n"); + else + sock_send_string (c->sock, "huh? Too many parameters...\n"); + return 0; + } + + errno = 0; + + // errno is set here, because if strtol does not result in + // ERANGE (out of range error) it will not set errno (!). + // At least, this is the case with glibc 2.1.3 ... + + p = argv[1]; + out = strtol(p, &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) { + int space; + + strcat(str, "huh? number argument: "); + space = sizeof(str) - 3 - strlen(str); + + strncat(str, strerror(errno), space); + strcat(str, "\n"); + + sock_send_string (c->sock, str); + return 0; + } else if (*p != '\0' && *endptr == '\0') { + secs = out; + out = out > MAX_SECS ? MAX_SECS : out; + out = out < MIN_SECS ? MIN_SECS : out; + } else { + sock_send_string (c->sock, "huh? invalid parameter...\n"); + return 0; + } + + // Repeat until no more remains - should normally be zero + // on exit the first time... + sprintf(str, "sleeping %d seconds\n", secs); + sock_send_string (c->sock, str); + + // whoops.... if this takes place as planned, ALL screens + // will "freeze" for the alloted time... + // + // while ((secs = sleep(secs)) > 0) + // ; + + sock_send_string (c->sock, "huh? ignored (not fully implemented)\n"); return 0; } diff --git a/server/clients.c b/server/clients.c index 0bbe84c..b2c8050 100644 --- a/server/clients.c +++ b/server/clients.c @@ -15,7 +15,9 @@ #include #include #include +#include +#include "sock.h" #include "clients.h" #include "client_data.h" #include "shared/debug.h" @@ -40,7 +42,6 @@ client_init () int client_shutdown () { - // TODO: Close all connections first... client *c; debug ("client_shutdown()\n"); @@ -52,7 +53,7 @@ client_shutdown () debug ("client_shutdown: ...\n"); if (c) { debug ("client_shutdown: ... %i ...\n", c->sock); - if (0 != client_destroy (c)) { + if (client_destroy (c) != 0) { fprintf (stderr, "client_shutdown: Error freeing client\n"); } else { debug ("client_shutdown: Freed client...\n"); @@ -70,6 +71,9 @@ client_shutdown () return 0; } +// A client is identified by the file descriptor +// associated with it. +// // Create and destroy clients.... client * client_create (int sock) @@ -117,7 +121,6 @@ client_create (int sock) int client_destroy (client * c) { - // TODO: Close the socket connection here? int err; char *str; @@ -136,17 +139,18 @@ client_destroy (client * c) } } + // close socket... + if (c->sock) { + // sock_send_string (c->sock, "bye\n"); + close(c->sock); + syslog(LOG_NOTICE, "closed socket for #%d\n", c->sock); + } + err = LL_Destroy (c->messages); // Free client's other data client_data_destroy (c->data); -/* - // FIXME? Should the connection get closed here or elsewhere? - if(c->sock) close(c->sock); - c->sock = 0; -*/ - // Remove the client from the clients list... LL_Remove (clients, c); diff --git a/server/clients.h b/server/clients.h index 92eaad7..96f24d8 100644 --- a/server/clients.h +++ b/server/clients.h @@ -6,6 +6,7 @@ typedef struct client { int sock; + char addr[64]; LL *messages; client_data *data; diff --git a/server/drivers/MtxOrb.c b/server/drivers/MtxOrb.c index d274155..d5a2b4e 100644 --- a/server/drivers/MtxOrb.c +++ b/server/drivers/MtxOrb.c @@ -1,10 +1,24 @@ +/* + * Matrix Orbital driver + * + * For the Matrix Orbital LCD* LKD* VFD* and VKD* displays + * + * September 16, 2001 + * + * NOTE: GLK displays have a different driver. + * + */ + #include #include #include +#include +#include #include #include #include #include +#include #ifdef HAVE_CONFIG_H # include "config.h" @@ -16,6 +30,26 @@ #include "shared/debug.h" #include "shared/str.h" +#define DEFAULT_CONTRAST 140 +#define DEFAULT_DEVICE "/dev/lcd" +#define DEFAULT_SPEED B19200 +#define DEFAULT_LINEWRAP 1 +#define DEFAULT_AUTOSCROLL 1 +#define DEFAULT_CURSORBLINK 0 + +#define GENERIC (void *) -1 + +#define IS_LCD_DISPLAY (MtxOrb_type == MTXORB_LCD) +#define IS_LKD_DISPLAY (MtxOrb_type == MTXORB_LKD) +#define IS_VFD_DISPLAY (MtxOrb_type == MTXORB_VFD) +#define IS_VKD_DISPLAY (MtxOrb_type == MTXORB_VKD) + +#define NotEnoughArgs (i + 1 > argc) + +// NOTE: This does not appear to make use of the +// hbar and vbar functions present in the LKD202-25. +// Why I do not know. + static int custom = 0; static enum {MTXORB_LCD, MTXORB_LKD, MTXORB_VFD, MTXORB_VKD} MtxOrb_type; @@ -65,25 +99,102 @@ static void MtxOrb_linewrap (int on); static void MtxOrb_autoscroll (int on); static void MtxOrb_cursorblink (int on); +int +MtxOrb_set_type (char * str) { + char c; + c = str[0]; + + if (c == 'l') { + if (strcmp(str, "lcd") == 0) { + return MTXORB_LCD; + } else if (strcmp(str, "lkd") == 0) { + return MTXORB_LKD; + } else { + fprintf (stderr, "MtxOrb_init: unknwon display type %s; must be one of lcd, lkd, vfd, or vkd\n", str); + } + } else if (c == 'v') { + if (strcmp (str, "vfd") == 0) { + return MTXORB_VFD; + } else if (strcmp (str, "vkd") == 0) { + return MTXORB_VKD; + } else { + fprintf (stderr, "MtxOrb_init: unknwon display type %s; must be one of lcd, lkd, vfd, or vkd\n", str); + } + } else { + fprintf (stderr, "MtxOrb_init: unknwon display type %s; must be one of lcd, lkd, vfd, or vkd\n", str); + } + return (-1); +} + +int +MtxOrb_get_speed (char *arg) { + int speed; + + switch (atoi(arg)) { + case 1200: speed = B1200; break; + case 2400: speed = B2400; break; + case 9600: speed = B9600; break; + case 19200: speed = B19200; break; + default: + speed = DEFAULT_SPEED; + fprintf (stderr, "MtxOrb_init: argument must be 1200, 2400, 9600 or 19200. Using default value"); + switch (speed) { + case B1200: fprintf(stderr, " of 1200 baud.\n"); break; + case B2400: fprintf(stderr, " of 2400 baud.\n"); break; + case B9600: fprintf(stderr, " of 9600 baud.\n"); break; + case B19200: fprintf(stderr, " of 19200 baud.\n"); break; + default: fprintf(stderr, ".\n"); break; + } + } + + return speed; + } + +void +MtxOrb_usage (void) { + printf ("LCDproc Matrix-Orbital LCD driver\n" + "\t-d\t--device\tSelect the output device to use [/dev/lcd]\n" +// "\t-t\t--type\t\tSelect the LCD type (size) [20x4]\n" +// "\t-b\t--backlight\tSelect the backlight state [on]\n" + "\t-c\t--contrast\tSet the initial contrast [140]\n" + "\t-s\t--speed\t\tSet the communication speed [19200]\n" + "\t-h\t--help\t\tShow this help information\n" + "\t-t\t--type\t\tdisplay type: lcd, lkd, vfd, vkd\n"); +} + +int +MtxOrb_set_contrast (char * str) { + int contrast; + + contrast = atoi (str); + if ((contrast < 0) || (contrast > 255)) { + fprintf(stderr, "MtxOrb_init: argument must between 0 and 255 (found %s). Using default contrast value of %d.\n", str, DEFAULT_CONTRAST); + contrast = DEFAULT_CONTRAST; + } + return contrast; +} + // TODO: Get rid of this variable? -lcd_logical_driver *MtxOrb; +lcd_logical_driver *MtxOrb; // set by MtxOrb_init(); doesn't seem to be used anywhere // TODO: Get the frame buffers working right ///////////////////////////////////////////////////////////////// // Opens com port and sets baud correctly... // +// Called to initialize driver settings +// int MtxOrb_init (lcd_logical_driver * driver, char *args) { - char *argv[64]; + char *argv[64]; // Notice: 64 arguments - overflows? int argc; struct termios portset; int i; int tmp; - int contrast = 140; - char device[256] = "/dev/lcd"; - int speed = B19200; + int contrast = DEFAULT_CONTRAST; + char device[256] = DEFAULT_DEVICE; + int speed = DEFAULT_SPEED; MtxOrb_type = MTXORB_LKD ; // Assume it's an LCD w/keypad MtxOrb = driver; @@ -166,10 +277,19 @@ MtxOrb_init (lcd_logical_driver * driver, char *args) // Set up io port correctly, and open it... fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY); if (fd == -1) { - fprintf (stderr, "MtxOrb_init: failed (%s)\n", strerror (errno)); - return -1; - } - //else fprintf(stderr, "MtxOrb_init: opened device %s\n", device); + switch (errno) { + case ENOENT: fprintf(stderr, "MtxOrb_init: %s device file missing!\n", device); + break; + case EACCES: fprintf(stderr, "MtxOrb_init: %s device could not be opened...\n", device); + fprintf(stderr, "MtxOrb_init: perhaps you should run LCDd as root?\n"); + break; + default: fprintf (stderr, "MtxOrb_init: failed (%s)\n", strerror (errno)); + break; + } + return -1; + } else + syslog(LOG_INFO, "opened Matrix Orbital display on %s\n", device); + tcgetattr (fd, &portset); // We use RAW mode @@ -193,29 +313,32 @@ MtxOrb_init (lcd_logical_driver * driver, char *args) // Do it... tcsetattr (fd, TCSANOW, &portset); - // Set display-specific stuff.. - MtxOrb_linewrap (1); - MtxOrb_autoscroll (1); - MtxOrb_cursorblink (0); + /* + * Configure display + */ + + MtxOrb_linewrap (DEFAULT_LINEWRAP); + MtxOrb_autoscroll (DEFAULT_AUTOSCROLL); + MtxOrb_cursorblink (DEFAULT_CURSORBLINK); + MtxOrb_contrast (contrast); if (!driver->framebuf) { fprintf (stderr, "MtxOrb_init: No frame buffer.\n"); driver->close (); return -1; } - // Set the functions the driver supports... -// driver->clear = (void *)-1; - driver->clear = MtxOrb_clear; - driver->string = (void *) -1; -// driver->chr = MtxOrb_chr; - driver->chr = (void *) -1; + /* + * Configure the display functions + */ + + driver->clear = MtxOrb_clear; // was GENERIC + driver->string = GENERIC; + driver->chr = MtxOrb_chr; // was GENERIC driver->vbar = MtxOrb_vbar; - driver->init_vbar = MtxOrb_init_vbar; -// driver->init_vbar = (void *)-1; + driver->init_vbar = MtxOrb_init_vbar; // was GENERIC driver->hbar = MtxOrb_hbar; - driver->init_hbar = MtxOrb_init_hbar; -// driver->init_hbar = (void *)-1; + driver->init_hbar = MtxOrb_init_hbar; // was GENERIC driver->num = MtxOrb_num; driver->init_num = MtxOrb_init_num; @@ -231,8 +354,7 @@ MtxOrb_init (lcd_logical_driver * driver, char *args) driver->draw_frame = MtxOrb_draw_frame; driver->getkey = MtxOrb_getkey; - - MtxOrb_contrast (contrast); + driver->getinfo = MtxOrb_getinfo; return fd; } @@ -243,11 +365,15 @@ MtxOrb_init (lcd_logical_driver * driver, char *args) // forget bar caracter not in use anymore and reuse the // slot for another bar caracter. // +// Why not just use Matrix Orbital's "clear screen" function or output a "^L"? +// This reliance on drv_base_clear seems suspicious... especially as +// using a (void *) -1 in the driver structure does the same thing... +// void MtxOrb_clear () { -// REMOVE: fprintf(stderr, "GLU: MtxOrb_clear.\n"); - drv_base_clear (); + drv_base_clear (); // do we need this? + write(fd, "\x0FEX", 2); // instant clear... clear = 1; } @@ -280,7 +406,7 @@ MtxOrb_flush_box (int lft, int top, int rgt, int bot) // printf("Flush (%i,%i)-(%i,%i)\n", lft, top, rgt, bot); for (y = top; y <= bot; y++) { - sprintf (out, "%cG%c%c", 254, lft, y); + sprintf (out, "\x0FEG%c%c", lft, y); write (fd, out, 4); write (fd, lcd.framebuf + (y * lcd.wid) + lft, rgt - lft + 1); @@ -295,9 +421,25 @@ MtxOrb_flush_box (int lft, int top, int rgt, int bot) void MtxOrb_chr (int x, int y, char c) { - y--; - x--; + char out[10]; + // validate x and y + if (y > lcd.hgt) + y = lcd.hgt; + if (x > lcd.wid) + x = lcd.wid; + if (y < 1) + y = 1; + if (x < 1) + x = 1; + + // write immediately to screen... this code was taken + // from the LK202-25; should work for others, yes? + sprintf(out, "\x0FEG%c%c%c", x, y, c); + write (fd, out, 4); + + // write to frame buffer + y--; x--; lcd.framebuf[(y * lcd.wid) + x] = c; } @@ -310,35 +452,49 @@ int MtxOrb_contrast (int contrast) { char out[4]; - static int status = 140; - if ( ((MtxOrb_type == MTXORB_LCD) || (MtxOrb_type == MTXORB_LKD)) && - (contrast > 0) ) { - status = contrast; - sprintf (out, "%cP%c", 254, status); + // validate contrast value + if (contrast > 255) + contrast = 255; + if (contrast < 0) + contrast = 0; + + if (IS_LCD_DISPLAY || IS_LKD_DISPLAY) { + sprintf (out, "\x0FEP%c", contrast); write (fd, out, 3); } - - return status; + return contrast; } ///////////////////////////////////////////////////////////////// // Sets the backlight on or off -- can be done quickly for // an intermediate brightness... -// WARN: off switches vfd/vkd displays off -// -> so it's maybe the best to start LCDd with -b on // +// WARNING: off switches vfd/vkd displays off entirely +// so maybe it is best to start LCDd with -b on +// +// WARNING: there seems to be a movement afoot to add more +// functions than just on/off to this.. + +#define BACKLIGHT_OFF 0 +#define BACKLIGHT_ON 1 + void MtxOrb_backlight (int on) { - char out[4]; - if (on) { - sprintf (out, "%cB%c", 254, 0); - write (fd, out, 3); - } else { - sprintf (out, "%cF", 254); - write (fd, out, 2); - } + switch (on) { + case BACKLIGHT_ON: + write (fd, "\x0FE" "F", 2); + break; + case BACKLIGHT_OFF: + if (IS_VKD_DISPLAY || IS_VFD_DISPLAY) + ; // turns display off entirely (whoops!) + else + write (fd, "\x0FE" "B" "\x000", 3); + break; + default: // ignored... + break; + } } ///////////////////////////////////////////////////////////////// @@ -350,21 +506,24 @@ void MtxOrb_output (int on) { char out[5]; - if ( ((MtxOrb_type == MTXORB_LCD) || (MtxOrb_type == MTXORB_VFD)) ) { - if (on) { - sprintf (out, "%cW", 254); - } else { - sprintf (out, "%cV", 254); - } - write (fd, out, 2); + + if (IS_LCD_DISPLAY || IS_VFD_DISPLAY) { + // LCD and VFD displays only have one output port + (on) ? + write (fd, "\x0FEW", 2) : + write (fd, "\x0FEV", 2); } else { int i; - for(i=0; i<6; i++) { - if ( on & (1 << i) ) { - sprintf (out, "%cW%c", 254, i+1); - } else { - sprintf (out, "%cV%c", 254, i+1); - } + + // Other displays have six output ports; + // the value "on" is a binary value determining which + // ports are turned on (1) and off (0). + + on = on & 077; // strip to six bits + for(i = 0; i < 6; i++) { + (on & (1 << i)) ? + sprintf (out, "\x0FEW%c", i + 1) : + sprintf (out, "\x0FEV%c", i + 1); write (fd, out, 3); } } @@ -376,12 +535,7 @@ MtxOrb_output (int on) static void MtxOrb_linewrap (int on) { - char out[4]; - if (on) - sprintf (out, "%cC", 254); - else - sprintf (out, "%cD", 254); - write (fd, out, 2); + (on) ? write (fd, "\x0FE" "C", 2) : write (fd, "\x0FE" "D", 2); } ///////////////////////////////////////////////////////////////// @@ -390,12 +544,7 @@ MtxOrb_linewrap (int on) static void MtxOrb_autoscroll (int on) { - char out[4]; - if (on) - sprintf (out, "%cQ", 254); - else - sprintf (out, "%cR", 254); - write (fd, out, 2); + (on) ? write (fd, "\x0FEQ", 2) : write (fd, "\x0FER", 2); } // TODO: make sure this doesn't mess up non-VFD displays @@ -405,12 +554,7 @@ MtxOrb_autoscroll (int on) static void MtxOrb_cursorblink (int on) { - char out[4]; - if (on) - sprintf (out, "%cS", 254); - else - sprintf (out, "%cT", 254); - write (fd, out, 2); + (on) ? write (fd, "\x0FES", 2) : write (fd, "\x0FET", 2); } //// TODO: Might not be needed anymore... @@ -420,6 +564,7 @@ MtxOrb_cursorblink (int on) void MtxOrb_init_vbar () { +// Isn't this function supposed to go away? MtxOrb_init_all (vbar); } @@ -430,9 +575,132 @@ MtxOrb_init_vbar () void MtxOrb_init_hbar () { +// Isn't this function supposed to go away? MtxOrb_init_all (hbar); } +///////////////////////////////////////////////////////////////// +// Returns string with general information about the display +// +char * +MtxOrb_getinfo (void) +{ + char in = 0; + static char info[255]; + char tmp[255], buf[64]; + int i = 0; + fd_set rfds; + + struct timeval tv; + int retval; + + memset(info, '\0', sizeof(info)); + strcpy(info, "Matrix Orbital Driver "); + + /* + * Read type of display + */ + + write(fd, "\x0FE" "7", 2); + + /* Watch fd to see when it has input. */ + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + /* Wait the specified amount of time. */ + tv.tv_sec = 0; // seconds + tv.tv_usec = 500; // microseconds + + retval = select(1, &rfds, NULL, NULL, &tv); + + if (retval) { + if (read (fd, &in, 1) < 0) { + syslog(LOG_WARNING, "MatrixOrbital driver: unable to read data"); + } else { + switch (in) { + case '\x01': strcat(info, "LCD0821 "); break; + case '\x03': strcat(info, "LCD2021 "); break; + case '\x04': strcat(info, "LCD1641 "); break; + case '\x05': strcat(info, "LCD2041 "); break; + case '\x06': strcat(info, "LCD4021 "); break; + case '\x07': strcat(info, "LCD4041 "); break; + case '\x08': strcat(info, "LK202-25 "); break; + case '\x09': strcat(info, "LK204-25 "); break; + case '\x0A': strcat(info, "LK404-55 "); break; + case '\x0B': strcat(info, "VFD2021 "); break; + case '\x0C': strcat(info, "VFD2041 "); break; + case '\x0D': strcat(info, "VFD4021 "); break; + case '\x0E': strcat(info, "VK202-25 "); break; + case '\x0F': strcat(info, "VK204-25 "); break; + case '\x10': strcat(info, "GLC12232 "); break; + case '\x11': strcat(info, "GLC12864 "); break; + case '\x12': strcat(info, "GLC128128 "); break; + case '\x13': strcat(info, "GLC24064 "); break; + case '\x14': strcat(info, "GLK12864-25 "); break; + case '\x15': strcat(info, "GLK24064-25 "); break; + case '\x21': strcat(info, "GLK128128-25 "); break; + case '\x22': strcat(info, "GLK12232-25 "); break; + case '\x31': strcat(info, "LK404-AT "); break; + case '\x32': strcat(info, "VFD1621 "); break; + case '\x33': strcat(info, "LK402-12 "); break; + case '\x34': strcat(info, "LK162-12 "); break; + case '\x35': strcat(info, "LK204-25PC "); break; + default: //sprintf(tmp, "Unknown (%X) ", in); strcat(info, tmp); + break; + } + } + } else + syslog(LOG_WARNING, "MatrixOrbital driver: unable to read device type"); + + /* + * Read serial number of display + */ + + memset(tmp, '\0', sizeof(tmp)); + write(fd, "\x0FE" "5", 2); + + /* Wait the specified amount of time. */ + tv.tv_sec = 0; // seconds + tv.tv_usec = 500; // microseconds + + retval = select(1, &rfds, NULL, NULL, &tv); + + if (retval) { + if (read (fd, &tmp, 2) < 0) { + syslog(LOG_WARNING, "MatrixOrbital driver: unable to read data"); + } else { + sprintf(buf, "Serial No: %ld ", (long int) tmp); + strcat(info, buf); + } + } else + syslog(LOG_WARNING, "MatrixOrbital driver: unable to read device serial number"); + + /* + * Read firmware revision number + */ + + memset(tmp, '\0', sizeof(tmp)); + write(fd, "\x0FE" "6", 2); + + /* Wait the specified amount of time. */ + tv.tv_sec = 0; // seconds + tv.tv_usec = 500; // microseconds + + retval = select(1, &rfds, NULL, NULL, &tv); + + if (retval) { + if (read (fd, &tmp, 2) < 0) { + syslog(LOG_WARNING, "MatrixOrbital driver: unable to read data"); + } else { + sprintf(buf, "Firmware Rev. %ld ", (long int) tmp); + strcat(info, buf); + } + } else + syslog(LOG_WARNING, "MatrixOrbital driver: unable to read device firmware revision"); + + return info; +} + // TODO: Finish the support for bar growing reverse way. // TODO: Need a "y" as input also !!! ///////////////////////////////////////////////////////////////// @@ -447,9 +715,9 @@ MtxOrb_vbar (int x, int len) int y; -// TODO: REMOVE THE NEXT LINE FOR TESTING ONLY... +// REMOVE THE NEXT LINE FOR TESTING ONLY... // len=-len; -// TODO: REMOVE THE PREVIOUS LINE FOR TESTING ONLY... +// REMOVE THE PREVIOUS LINE FOR TESTING ONLY... if (len > 0) { for (y = lcd.hgt; y > 0 && len > 0; y--) { @@ -518,10 +786,8 @@ MtxOrb_hbar (int x, int y, int len) void MtxOrb_init_num () { - char out[3]; if (custom != bign) { - sprintf (out, "%cn", 254); - write (fd, out, 2); + write (fd, "\x0FEn", 2); custom = bign; } } @@ -535,7 +801,7 @@ void MtxOrb_num (int x, int num) { char out[5]; - sprintf (out, "%c#%c%c", 254, x, num); + sprintf (out, "\x0FE#%c%c", x, num); write (fd, out, 4); } @@ -560,7 +826,7 @@ MtxOrb_set_char (int n, char *dat) if (!dat) return; - sprintf (out, "%cN%c", 254, n); + sprintf (out, "\x0FEN%c", n); write (fd, out, 3); for (row = 0; row < lcd.cellhgt; row++) { @@ -636,7 +902,7 @@ MtxOrb_draw_frame (char *dat) write(fd, dat, lcd.wid*lcd.hgt); */ for (i = 0; i < lcd.hgt; i++) { - sprintf (out, "%cG%c%c", 254, 1, i + 1); + sprintf (out, "\x0FEG\x001%c", i + 1); write (fd, out, 4); write (fd, dat + (lcd.wid * i), lcd.wid); } @@ -650,6 +916,7 @@ char MtxOrb_getkey () { char in = 0; + read (fd, &in, 1); return in; } @@ -802,6 +1069,17 @@ MtxOrb_ask_bar (int type) return (pos); } +///////////////////////////////////////////////////////////// +// Does the heartbeat... +// +char +MtxOrb_heartbeat (int timer) +{ + MtxOrb_icon (!((timer + 4) & 5), 0); + MtxOrb_chr (lcd.wid, 1, 0); + return (char) 0; +} + ///////////////////////////////////////////////////////////////// // Sets up a well known character for use. // @@ -1044,6 +1322,8 @@ MtxOrb_set_known_char (int car, int type) // TODO: Remove this code wich was use for developpement. // PS: There might be reference to this code left, so keep it for some time. +// +// MtxOrb_init_hbar and MtxOrb_init_vbar use it; it's prototyped in MtxOrb.h ... void MtxOrb_init_all (int type) { diff --git a/server/drivers/MtxOrb.h b/server/drivers/MtxOrb.h index b4c0824..6419112 100644 --- a/server/drivers/MtxOrb.h +++ b/server/drivers/MtxOrb.h @@ -22,9 +22,11 @@ void MtxOrb_set_char (int n, char *dat); void MtxOrb_icon (int which, char dest); void MtxOrb_draw_frame (char *dat); char MtxOrb_getkey (); +char * MtxOrb_getinfo (); -void MtxOrb_init_all (int type); int MtxOrb_ask_bar (int type); void MtxOrb_set_known_char (int car, int type); +// Isn't this function supposed to go away? +void MtxOrb_init_all (int type); #endif diff --git a/server/drivers/joy.c b/server/drivers/joy.c index 125d008..a6ec77b 100644 --- a/server/drivers/joy.c +++ b/server/drivers/joy.c @@ -1,3 +1,17 @@ +/* + * Joystick input driver for LCDd + * + * Only two unique functions are defined: + * + * joy_getkey + * joy_close + * + * All others are at their defaults. + * + * The code here is configured for a Gravis Gamepad (2 axis, 4 button) + * + */ + #include #include #include @@ -9,6 +23,9 @@ #include #include +#ifndef JSIOCGNAME +#define JSIOCGNAME(len) _IOC(_IOC_READ, 'j', 0x13, len) /* get identifier string */ +#endif #include "shared/debug.h" #include "shared/str.h" @@ -18,10 +35,6 @@ #include "lcd.h" #include "joy.h" -////////////////////////////////////////////////////////////////////////// -////////////////////// Base "class" to derive from /////////////////////// -////////////////////////////////////////////////////////////////////////// - lcd_logical_driver *joy; int fd; diff --git a/server/drivers/lcd.c b/server/drivers/lcd.c index 8b30cd4..10bbf45 100644 --- a/server/drivers/lcd.c +++ b/server/drivers/lcd.c @@ -11,6 +11,7 @@ #endif #include "shared/LL.h" +#include "shared/debug.h" #include "lcd.h" @@ -68,6 +69,15 @@ #include "glk.h" #endif +// Make program more readable and understandable; +// hide details... +#define ResetList(a) LL_Rewind(a) +#define GetDriverData(a) ((lcd_logical_driver *)LL_Get(a)) +#define NextDriver(a) (LL_Next(a)) +#define MoreDrivers(a) (LL_Next(a) == 0) +#define DriverPresent(a) (a) +#define FunctionPresent(a) ((a) != 0) + // TODO: Make a Windows server, and clients...? lcd_logical_driver lcd; @@ -120,7 +130,9 @@ lcd_physical_driver drivers[] = { LL *list; //////////////////////////////////////////////////////////// -// This sets up which driver to use and initializes stuff. +// This function initializes a few basics as well as the +// "base" array. To initialize a specific driver, use the +// lcd_add_driver() function. // int lcd_init (char *args) @@ -134,8 +146,12 @@ lcd_init (char *args) return -1; } + // This sets up functions which call all drivers in + // round-robin fashion lcd_drv_init (NULL, NULL); + // "base" driver is a special driver which is always + // loaded... err = lcd_add_driver ("base", args); lcd.wid = 20; @@ -162,6 +178,10 @@ lcd_init (char *args) // TODO: lcd_remove_driver() +// This initializes the specified driver and sends parameters to +// it. This is the function which calls, for example, +// MtxOrb_init. The specifics come from the drivers[] array. +// int lcd_add_driver (char *driver, char *args) { @@ -177,6 +197,8 @@ lcd_add_driver (char *driver, char *args) //printf("Found driver: %s (%s)\n", drivers[i].name, driver); + // This creates an instance of the lcd structure specific to the + // driver... it is passed to the driver's init routine... add = malloc (sizeof (lcd_logical_driver)); if (!add) { printf ("Couldn't allocate driver \"%s\".\n", driver); @@ -204,6 +226,7 @@ lcd_add_driver (char *driver, char *args) LL_Push (list, (void *) add); + // This is where the driver itself is actually called; return drivers[i].init (add, args); } } @@ -241,6 +264,9 @@ lcd_shutdown () return 0; } +// This sets up all of the "wrapper" driver functions +// which call all of the drivers in turn. +// int lcd_drv_init (struct lcd_logical_driver *driver, char *args) { @@ -290,6 +316,7 @@ lcd_drv_init (struct lcd_logical_driver *driver, char *args) lcd.draw_frame = lcd_drv_draw_frame; lcd.getkey = lcd_drv_getkey; + lcd.getinfo = lcd_drv_getinfo; return 1; // 1 is arbitrary. (must be 1 or more) } @@ -713,3 +740,34 @@ lcd_drv_getkey () return 0; } + +#define MAX_INFO_BUF 1024 + +char * +lcd_drv_getinfo () +{ + static char info[MAX_INFO_BUF]; + char *p; + lcd_logical_driver *driver; + + memset(info, '\0', sizeof(info)); + + ResetList(list); + do { + driver = GetDriverData(list); + + if (DriverPresent(driver)) { + if (FunctionPresent(driver->getinfo)) { + p = (char *) driver->getinfo (); + if (strlen(p) + strlen(info) < (MAX_INFO_BUF - 2)) { + strcat(info, p); + } + strcat(info, "\n"); + } + + } + + } while (MoreDrivers(list)); + + return info; +} diff --git a/server/drivers/lcd.h b/server/drivers/lcd.h index 974b505..8bf2e59 100644 --- a/server/drivers/lcd.h +++ b/server/drivers/lcd.h @@ -52,6 +52,9 @@ typedef struct lcd_logical_driver { // Returns 0 for "no key pressed", or (A-Z). char (*getkey) (); + // Returns pointer to static string. + char * (*getinfo) (); + // more? } lcd_logical_driver; @@ -83,5 +86,6 @@ void lcd_drv_icon (int which, char dest); void lcd_drv_flush_box (int lft, int top, int rgt, int bot); void lcd_drv_draw_frame (); char lcd_drv_getkey (); +char *lcd_drv_getinfo (); #endif diff --git a/server/input.c b/server/input.c index 1781303..5613fd0 100644 --- a/server/input.c +++ b/server/input.c @@ -24,9 +24,49 @@ E-Z Ignored */ +// These are the keys for a (likely) properly functioning LK202-25... +// #define KEY_UP 'I' +// #define KEY_DOWN 'J' +// #define KEY_LEFT 'O' +// #define KEY_RIGHT 'E' +// #define KEY_F1 'N' +// #define KEY_F2 'M' +// #define KEY_ENTER 'H' + +// These are the keys for my (possibly) broken LK202-25... +#define KEY_UP 'I' +#define KEY_DOWN 'F' +#define KEY_LEFT 'K' +#define KEY_RIGHT 'A' +#define KEY_F1 'N' +// #define KEY_F2 'M' +// #define KEY_ENTER 'H' + +// TODO: Generalize these into each driver... +// +// Really, what this comes down to, is different settings for +// different displays. Unless you want to recompile for all +// the defaults, these key settings must be in the driver. +// +// But then, which driver is active and which screen takes which +// input and... (sigh). +// +#define PAUSE_KEY KEY_F1 +#define BACK_KEY KEY_LEFT +#define FORWARD_KEY KEY_RIGHT +#define MAIN_MENU_KEY KEY_DOWN + +// This seems somewhat arbitrary, but it IS the original settings: +// +// #define PAUSE_KEY 'A' +// #define BACK_KEY 'B' +// #define FORWARD_KEY 'C' +// #define MAIN_MENU_KEY 'D' + #include #include #include +#include #include "shared/sockets.h" #include "shared/debug.h" @@ -42,6 +82,11 @@ #include "input.h" +#define KeyWanted(a,b) ((a) && strchr((a), (b))) +#define CurrentScreen screenlist_current +#define FirstClient(a) (client *)LL_GetFirst(a); +#define NextClient(a) (client *)LL_GetNext(a); + int server_input (int key); // FIXME! The server tends to crash when "E" is pressed.. (?!) @@ -51,46 +96,65 @@ int server_input (int key); int handle_input () { - char str[256]; + char str[15]; int key; screen *s; widget *w; client *c; - key = lcd.getkey (); - - if (!key) + if ((key = lcd.getkey ()) == 0) return 0; - debug ("handle_input(%c)\n", (char) key); + //debug ("handle_input(%c)\n", (char) key); - if (key) { - // TODO: Interpret and translate keys! + // Sequence: + // Does the current screen want the key? + // IfTrue: handle and quit + // IfFalse: + // Let ALL clients handle it if they want + // Let Server handle it, too + // + // This leads to a unique situation: + // First: multiple clients may handle the same key in multiple ways + // Second: the server may handle the key differently yet + // + // Solution: Only the current screen can handle the key press. + // Alternately, only one client can handle the key press. - // Give current screen a shot at the key first - s = screenlist_current (); - if( s->keys && strchr( s->keys, key ) ) { - // This screen wants this key. Tell it we got one - sprintf(str, "key %c\n", key); - sock_send_string(s->parent->sock, str); - // Nobody else gets this key - } else { - // Give key to clients who want it - c = (client *)LL_GetFirst(clients); - while(c) { - // If the client should have this keypress... - if( c->data->client_keys && strchr(c->data->client_keys, key) ) { - // Send keypress to client - sprintf(str, "key %c\n", key); - sock_send_string(c->sock, str); - }; - c = (client *)LL_GetNext(clients); - } // while clients + // TODO: Interpret and translate keys! - // Give server a shot at all keys - server_input (key); - } - }; + // Give current screen a shot at the key first + s = CurrentScreen (); + + if (KeyWanted(s->keys, key)) { + // This screen wants this key. Tell it we got one + snprintf(str, sizeof(str), "key %c\n", key); + sock_send_string(s->parent->sock, str); + // Nobody else gets this key + } + + // if the current screen doesn't want it, + // ignore the key... + +// else { +// // Give key to clients who want it +// +// c = FirstClient(clients); +// +// while (c) { +// // If the client should have this keypress... +// if(KeyWanted(c->data->client_keys,key)) { +// // Send keypress to client +// snprintf(str, sizeof(str), "key %c\n", key); +// sock_send_string(c->sock, str); +// break; // first come, first serve +// }; +// c = NextClient(clients); +// } // while clients +// +// // Give server a shot at all keys +// server_input (key); +// } return 0; } @@ -99,29 +163,30 @@ int server_input (int key) { debug ("server_input(%c)\n", (char) key); + syslog(LOG_DEBUG, "key %d pressed on device", key); - switch (key) { - case 'A': - if (screenlist_action == SCR_HOLD) - screenlist_action = 0; - else - screenlist_action = SCR_HOLD; - break; - case 'B': - screenlist_action = SCR_BACK; - screenlist_prev (); - break; - case 'C': - screenlist_action = SCR_SKIP; - screenlist_next (); - break; - case 'D': - debug ("got the menu key!\n"); - server_menu (); - break; - default: - debug ("server_input: Unused key \"%c\" (%i)\n", (char) key, key); - break; + switch ((char) key) { + case PAUSE_KEY: + if (screenlist_action == SCR_HOLD) + screenlist_action = 0; + else + screenlist_action = SCR_HOLD; + break; + case BACK_KEY: + screenlist_action = SCR_BACK; + screenlist_prev (); + break; + case FORWARD_KEY: + screenlist_action = SCR_SKIP; + screenlist_next (); + break; + case MAIN_MENU_KEY: + debug ("got the menu key!\n"); + server_menu (); + break; + default: + debug ("server_input: Unused key \"%c\" (%i)\n", (char) key, key); + break; } return 0; diff --git a/server/main.c b/server/main.c index 6f69e07..799d551 100644 --- a/server/main.c +++ b/server/main.c @@ -18,6 +18,10 @@ #include #include #include +#include +#include +#include +#include #include "shared/debug.h" @@ -32,10 +36,30 @@ #include "input.h" #include "main.h" +#define MAX_TIMER 0x10000 +#define DEFAULT_USER "nobody" + char *version = VERSION; char *protocol_version = PROTOCOL_VERSION; char *build_date = __DATE__; +/* Socket to bind to... + + Using loopback is much more secure; it means that this port is + accessible only to programs running locally on the same host as LCDd. + + Using variables for these means that (later) we can select which port + and which address to bind to at run time. */ + +char bind_addr[64] = "127.0.0.1"; +int lcd_port = LCDPORT; + +// The parameter structure and args[] should +// be removed when getopt(3) is implemented, +// as there won't be any need for them then. +typedef struct parameter { + char *sh, *lg; // short and long versions +} parameter; // This is currently only a list of available arguments, but doesn't // really *do* anything. It just helps to figure out which parameters @@ -54,6 +78,34 @@ static parameter args[] = { void exit_program (int val); void HelpScreen (); +// At this point, this function will only succeed; +// all other options will stop the program. +// However, it may not always be thus; so we prepared +// for this possibility by making it return an int. +// +int drop_privs(char *user) { + struct passwd *pwent; + + if (getuid() == 0 || geteuid() == 0) { + if ((pwent = getpwnam(user)) == NULL) { + if (errno) { + perror("LCDd: getpwnam"); + exit(1); + } else { + fprintf(stderr, "user %s not a valid user!", user); + exit(1); + } + } else { + if (setuid(pwent->pw_uid) < 0) { + fprintf(stderr, "unable to switch to user %s\n", user); + perror("LCDd: setuid"); + exit(1); + } + } + } + return 0; +} + int main (int argc, char **argv) { @@ -64,6 +116,7 @@ main (int argc, char **argv) int disable_server_screen = 1; screen *s = NULL; char *str, *ing; // strings for commandline handling + char *user = DEFAULT_USER; // Ctrl-C will cause a clean exit... signal (SIGINT, exit_program); @@ -86,14 +139,31 @@ main (int argc, char **argv) // Now, go into daemon mode... #ifndef DEBUG + openlog("LCDd", LOG_PID, LOG_DAEMON); + syslog(LOG_NOTICE, "server version %s starting up (protocol version %s)", + version, protocol_version); + syslog(LOG_NOTICE, "server built on %s", + build_date); + if (daemon_mode) { int child; + + syslog(LOG_NOTICE, "server forking to background"); + if ((child = fork ()) != 0) { usleep (1500000); // Wait for child to initialize exit (0); /* PARENT EXITS */ } // This line removed because it eats error messages... //setsid(); /* RELEASE TTY */ + // + // After this point, as a daemon, no error messages should + // go to the console unless drastic; rather, they should go to syslog + // + // However, option processing is not yet done, nor is any initialization (!) + // So we must wait until the main loop. + } else { + syslog(LOG_NOTICE, "server running in foreground"); } #endif @@ -195,13 +265,20 @@ main (int argc, char **argv) } } - // Now init a bunch of required stuff... + // switch to a different user for the real work... + if (lcd_port >= 1024) + drop_privs(user); - if (sock_create_server () <= 0) { + if (sock_create_server (&bind_addr, lcd_port) <= 0) { printf ("Error opening socket.\n"); return 1; } + if (lcd_port > 1024) + drop_privs(user); + + // Now init a bunch of required stuff... + if (client_init () < 0) { printf ("Error initializing client list\n"); return 1; @@ -218,29 +295,48 @@ main (int argc, char **argv) } else if (disable_server_screen) { server_screen->priority = 256; } + + // Probably a better place to fork + // // Main loop... + + syslog(LOG_NOTICE, "using %dx%d LCD with cells %dx%d", + lcd.wid, lcd.hgt, lcd.cellwid, lcd.cellhgt); + while (1) { - sock_poll_clients (); - parse_all_client_messages (); - handle_input (); + sock_poll_clients (); // poll clients for input + parse_all_client_messages (); // analyze input from network clients + handle_input (); // handle key input from devices // TODO: Move this code to screenlist.c... // ... it should just say "handle_screens();" // Timer gets reset by screenlist_next() + timer++; + // this line's here because s was getting overwritten at one time... //s = screenlist_current(); + if (s && (timer >= s->duration)) { screenlist_next (); } - // Just in case it gets out of hand... - if (timer >= 0x10000) - timer = 0; - update_server_screen (timer); - s = screenlist_current (); - // render something here... - if (s) + // Just in case it gets out of hand... + if (timer >= MAX_TIMER) + timer = 0; + + // Update server screen with the right number + // of clients and screens... + // + // TODO: Move this call to every client connection + // and every screen add... + + update_server_screen (timer); + + // draw the current scren + + if ((s = screenlist_current ()) != NULL) + draw_screen (s, timer); else no_screen_screen (timer); @@ -257,9 +353,22 @@ main (int argc, char **argv) void exit_program (int val) { + char buf[64]; + // TODO: These things shouldn't be so interdependent. The order // things are shut down in shouldn't matter... + strcpy(buf, "server shutting down on "); + switch(val) { + case 1: strcat(buf, "SIGHUP"); break; + case 2: strcat(buf, "SIGINT"); break; + case 15: strcat(buf, "SIGTERM"); break; + default: sprintf(buf, "server shutting down on signal %d", val); break; + // Other values should not be seen, but just in case.. + } + + // Make note in the logs... + syslog(LOG_NOTICE, buf); // Say goodbye! goodbye_screen (); // Can go anywhere... diff --git a/server/main.h b/server/main.h index f6a12de..a0e60e1 100644 --- a/server/main.h +++ b/server/main.h @@ -26,8 +26,8 @@ typedef struct screen_size { int wid, hgt; } screen_size; -typedef struct parameter { - char *sh, *lg; // short and long versions -} parameter; +#define DEFAULT_SCREEN_PRIORITY 128 +#define DEFAULT_SCREEN_DURATION 32 +#define DEFAULT_HEARTBEAT 1 #endif diff --git a/server/menu.c b/server/menu.c index fe0b1e7..ad318e1 100644 --- a/server/menu.c +++ b/server/menu.c @@ -303,7 +303,7 @@ slid_func (menu_item * item) value = readfunc (MENU_READ); if (value < 0 || value >= MENU_CLOSE) return value; - sprintf (str, "%i", value); + snprintf (str, sizeof(str), "%i", value); if (lcd.hgt >= 4) { lcd.string (8, 4, str); value = (lcd.wid * lcd.cellwid * value / 256); diff --git a/server/menus.c b/server/menus.c index 03e3b45..aec5038 100644 --- a/server/menus.c +++ b/server/menus.c @@ -260,7 +260,7 @@ Server_screen_func (int input) if (server_screen->priority < 256) server_screen->priority = 256; else - server_screen->priority = 128; + server_screen->priority = DEFAULT_SCREEN_PRIORITY; } return (MENU_OK | (server_screen->priority < 256)); diff --git a/server/parse.c b/server/parse.c index cd01090..4a5ca71 100644 --- a/server/parse.c +++ b/server/parse.c @@ -20,21 +20,32 @@ #include "client_functions.h" #include "parse.h" +// This is a big function... TOO big. How to trim.... +// TODO: Simplify... simplify... int parse_all_client_messages () { - int i, j; + int i, j, len; int newtoken, inquote; client *c; - char *str; + char *str, *p, *q, *s; // char *tok; int argc; char *argv[256]; - char delimiters[] = " \0"; - char leftquote[] = "\0\"'`([{\0"; - char rightquote[] = "\0\"'`)]}\0"; + char delimiters[] = " "; + char leftquote[] = "\"'`([{"; + char rightquote[] = "\"'`)]}"; char errmsg[256]; int invalid = 0; + int quoteindex; + + for (i = 0; i <= 256; i++) { + argv[i] == NULL; + } + +#define SEPARATOR_CHAR ' ' +#define LINE_TERM_CHAR '\0' +#define COMMENT_CHAR '#' //debug("parse: Rewinding list...\n"); LL_Rewind (clients); @@ -48,76 +59,107 @@ parse_all_client_messages () for (str = client_get_message (c); str; str = client_get_message (c)) { debug ("parse: ...%s\n", str); // Now, split up the string... - //len = strlen(str); argc = 0; - newtoken = 1; - inquote = 0; - for (i = 0; str[i]; i++) { - if (inquote) // Scan for the end of the quote - { - if (str[i] == rightquote[inquote]) { // Found the end of the quote - inquote = 0; - str[i] = 0; - newtoken = 1; - } - } else // Normal operation; split at delimiters - { - for (j = 1; leftquote[j]; j++) { - // Found the beginning of a new quote... - if (str[i] == leftquote[j]) { - inquote = j; - str[i] = 0; - continue; - } - } - for (j = 0; delimiters[j]; j++) { - // Break into a new string... - if (str[i] == delimiters[j]) { - str[i] = 0; - newtoken = 1; - continue; - } - } + i = 0; + q = p = str; + + if (*p == COMMENT_CHAR) { + continue; // found a comment line - skip it... + } + + //fprintf(stderr, "starting string scan...\n"); + + do { + // bypass initial white space... + while ((*p == SEPARATOR_CHAR) && (*p)) { + p++; + q++; } - if (newtoken && str[i]) { - newtoken = 0; - argv[argc] = str + i; - argc++; + + // If (*p) is null here, we reached the end of + // an empty parameter... so one of two things + // is true: + // + // 1. There is nothing but white space on this line (odd..) + // 2. This is trailing white space (odd... but allowable) + + if (*p == LINE_TERM_CHAR) { + break; + // if there are no arguments, argc == 0 and will fail + // appropriately... + // + // if this is trailing white space, ignore the argc++ at the + // end and claim this as the end... + } + + // Handle quoted strings... + if ((s = strchr(leftquote, *p)) != NULL) { + quoteindex = s - leftquote; + //fprintf(stderr, "found <%c> at index [%d] = <%c>\n", *p, quoteindex, leftquote[quoteindex]); + q = ++p; // past open quote... + while ((rightquote[quoteindex] != *p) && (*p != LINE_TERM_CHAR)) { + p++; + } + if (*p == LINE_TERM_CHAR) { + // We just sucked up the rest of the command line: ERROR!! + snprintf (errmsg, sizeof(errmsg), "huh? unterminated string! missing ending %c\n", + rightquote[quoteindex]); + sock_send_string (c->sock, errmsg); + continue; + } else { + *p = LINE_TERM_CHAR; // terminate string + p++; // bypass to next character + // Note that next character could be a EndOfLine (null) + // if the string was last on the line, or it could be + // something else... is it a blank? + if (*p != SEPARATOR_CHAR && *p != LINE_TERM_CHAR) { + sock_send_string (c->sock, "huh? improperly terminated string! (missing whitespace)\n"); + continue; + } + } + + // Otherwise, normal string... } else { + while (*p != SEPARATOR_CHAR && *p != LINE_TERM_CHAR) + p++; } - } - if (inquote) { - sprintf (errmsg, "huh? Unterminated string: missing %c\n", rightquote[inquote]); - sock_send_string (c->sock, errmsg); - continue; - } -/* - for(tok = strtok(str, delimiters); - tok; - tok=strtok(NULL, delimiters)) - { - argv[argc] = tok; - argc++; - } -*/ + + // Not end of line? + if (*p) { + *p = LINE_TERM_CHAR; + //fprintf(stderr, "found new token: %s\n", q); + argv[i++] = q; + q = ++p; + } else { + //fprintf(stderr, "found new token: %s\n", q); + argv[i++] = q; + } + // At the end of this statement, + // *p will be '\0' if end of input reached; + // otherwise, it is the first character of the + // next part of the string. + + + argc++; + } while (*p); + + //fprintf(stderr, "exiting string scan...\n"); + argv[argc] = NULL; if (argc < 1) continue; // Now find and call the appropriate function... -// debug("parse: Finding function...\n"); invalid = 1; for (i = 0; commands[i].keyword; i++) { -// debug("(checking %s)\n", commands[i].keyword); if (0 == strcmp (argv[0], commands[i].keyword)) { -// debug("(FOUND %s)\n", commands[i].keyword); invalid = commands[i].function (c, argc, argv); -// debug("parse: Returned %i...\n", err); + break; // found our function - don't continue on... } } + if (invalid) { - // FIXME: Check for buffer overflows here... - sprintf (errmsg, "huh? Invalid command \"%s\"\n", argv[0]); + snprintf (errmsg, sizeof(errmsg), "huh? Invalid command \"%s\"\n", argv[0]); sock_send_string (c->sock, errmsg); } diff --git a/server/render.c b/server/render.c index eb00d9c..016e8f8 100644 --- a/server/render.c +++ b/server/render.c @@ -11,6 +11,10 @@ THIS FILE IS MESSY! Anyone care to rewrite it nicely? Please?? :) + NOTE: (from David Douthitt) Multiple screen sizes? Multiple simultaneous + screens? Horrors of horrors... next thing you know it'll be making coffee... + Better believe it'll take a while to do... + */ #include @@ -59,55 +63,75 @@ draw_screen (screen * s, int timer) reset = 0; old_s = s; + // Clear the LCD screen... lcd.clear (); - switch (backlight_state) { - case BACKLIGHT_OFF: - lcd.backlight (backlight_off_brightness); - break; - case BACKLIGHT_ON: - lcd.backlight (backlight_brightness); - break; - default: - if (backlight_state & BACKLIGHT_FLASH) { - tmp = (!((timer & 7) == 7)); - if (backlight_state & 1) - lcd.backlight (tmp ? backlight_brightness : backlight_off_brightness); - //lcd.backlight(backlight_brightness * (!((timer&7) == 7))); - else - lcd.backlight (!tmp ? backlight_brightness : backlight_off_brightness); - //lcd.backlight(backlight_brightness * ((timer&7) == 7)); - } else if (backlight_state & BACKLIGHT_BLINK) { - tmp = (!((timer & 14) == 14)); - if (backlight_state & 1) - lcd.backlight (tmp ? backlight_brightness : backlight_off_brightness); - //lcd.backlight(backlight_brightness * (!((timer&14) == 14))); - else - lcd.backlight (!tmp ? backlight_brightness : backlight_off_brightness); - //lcd.backlight(backlight_brightness * ((timer&14) == 14)); - } - break; + // lcd.backlight -- + // + // This should be in a separate function altogether. + // Perhaps several: lcd.backlight_off, lcd.backlight_on, + // lcd.backlight_brightness, lcd.backlight_flash ... + // + // Set up backlight to the correct state... + // NOTE: dirty stripping of other options... + switch (backlight_state & 1) { + // Backlight off (easy) + case BACKLIGHT_OFF: + lcd.backlight (BACKLIGHT_OFF); + break; + // Backlight on (easy) + case BACKLIGHT_ON: + lcd.backlight (BACKLIGHT_ON); + break; + default: + // Backlight flash: check timer and flip backlight as appropriate + if (backlight_state & BACKLIGHT_FLASH) { + tmp = (!((timer & 7) == 7)); + if (backlight_state & 1) + lcd.backlight (tmp ? backlight_brightness : backlight_off_brightness); + //lcd.backlight(backlight_brightness * (!((timer&7) == 7))); + else + lcd.backlight (!tmp ? backlight_brightness : backlight_off_brightness); + //lcd.backlight(backlight_brightness * ((timer&7) == 7)); + + // Backlight blink: check timer and flip backlight as appropriate + } else if (backlight_state & BACKLIGHT_BLINK) { + tmp = (!((timer & 14) == 14)); + if (backlight_state & 1) + lcd.backlight (tmp ? backlight_brightness : backlight_off_brightness); + //lcd.backlight(backlight_brightness * (!((timer&14) == 14))); + else + lcd.backlight (!tmp ? backlight_brightness : backlight_off_brightness); + //lcd.backlight(backlight_brightness * ((timer&14) == 14)); + } + break; } + // Output ports from LCD - outputs depend on the current screen lcd.output (output_state); + // Draw a frame... draw_frame (s->widgets, 'v', 0, 0, lcd.wid, lcd.hgt, s->wid, s->hgt, s->duration / s->hgt, timer); //debug("draw_screen done\n"); if (heartbeat) { - if ((s->heartbeat == 1) || heartbeat == HEART_ON) { + if ((s->heartbeat == HEART_ON) || heartbeat == HEART_ON) { // Set this to pulsate like a real heart beat... // (binary is fun... :) + // lcd.heartbeat (); lcd.icon (!((timer + 4) & 5), 0); lcd.chr (lcd.wid, 1, 0); } - if ((s->heartbeat == 2) && heartbeat != HEART_OFF) { - char *phases = "-\\|/"; - lcd.chr (lcd.wid, 1, phases[timer & 3]); - } + // else + // This seems unnecessary... heartbeat is nicer... + // if ((s->heartbeat == HEART_OPEN) && heartbeat != HEART_OFF) { + // char *phases = "-\\|/"; + // lcd.chr (lcd.wid, 1, phases[timer & 3]); + // } } + // flush display out, frame and all... lcd.flush (); //debug("draw_screen: %8x, %i\n", s, timer); @@ -116,15 +140,31 @@ draw_screen (screen * s, int timer) } +// The following function is positively ghastly (as was mentioned above!) +// Best thing to do is to remove support for frames... but anyway... +// static int -draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, int fwid, int fhgt, int fspeed, int timer) +draw_frame (LL * list, + char fscroll, // direction of scrolling + int left, // left edge of frame + int top, // top edge of frame + int right, // right edge of frame + int bottom, // bottom edge of frame + int fwid, // frame width? + int fhgt, // frame height? + int fspeed, // speed of scrolling... + int timer) // ? { + +#define VerticalScrolling (fscroll == 'v') +#define HorizontalScrolling (fscroll == 'h') + char str[BUFSIZE]; // scratch buffer widget *w; - int wid, hgt; // Width and height of visible frame area + int wid, hgt; // Width and height of visible frame area int x, y; - int fx, fy; // Scrolling offset for the frame... + int fx, fy; // Scrolling offset for the frame... int length, speed; //int lines; @@ -135,18 +175,22 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i fx = 0; fy = 0; - if (fscroll == 'v') { - + if (VerticalScrolling) { if (fspeed > 0) fy = (timer - fspeed) / fspeed; - if (fspeed < 0) + else if (fspeed < 0) fy = (-fspeed) * timer; + if (fy < 0) fy = 0; // Make sure the whole frame gets displayed, at least... + // ...by setting the action to RENDER_HOLD if no other action + // is currently defined... + if (!screenlist_action) screenlist_action = RENDER_HOLD; + if ((fy) > fhgt - 1) { // Release hold after it has been displayed if (!screenlist_action || screenlist_action == RENDER_HOLD) @@ -156,8 +200,9 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i fy %= fhgt; if (fy > fhgt - hgt) fy = fhgt - hgt; - } else if (fscroll == 'h') { // TODO: Frames don't scroll horizontally yet! + } else if (HorizontalScrolling) { + // TODO: Frames don't scroll horizontally yet! } //debug("draw_screen: %8x, %i\n", s, timer); @@ -166,6 +211,11 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i //debug("draw_frame: %8x, %i\n", frame, timer); +#define PositiveX(a) ((a)->x > 0) +#define PositiveY(a) ((a)->y > 0) +#define ValidPoint(a) (PositiveX(a) && PositiveY(a)) +#define TextPresent(a) ((a)->text) + LL_Rewind (list); do { w = (widget *) LL_Get (list); @@ -174,266 +224,266 @@ draw_frame (LL * list, char fscroll, int left, int top, int right, int bottom, i // TODO: Make this cleaner and more flexible! switch (w->type) { - case WID_STRING: - if ((w->x > 0) && (w->y > 0) && (w->text)) { - if ((w->y <= hgt + fy) && (w->y > fy)) { - if (w->x > wid) { w->x=wid; }; - strncpy (str, w->text, wid - w->x + 1); - str[wid - w->x + 1] = 0; - lcd.string (w->x + left, w->y + top - fy, str); + case WID_STRING: + if (ValidPoint(w) && TextPresent(w)) { + if ((w->y <= hgt + fy) && (w->y > fy)) { + if (w->x > wid) w->x=wid; + strncpy (str, w->text, wid - w->x + 1); + str[wid - w->x + 1] = 0; + lcd.string (w->x + left, w->y + top - fy, str); + } } - } - break; - case WID_HBAR: - if (reset) { - lcd.init_hbar (); - reset = 0; - } - if ((w->x > 0) && (w->y > 0)) { - if ((w->y <= hgt + fy) && (w->y > fy)) { + break; + case WID_HBAR: + if (reset) { + lcd.init_hbar (); + reset = 0; + } + if ((w->x > 0) && (w->y > 0)) { + if ((w->y <= hgt + fy) && (w->y > fy)) { + if (w->length > 0) { + if ((w->length / lcd.cellwid) < wid - w->x + 1) + lcd.hbar (w->x + left, w->y + top - fy, w->length); + else + lcd.hbar (w->x + left, w->y + top - fy, wid * lcd.cellwid); + } else if (w->length < 0) { + // TODO: Rearrange stuff to get left-extending + // hbars to draw correctly... + // .. er, this'll require driver modifications, + // so I'll leave it out for now. + } + } + } + break; + case WID_VBAR: // FIXME: Vbars don't work in frames! + if (reset) { + lcd.init_vbar (); + reset = 0; + } + if ((w->x > 0) && (w->y > 0)) { if (w->length > 0) { - if ((w->length / lcd.cellwid) < wid - w->x + 1) - lcd.hbar (w->x + left, w->y + top - fy, w->length); - else - lcd.hbar (w->x + left, w->y + top - fy, wid * lcd.cellwid); + lcd.vbar (w->x, w->length); } else if (w->length < 0) { - // TODO: Rearrange stuff to get left-extending - // hbars to draw correctly... + // TODO: Rearrange stuff to get down-extending + // vbars to draw correctly... // .. er, this'll require driver modifications, // so I'll leave it out for now. } } - } - break; - case WID_VBAR: // FIXME: Vbars don't work in frames! - if (reset) { - lcd.init_vbar (); - reset = 0; - } - if ((w->x > 0) && (w->y > 0)) { - if (w->length > 0) { - lcd.vbar (w->x, w->length); - } else if (w->length < 0) { - // TODO: Rearrange stuff to get down-extending - // vbars to draw correctly... - // .. er, this'll require driver modifications, - // so I'll leave it out for now. - } - } - break; - case WID_ICON: // FIXME: Not implemented - break; - case WID_TITLE: // FIXME: Doesn't work quite right in frames... - if (!w->text) break; - if (wid < 8) + case WID_ICON: // FIXME: Not implemented break; - - memset (str, 255, wid); - str[2] = ' '; - length = strlen (w->text); - if (length <= wid - 6) { - memcpy (str + 3, w->text, length); - str[length + 3] = ' '; - } else // Scroll the title, if it doesn't fit... - { - speed = 1; - x = timer / speed; - y = x / length; - - // Make sure the whole title gets displayed, at least... - if (!screenlist_action) - screenlist_action = RENDER_HOLD; - if (x > length - 6) { - // Release hold after it has been displayed - if (!screenlist_action || screenlist_action == RENDER_HOLD) - screenlist_action = 0; - } - x %= (length); - x -= 3; - if (x < 0) - x = 0; - if (x > length - (wid - 6)) - x = length - (wid - 6); - - if (y & 1) // Scrolling backwards... - { - x = (length - (wid - 6)) - x; - } - strncpy (str + 3, w->text + x, (wid - 6)); - str[wid - 3] = ' '; - } - str[wid] = 0; - - lcd.string (1 + left, 1 + top, str); - break; - case WID_SCROLLER: // FIXME: doesn't work in frames... - { - int offset; - int screen_width; + case WID_TITLE: // FIXME: Doesn't work quite right in frames... if (!w->text) break; - if (w->right < w->left) + if (wid < 8) break; - //printf("rendering: %s %d\n",w->text,timer); - screen_width = w->right - w->left + 1; - switch (w->length) { // actually, direction... - // FIXED: Horz scrollers don't show the - // last letter in the string... (1-off error?) - case 'h': - length = strlen (w->text) + 1; - if (length <= screen_width) { - /* it fits within the box, just render it */ - lcd.string (w->left, w->top, w->text); - } else { - int effLength = length - screen_width; - int necessaryTimeUnits = 0; - if (!screenlist_action) - screenlist_action = RENDER_HOLD; - if (w->speed > 0) { - necessaryTimeUnits = effLength * w->speed; - if (((timer / (effLength * w->speed)) % 2) == 0) { - //wiggle one way - offset = (timer % (effLength * w->speed)) - / w->speed; - } else { - //wiggle the other - offset = (((timer % (effLength * w->speed)) - - (effLength * w->speed) + 1) - / w->speed) * -1; - } - } else if (w->speed < 0) { - necessaryTimeUnits = effLength / (w->speed * -1); - if (((timer / (effLength / (w->speed * -1))) % 2) == 0) { - offset = (timer % (effLength / (w->speed * -1))) - * w->speed * -1; - } else { - offset = (((timer % (effLength / (w->speed * -1))) - * w->speed * -1) - effLength + 1) * -1; - } - } else { - offset = 0; - if (screenlist_action == RENDER_HOLD) - screenlist_action = 0; - } - if (timer > necessaryTimeUnits) { - if (screenlist_action == RENDER_HOLD) - screenlist_action = 0; - } - if (offset <= length) { - strncpy (str, &((w->text)[offset]), screen_width); - str[screen_width] = '\0'; - //printf("%s : %d\n",str,length-offset); - } else { - str[0] = '\0'; - } - lcd.string (w->left, w->top, str); + + memset (str, 255, wid); + str[2] = ' '; + length = strlen (w->text); + if (length <= wid - 6) { + memcpy (str + 3, w->text, length); + str[length + 3] = ' '; + } else // Scroll the title, if it doesn't fit... + { + speed = 1; + x = timer / speed; + y = x / length; + + // Make sure the whole title gets displayed, at least... + if (!screenlist_action) + screenlist_action = RENDER_HOLD; + if (x > length - 6) { + // Release hold after it has been displayed + if (!screenlist_action || screenlist_action == RENDER_HOLD) + screenlist_action = 0; } - break; - // FIXME: Vert scrollers don't always seem to scroll - // back up after hitting the bottom. They jump back to - // the top instead... (nevermind?) - case 'v': + x %= (length); + x -= 3; + if (x < 0) + x = 0; + if (x > length - (wid - 6)) + x = length - (wid - 6); + + if (y & 1) // Scrolling backwards... { - int i = 0; - length = strlen (w->text); + x = (length - (wid - 6)) - x; + } + strncpy (str + 3, w->text + x, (wid - 6)); + str[wid - 3] = ' '; + } + str[wid] = 0; + + lcd.string (1 + left, 1 + top, str); + break; + case WID_SCROLLER: // FIXME: doesn't work in frames... + { + int offset; + int screen_width; + if (!w->text) + break; + if (w->right < w->left) + break; + //printf("rendering: %s %d\n",w->text,timer); + screen_width = w->right - w->left + 1; + switch (w->length) { // actually, direction... + // FIXED: Horz scrollers don't show the + // last letter in the string... (1-off error?) + case 'h': + length = strlen (w->text) + 1; if (length <= screen_width) { - /* no scrolling required... */ + /* it fits within the box, just render it */ lcd.string (w->left, w->top, w->text); } else { - int lines_required = (length / screen_width) - + (length % screen_width ? 1 : 0); - int available_lines = (w->bottom - w->top + 1); - if (lines_required <= available_lines) { - // easy... - for (i = 0; i < lines_required; i++) { - strncpy (str, &((w->text)[i * screen_width]), screen_width); - str[screen_width] = '\0'; - lcd.string (w->left, w->top + i, str); + int effLength = length - screen_width; + int necessaryTimeUnits = 0; + if (!screenlist_action) + screenlist_action = RENDER_HOLD; + if (w->speed > 0) { + necessaryTimeUnits = effLength * w->speed; + if (((timer / (effLength * w->speed)) % 2) == 0) { + //wiggle one way + offset = (timer % (effLength * w->speed)) + / w->speed; + } else { + //wiggle the other + offset = (((timer % (effLength * w->speed)) + - (effLength * w->speed) + 1) + / w->speed) * -1; + } + } else if (w->speed < 0) { + necessaryTimeUnits = effLength / (w->speed * -1); + if (((timer / (effLength / (w->speed * -1))) % 2) == 0) { + offset = (timer % (effLength / (w->speed * -1))) + * w->speed * -1; + } else { + offset = (((timer % (effLength / (w->speed * -1))) + * w->speed * -1) - effLength + 1) * -1; } } else { - int necessaryTimeUnits = 0; - int effLines = lines_required - available_lines + 1; - int begin = 0; - if (!screenlist_action) - screenlist_action = RENDER_HOLD; - //printf("length: %d sw: %d lines req: %d avail lines: %d effLines: %d \n",length,screen_width,lines_required,available_lines,effLines); - if (w->speed > 0) { - necessaryTimeUnits = effLines * w->speed; - if (((timer / (effLines * w->speed)) % 2) == 0) { - //printf("up "); - begin = (timer % (effLines * w->speed)) - / w->speed; - } else { - //printf("down "); - begin = (((timer % (effLines * w->speed)) - - (effLines * w->speed) + 1) / w->speed) - * -1; - } - } else if (w->speed < 0) { - necessaryTimeUnits = effLines / (w->speed * -1); - if (((timer / (effLines / (w->speed * -1))) % 2) == 0) { - begin = (timer % (effLines / (w->speed * -1))) - * w->speed * -1; - } else { - begin = (((timer % (effLines / (w->speed * -1))) - * w->speed * -1) - effLines + 1) - * -1; - } - } else { - begin = 0; - } - //printf("rendering begin: %d timer: %d effLines: %d\n",begin,timer,effLines); - for (i = begin; i < begin + available_lines; i++) { - strncpy (str, &((w->text)[i * (screen_width)]), screen_width); - str[screen_width] = '\0'; - //printf("rendering: '%s' of %s\n", - //str,w->text); - lcd.string (w->left, w->top + (i - begin), str); - } - if (timer > necessaryTimeUnits) { - if (screenlist_action == RENDER_HOLD) - screenlist_action = 0; - } + offset = 0; + if (screenlist_action == RENDER_HOLD) + screenlist_action = 0; } + if (timer > necessaryTimeUnits) { + if (screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + if (offset <= length) { + strncpy (str, &((w->text)[offset]), screen_width); + str[screen_width] = '\0'; + //printf("%s : %d\n",str,length-offset); + } else { + str[0] = '\0'; + } + lcd.string (w->left, w->top, str); } break; + // FIXME: Vert scrollers don't always seem to scroll + // back up after hitting the bottom. They jump back to + // the top instead... (nevermind?) + case 'v': + { + int i = 0; + length = strlen (w->text); + if (length <= screen_width) { + /* no scrolling required... */ + lcd.string (w->left, w->top, w->text); + } else { + int lines_required = (length / screen_width) + + (length % screen_width ? 1 : 0); + int available_lines = (w->bottom - w->top + 1); + if (lines_required <= available_lines) { + // easy... + for (i = 0; i < lines_required; i++) { + strncpy (str, &((w->text)[i * screen_width]), screen_width); + str[screen_width] = '\0'; + lcd.string (w->left, w->top + i, str); + } + } else { + int necessaryTimeUnits = 0; + int effLines = lines_required - available_lines + 1; + int begin = 0; + if (!screenlist_action) + screenlist_action = RENDER_HOLD; + //printf("length: %d sw: %d lines req: %d avail lines: %d effLines: %d \n",length,screen_width,lines_required,available_lines,effLines); + if (w->speed > 0) { + necessaryTimeUnits = effLines * w->speed; + if (((timer / (effLines * w->speed)) % 2) == 0) { + //printf("up "); + begin = (timer % (effLines * w->speed)) + / w->speed; + } else { + //printf("down "); + begin = (((timer % (effLines * w->speed)) + - (effLines * w->speed) + 1) / w->speed) + * -1; + } + } else if (w->speed < 0) { + necessaryTimeUnits = effLines / (w->speed * -1); + if (((timer / (effLines / (w->speed * -1))) % 2) == 0) { + begin = (timer % (effLines / (w->speed * -1))) + * w->speed * -1; + } else { + begin = (((timer % (effLines / (w->speed * -1))) + * w->speed * -1) - effLines + 1) + * -1; + } + } else { + begin = 0; + } + //printf("rendering begin: %d timer: %d effLines: %d\n",begin,timer,effLines); + for (i = begin; i < begin + available_lines; i++) { + strncpy (str, &((w->text)[i * (screen_width)]), screen_width); + str[screen_width] = '\0'; + //printf("rendering: '%s' of %s\n", + //str,w->text); + lcd.string (w->left, w->top + (i - begin), str); + } + if (timer > necessaryTimeUnits) { + if (screenlist_action == RENDER_HOLD) + screenlist_action = 0; + } + } + } + break; + } + } + break; + } + case WID_FRAME: + { + // FIXME: doesn't handle nested frames quite right! + // doesn't handle scrolling in nested frames at all... + int new_left, new_top, new_right, new_bottom; + new_left = left + w->left - 1; + new_top = top + w->top - 1; + new_right = left + w->right; + new_bottom = top + w->bottom; + if (new_right > right) + new_right = right; + if (new_bottom > bottom) + new_bottom = bottom; + if (new_left >= right || new_top >= bottom) { // Do nothing if it's invisible... + } else { + draw_frame (w->kids, w->length, new_left, new_top, new_right, new_bottom, w->wid, w->hgt, w->speed, timer); } } break; - } - case WID_FRAME: - { - // FIXME: doesn't handle nested frames quite right! - // doesn't handle scrolling in nested frames at all... - int new_left, new_top, new_right, new_bottom; - new_left = left + w->left - 1; - new_top = top + w->top - 1; - new_right = left + w->right; - new_bottom = top + w->bottom; - if (new_right > right) - new_right = right; - if (new_bottom > bottom) - new_bottom = bottom; - if (new_left >= right || new_top >= bottom) { // Do nothing if it's invisible... - } else { - draw_frame (w->kids, w->length, new_left, new_top, new_right, new_bottom, w->wid, w->hgt, w->speed, timer); + case WID_NUM: // FIXME: doesn't work in frames... + // NOTE: y=10 means COLON (:) + if ((w->x > 0) && (w->y >= 0) && (w->y <= 10)) { + if (reset) { + lcd.init_num (); + reset = 0; + } + lcd.num (w->x + left, w->y); } - } - break; - case WID_NUM: // FIXME: doesn't work in frames... - // NOTE: y=10 means COLON (:) - if ((w->x > 0) && (w->y >= 0) && (w->y <= 10)) { - if (reset) { - lcd.init_num (); - reset = 0; - } - lcd.num (w->x + left, w->y); - } - break; - case WID_NONE: - default: - break; + break; + case WID_NONE: + default: + break; } } while (LL_Next (list) == 0); diff --git a/server/screen.c b/server/screen.c index 9815d56..05076c1 100644 --- a/server/screen.c +++ b/server/screen.c @@ -11,6 +11,7 @@ #include "widget.h" #include "screenlist.h" #include "screen.h" +#include "main.h" int default_priority = 128 ; int default_duration = 64 ; // About 8 seconds @@ -28,9 +29,9 @@ screen_create () s->id = NULL; s->name = NULL; - s->priority = default_priority ; - s->duration = default_duration ; - s->heartbeat = 1; + s->priority = DEFAULT_SCREEN_PRIORITY; + s->duration = DEFAULT_SCREEN_DURATION; + s->heartbeat = DEFAULT_HEARTBEAT; s->wid = lcd.wid; s->hgt = lcd.hgt; s->keys = NULL; diff --git a/server/screenlist.c b/server/screenlist.c index 8409a65..e8da137 100644 --- a/server/screenlist.c +++ b/server/screenlist.c @@ -112,7 +112,7 @@ screenlist_current () c = old_s->parent; if (c) // Tell the client we're not listening any more... { - sprintf (str, "ignore %s\n", old_s->id); + snprintf (str, sizeof(str), "ignore %s\n", old_s->id); sock_send_string (c->sock, str); } else // The server has the display, so do nothing { @@ -125,7 +125,7 @@ screenlist_current () c = s->parent; if (c) // Tell the client we're paying attention... { - sprintf (str, "listen %s\n", s->id); + snprintf (str, sizeof(str), "listen %s\n", s->id); sock_send_string (c->sock, str); } else // The server has the display, so do nothing { diff --git a/server/serverscreens.c b/server/serverscreens.c index 8f371d0..abe6676 100644 --- a/server/serverscreens.c +++ b/server/serverscreens.c @@ -26,6 +26,11 @@ char one[256] = ""; char two[256] = ""; char three[256] = ""; +#define WidgetXPos(w,a) (w)->x = (a) +#define WidgetYPos(w,a) (w)->y = (a) +#define WidgetText(w,a) (w)->text = (a) +#define WidgetString(w,a,b,t) {WidgetXPos(w,a);WidgetYPos(w,b);WidgetText(w,t);} + int server_screen_init () { @@ -44,46 +49,39 @@ server_screen_init () server_screen->name = name; server_screen->duration = 8; // 1 second, instead of 4... - // TODO: Error-checking? - widget_add (server_screen, "title", "title", NULL, 1); - widget_add (server_screen, "one", "string", NULL, 1); - widget_add (server_screen, "two", "string", NULL, 1); - widget_add (server_screen, "three", "string", NULL, 1); + if (widget_add (server_screen, "title", "title", NULL, 1) != 0) { + fprintf (stderr, "server_screen_init: internal error: could not add title widget\n"); + } + if (widget_add (server_screen, "one", "string", NULL, 1) != 0) { + fprintf (stderr, "server_screen_init: internal error: could not add title widget\n"); + } + if (widget_add (server_screen, "two", "string", NULL, 1) != 0) { + fprintf (stderr, "server_screen_init: internal error: could not add title widget\n"); + } + if (widget_add (server_screen, "three", "string", NULL, 1) != 0) { + fprintf (stderr, "server_screen_init: internal error: could not add title widget\n"); + } // Now, initialize all the widgets... - w = widget_find (server_screen, "title"); - if (w) { - w->text = title; - } else { + if ((w = widget_find (server_screen, "title")) != NULL) { + WidgetText(w,title); + } else fprintf (stderr, "server_screen_init: Can't find title\n"); - } - w = widget_find (server_screen, "one"); - if (w) { - w->x = 1; - w->y = 2; - w->text = one; - } else { + if ((w = widget_find (server_screen, "one")) != NULL) + WidgetString(w,1,2,one) + else fprintf (stderr, "server_screen_init: Can't find widget one\n"); - } - w = widget_find (server_screen, "two"); - if (w) { - w->x = 1; - w->y = 3; - w->text = two; - } else { + if ((w = widget_find (server_screen, "two")) != NULL) + WidgetString(w,1,3,two) + else fprintf (stderr, "server_screen_init: Can't find widget two\n"); - } - w = widget_find (server_screen, "three"); - if (w) { - w->x = 1; - w->y = 4; - w->text = three; - } else { + if ((w = widget_find (server_screen, "three")) != NULL) + WidgetString(w,1,4,three) + else fprintf (stderr, "server_screen_init: Can't find widget three\n"); - } // And enqueue the screen screenlist_add (server_screen); @@ -93,6 +91,20 @@ server_screen_init () return 0; } +static int +screen_count (client *c) { + int n; + + n = 0; + LL_Rewind (c->data->screenlist); + do { + if (LL_Get (c->data->screenlist) != NULL) + n++; + } while (LL_Next (c->data->screenlist) == 0); + + return n; +} + int update_server_screen (int timer) { @@ -112,24 +124,31 @@ update_server_screen (int timer) c = LL_Get (clients); if (c) { num_clients++; - LL_Rewind (c->data->screenlist); - do { - s = LL_Get (c->data->screenlist); - if (s) { - num_screens++; - } - } while (LL_Next (c->data->screenlist) == 0); + num_screens += screen_count(c); +// LL_Rewind (c->data->screenlist); +// do { +// s = LL_Get (c->data->screenlist); +// if (s) { +// num_screens++; +// } +// } while (LL_Next (c->data->screenlist) == 0); } } while (LL_Next (clients) == 0); + // Format strings for the appropriate size display... + // if (lcd.hgt >= 3) { - sprintf (one, "Clients: %i", num_clients); - sprintf (two, "Screens: %i", num_screens); + snprintf (one, sizeof(one), "Clients: %i", num_clients); + snprintf (two, sizeof(two), "Screens: %i", num_screens); } else { if (lcd.wid >= 20) - sprintf (one, "%i Client%s, %i Screen%s", num_clients, (num_clients == 1) ? "" : "s", num_screens, (num_screens == 1) ? "" : "s"); + snprintf (one, sizeof(one), "%i Client%s, %i Screen%s", num_clients, + (num_clients == 1) ? "" : "s", num_screens, + (num_screens == 1) ? "" : "s"); else // 16x2 size - sprintf (one, "%i Cli%s, %i Scr%s", num_clients, (num_clients == 1) ? "" : "s", num_screens, (num_screens == 1) ? "" : "s"); + snprintf (one, sizeof(one), "%i Cli%s, %i Scr%s", num_clients, + (num_clients == 1) ? "" : "s", num_screens, + (num_screens == 1) ? "" : "s"); } return 0; @@ -140,9 +159,7 @@ no_screen_screen (int timer) { lcd.clear (); - lcd.string (1, 1, "Error: No screen!"); - lcd.flush (); return 0; diff --git a/server/sock.c b/server/sock.c index dc56cb8..ef01aa4 100644 --- a/server/sock.c +++ b/server/sock.c @@ -17,6 +17,10 @@ #include "sock.h" #include "clients.h" #include "shared/debug.h" +#include "syslog.h" + +extern char bind_addr[64]; +extern int lcd_port; /************************************************** LCDproc sockets code... @@ -34,7 +38,7 @@ int read_from_client (int filedes); // Creates a socket in internet space int -sock_create_inet_socket (unsigned short int port) +sock_create_inet_socket (char * addr, unsigned int port) { struct sockaddr_in name; int sock; @@ -46,6 +50,7 @@ sock_create_inet_socket (unsigned short int port) sock = socket (PF_INET, SOCK_STREAM, 0); if (sock < 0) { perror ("Error creating socket"); + syslog(LOG_ALERT, "could not create socket", port); return -1; } @@ -53,10 +58,14 @@ sock_create_inet_socket (unsigned short int port) //debug("Binding Inet Socket\n"); name.sin_family = AF_INET; name.sin_port = htons (port); - name.sin_addr.s_addr = htonl (INADDR_ANY); + inet_aton(addr, &name.sin_addr); + if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0) { perror ("Error binding socket"); + syslog(LOG_ALERT, "could not bind to port %d", port); return -1; + } else { + syslog(LOG_NOTICE, "listening for queries on port %d", port); } return sock; @@ -65,14 +74,14 @@ sock_create_inet_socket (unsigned short int port) //int StartSocketServer() int -sock_create_server () +sock_create_server (char *bind_addr, int lcd_port) { int sock; debug ("sock_create_server()\n"); /* Create the socket and set it up to accept connections. */ - sock = sock_create_inet_socket (LCDPORT); + sock = sock_create_inet_socket (bind_addr, lcd_port); if (sock < 0) { perror ("sock_create_server: Error creating socket"); return -1; @@ -80,6 +89,7 @@ sock_create_server () if (listen (sock, 1) < 0) { perror ("sock_create_server: Listen error"); + syslog(LOG_ALERT, "error in attempting to listen to port"); return -1; } @@ -107,6 +117,8 @@ sock_create_server () return sock; } +// Service all clients with input pending... + int sock_poll_clients () { @@ -140,9 +152,12 @@ sock_poll_clients () new = accept (orig_sock, (struct sockaddr *) &clientname, &size); if (new < 0) { perror ("sock_poll_clients: Accept error"); + syslog(LOG_WARNING, "error in accepting client"); return -1; } debug ("sock_poll_clients: connect from host %s, port %hd.\n", inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port)); + syslog(LOG_NOTICE, "connect from host %s:%hd on #%d", + inet_ntoa (clientname.sin_addr), ntohs (clientname.sin_port), new); FD_SET (new, &active_fd_set); fcntl (new, F_SETFL, O_NONBLOCK); @@ -168,6 +183,7 @@ sock_poll_clients () close (i); FD_CLR (i, &active_fd_set); debug ("sock_poll_clients: Closed connection %i\n", i); + syslog(LOG_NOTICE, "closed connection #%i", i); } else fprintf (stderr, "sock_poll_clients: Can't find client %i\n", i); } @@ -186,22 +202,22 @@ read_from_client (int filedes) int nbytes, i; client *c; -// nbytes = read (filedes, buffer, MAXMSG); + //nbytes = read (filedes, buffer, MAXMSG); //debug("read_from_client(%i): reading...\n", filedes); - nbytes = sock_recv (filedes, buffer, MAXMSG); + //nbytes = sock_recv (filedes, buffer, MAXMSG); //debug("read_from_client(%i): ...done\n", filedes); - debug ("read_from_client(%i): %i bytes\n", filedes, nbytes); + //debug ("read_from_client(%i): %i bytes\n", filedes, nbytes); - if (nbytes < 0) // Read error? No data available? - { - // TODO: check errno here! - //fprintf (stderr,"read_from_client: Read error\n"); + errno = 0; + if ((nbytes = sock_recv (filedes, buffer, MAXMSG)) < 0) { + if (errno != EAGAIN) + fprintf (stderr, "read_from_client: (fd %d) %s\n", filedes, strerror(errno)); return 0; } else if (nbytes == 0) // EOF return -1; else if (nbytes > (MAXMSG - (MAXMSG / 8))) // Very noisy client... { - sock_send_string (filedes, "huh? Shut up!\n"); + sock_send_string (filedes, "huh? Too much data received... quiet down!\n"); return -1; } else // Data Read { @@ -229,16 +245,28 @@ read_from_client (int filedes) int sock_close_all () { - int i; + int fd; debug ("sock_close_all()\n"); - for (i = 0; i < FD_SETSIZE; i++) { + for (fd = 0; fd < FD_SETSIZE; fd++) { // TODO: Destroy a "client" here...? Nope. - sock_send_string (i, "bye\n"); - close (i); - FD_CLR (i, &active_fd_set); - debug ("sock_close_all: Closed connection %i\n", i); + + // Instead of using STDIN_FILENO, STDOUT_FILENO, + // and STDERR_FILENO, one could use "fd = 4" in the + // for() call - but this would probably not be good + // practice... + + if ( fd == STDIN_FILENO || + fd == STDOUT_FILENO || + fd == STDERR_FILENO) + continue; + else { + //sock_send_string (fd, "bye\n"); + close (fd); + FD_CLR (fd, &active_fd_set); + debug ("sock_close_all: Closed connection %i\n", fd); + } } return 0; diff --git a/server/widget.c b/server/widget.c index b192529..fd9af5f 100644 --- a/server/widget.c +++ b/server/widget.c @@ -167,6 +167,7 @@ widget_add (screen * s, char *id, char *type, char *in, int sock) s->heartbeat = 1; return 0; } + // Make sure this screen doesn't already exist... w = widget_find (s, id); if (w) { @@ -193,13 +194,16 @@ widget_add (screen * s, char *id, char *type, char *in, int sock) } } } + // Make sure it's a valid widget type for (i = 1; types[i]; i++) { if (0 == strcmp (types[i], type)) { valid = 1; wid_type = i; + break; // it's valid: skip out... } } + if (!valid) { // invalid widget type sock_send_string (sock, "huh? Invalid widget type\n"); @@ -233,6 +237,7 @@ widget_add (screen * s, char *id, char *type, char *in, int sock) } } } + // TODO: Check for errors here? LL_Push (list, (void *) w); @@ -266,19 +271,17 @@ widget_remove (screen * s, char *id, int sock) return 1; } -/* - // TODO: Check for errors here? - // TODO: Make this work with frames... -// LL_Remove(list, (void *)w); +// TODO: Check for errors here? +// TODO: Make this work with frames... +// LL_Remove(list, (void *)w); - // TODO: Check for errors here? -// widget_destroy(w); -*/ +// TODO: Check for errors here? +// widget_destroy(w); return widget_remover (list, w); -// return 0; +// return 0; } int