1. Use <stdbool.h> if it is available but keep a compatibility shim in
shared/defines.h in case it is not.
2. Unbreak the circular header dependencies (mostly):
2a. client.c and client.h may NOT depend on 'struct Menu'. Use a void pointer
and casts instead.
2b. Separate the data type definitions in client.h and screen.h from
function prototypes which may require other data structures. This makes
header dependencies much more easy to maintain. Usually the data types
should have been moved to their own files but I (mmdolze) chose to
separate them using different header guards.
2c. Remove many now unused header includes.
Apply (old BSD-) style on menuscreens.c.
306 lines
6.1 KiB
C
306 lines
6.1 KiB
C
/** \file server/commands/client_commands.c
|
|
* Implements handlers for general client commands.
|
|
*
|
|
* This contains definitions for all the functions which clients can run.
|
|
* The functions here are to be called only from parse.c's interpreter.
|
|
*
|
|
* The client's available function set is defined here, as is the syntax
|
|
* for each command.
|
|
*/
|
|
|
|
/* This file is part of LCDd, the lcdproc server.
|
|
*
|
|
* This file is released under the GNU General Public License.
|
|
* Refer to the COPYING file distributed with this package.
|
|
*
|
|
* Copyright (c) 1999, William Ferrell, Selene Scriven
|
|
* 2002, Joris Robijn
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
|
|
#include "shared/report.h"
|
|
#include "shared/sockets.h"
|
|
|
|
#include "drivers.h"
|
|
#include "client.h"
|
|
#include "render.h"
|
|
#include "input.h"
|
|
#include "client_commands.h"
|
|
|
|
|
|
/**
|
|
* Debugging only.. prints out a list of arguments it receives
|
|
*/
|
|
int
|
|
test_func_func(Client *c, int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
report(RPT_INFO, "%s: %i -> %s", __FUNCTION__, i, argv[i]);
|
|
sock_printf(c->sock, "%s: %i -> %s\n", __FUNCTION__, i, argv[i]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* The client must say "hello" before doing anything else.
|
|
*
|
|
* It sends back a string of info about the server to the client.
|
|
*
|
|
*\verbatim
|
|
* Usage: hello
|
|
*\endverbatim
|
|
*
|
|
* \todo Give \em real info about the server/lcd
|
|
*/
|
|
int
|
|
hello_func(Client *c, int argc, char **argv)
|
|
{
|
|
if (argc > 1) {
|
|
sock_send_error(c->sock, "extra parameters ignored\n");
|
|
}
|
|
|
|
debug(RPT_INFO, "Hello!");
|
|
|
|
sock_printf(c->sock, "connect LCDproc %s protocol %s lcd wid %i hgt %i cellwid %i cellhgt %i\n",
|
|
VERSION, PROTOCOL_VERSION,
|
|
display_props->width, display_props->height,
|
|
display_props->cellwidth, display_props->cellheight);
|
|
|
|
/* make note that client has sent hello */
|
|
c->state = ACTIVE;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* The client should say "bye" before disconnecting
|
|
*
|
|
* The function does not respond to the client: it simply cuts connection.
|
|
*
|
|
*\verbatim
|
|
* Usage: bye
|
|
*\endverbatim
|
|
*/
|
|
int
|
|
bye_func(Client *c, int argc, char **argv)
|
|
{
|
|
if (c != NULL) {
|
|
debug(RPT_INFO, "Bye, %s!", (c->name != NULL) ? c->name : "unknown client");
|
|
|
|
c->state = GONE;
|
|
//sock_send_error(c->sock, "\"bye\" is currently ignored\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sets info about the client, such as its name
|
|
*
|
|
*\verbatim
|
|
* Usage: client_set -name <id>
|
|
*\endverbatim
|
|
*/
|
|
int
|
|
client_set_func(Client *c, int argc, char **argv)
|
|
{
|
|
int i;
|
|
|
|
if (c->state != ACTIVE)
|
|
return 1;
|
|
|
|
if (argc != 3) {
|
|
sock_send_error(c->sock, "Usage: client_set -name <name>\n");
|
|
return 0;
|
|
}
|
|
|
|
i = 1;
|
|
do {
|
|
char *p = argv[i];
|
|
|
|
/* ignore leading '-' in options: we allow both forms */
|
|
if (*p == '-')
|
|
p++;
|
|
|
|
/* Handle the "name" option */
|
|
if (strcmp(p, "name") == 0) {
|
|
i++;
|
|
if (argv[i] == '\0') {
|
|
sock_printf_error(c->sock, "internal error: no parameter #%d\n", i);
|
|
continue;
|
|
}
|
|
|
|
debug(RPT_DEBUG, "client_set: name=\"%s\"", argv[i]);
|
|
|
|
/* set the name...*/
|
|
if (c->name != NULL)
|
|
free(c->name);
|
|
|
|
if ((c->name = strdup(argv[i])) == NULL) {
|
|
sock_send_error(c->sock, "error allocating memory!\n");
|
|
}
|
|
else {
|
|
sock_send_string(c->sock, "success\n");
|
|
i++; /* bypass argument (name string)*/
|
|
}
|
|
}
|
|
else {
|
|
sock_printf_error(c->sock, "invalid parameter (%s)\n", p);
|
|
}
|
|
} while (++i < argc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Tells the server the client would like to accept keypresses
|
|
* of a particular type
|
|
*
|
|
*\verbatim
|
|
* Usage: client_add_key [-exclusively|-shared] {<key>}+
|
|
*\endverbatim
|
|
*/
|
|
int
|
|
client_add_key_func(Client *c, int argc, char **argv)
|
|
{
|
|
int exclusively = 0;
|
|
int argnr;
|
|
|
|
if (c->state != ACTIVE)
|
|
return 1;
|
|
|
|
if (argc < 2) {
|
|
sock_send_error(c->sock, "Usage: client_add_key [-exclusively|-shared] {<key>}+\n");
|
|
return 0;
|
|
}
|
|
|
|
argnr = 1;
|
|
if (argv[argnr][0] == '-') {
|
|
if (strcmp( argv[argnr], "-shared") == 0) {
|
|
exclusively = 0;
|
|
}
|
|
else if(strcmp(argv[argnr], "-exclusively") == 0) {
|
|
exclusively = 1;
|
|
}
|
|
else {
|
|
sock_printf_error(c->sock, "Invalid option: %s\n", argv[argnr]);
|
|
}
|
|
argnr++;
|
|
}
|
|
for ( ; argnr < argc; argnr++) {
|
|
if (input_reserve_key(argv[argnr], exclusively, c) < 0) {
|
|
sock_printf_error(c->sock, "Could not reserve key \"%s\"\n", argv[argnr]);
|
|
}
|
|
}
|
|
sock_send_string(c->sock, "success\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Tells the server the client would NOT like to accept keypresses
|
|
* of a particular type
|
|
*
|
|
*\verbatim
|
|
* Usage: client_del_key {<key>}+
|
|
*\endverbatim
|
|
*/
|
|
int
|
|
client_del_key_func(Client *c, int argc, char **argv)
|
|
{
|
|
int argnr;
|
|
|
|
if (c->state != ACTIVE)
|
|
return 1;
|
|
|
|
if (argc < 2) {
|
|
sock_send_error(c->sock, "Usage: client_del_key {<key>}+\n");
|
|
return 0;
|
|
}
|
|
|
|
for (argnr = 1; argnr < argc; argnr++) {
|
|
input_release_key(argv[argnr], c);
|
|
}
|
|
sock_send_string(c->sock, "success\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Toggles the backlight, if enabled.
|
|
*
|
|
*\verbatim
|
|
* Usage: backlight {on|off|toggle|blink|flash}
|
|
*\endverbatim
|
|
*/
|
|
int
|
|
backlight_func(Client *c, int argc, char **argv)
|
|
{
|
|
if (c->state != ACTIVE)
|
|
return 1;
|
|
|
|
if (argc != 2) {
|
|
sock_send_error(c->sock, "Usage: backlight {on|off|toggle|blink|flash}\n");
|
|
return 0;
|
|
}
|
|
|
|
debug(RPT_DEBUG, "backlight(%s)", argv[1]);
|
|
|
|
|
|
//backlight = (backlight && 1); /* only preserves ON/OFF bit*/
|
|
|
|
if (strcmp ("on", argv[1]) == 0) {
|
|
c->backlight = BACKLIGHT_ON;
|
|
}
|
|
else if (strcmp ("off", argv[1]) == 0) {
|
|
c->backlight = BACKLIGHT_OFF;
|
|
}
|
|
else if (strcmp ("toggle", argv[1]) == 0) {
|
|
if (c->backlight == BACKLIGHT_ON)
|
|
c->backlight = BACKLIGHT_OFF;
|
|
else if (c->backlight == BACKLIGHT_OFF)
|
|
c->backlight = BACKLIGHT_ON;
|
|
}
|
|
else if (strcmp ("blink", argv[1]) == 0) {
|
|
c->backlight |= BACKLIGHT_BLINK;
|
|
}
|
|
else if (strcmp ("flash", argv[1]) == 0) {
|
|
c->backlight |= BACKLIGHT_FLASH;
|
|
}
|
|
|
|
sock_send_string(c->sock, "success\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
|
* Sends back information about the loaded drivers.
|
|
*
|
|
*\verbatim
|
|
* Usage: info
|
|
*\endverbatim
|
|
*/
|
|
int
|
|
info_func(Client *c, int argc, char **argv)
|
|
{
|
|
if (c->state != ACTIVE)
|
|
return 1;
|
|
|
|
if (argc > 1) {
|
|
sock_send_error(c->sock, "Extra arguments ignored...\n");
|
|
}
|
|
|
|
sock_printf(c->sock, "%s\n", drivers_get_info());
|
|
|
|
return 0;
|
|
}
|
|
|