Added lcdexec

This commit is contained in:
robijn
2002-08-19 20:47:52 +00:00
parent 2387f30bc3
commit 6da4b44139
6 changed files with 627 additions and 1 deletions
+1 -1
View File
@@ -1 +1 @@
SUBDIRS = examples headlines lcdproc metar
SUBDIRS = examples headlines lcdexec lcdproc metar
+4
View File
@@ -0,0 +1,4 @@
bin_PROGRAMS = lcdexec
lcdexec_SOURCES = lcdexec.c menu.c menu.h
lcdexec_LDADD = ../../shared/libLCDstuff.a
INCLUDES = -I$(top_srcdir)
+363
View File
@@ -0,0 +1,363 @@
/*
* lcdexec.c
* This file is part of lcdexec, an LCDproc client.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2002, Joris Robijn
*
*/
/*
* How to use submenus in the config file:
* [lcdexec]
* MenuCommand="Shut down,shutdown -h now"
* SubMenu="Internet,inet"
* # The inet submenu is filled as follows:
* inet_MenuCommand="open,inet open"
* inet_MenuCommand="close,inet close"
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "shared/str.h"
#include "shared/report.h"
#include "shared/configfile.h"
#include "shared/sockets.h"
#include "menu.h"
#define DEFAULT_CONFIGFILE "/etc/LCDclients.conf"
char * help_text =
"lcdexec - LCDproc client to execute commands from the LCDd menu.\n"
"Copyright (c) 2002, Joris Robijn\n"
"This file is released under the GNU General Public License. Refer to the\n"
"COPYING file distributed with this package.\n"
"Options:\n"
" -c <file>\tSpecify configuration file ["DEFAULT_CONFIGFILE"]\n"
" -a <address>\tDNS name or IP address of the LCDd server [localhost]\n"
" -p <port>\tport of the LCDd server [13666]\n"
" -f <0|1>\tRun in foreground (1) or background (0, default)\n"
" -r <level>\tSet reporting level (0-5) [2: errors and warnings]\n"
" -s <0|1>\tReport to syslog (1) or stderr (0, default)\n"
" -h\t\tShow this help\n";
char * progname = "lcdexec";
extern char *optarg;
extern int optind, optopt, opterr;
/* Variables set by config */
#define UNSET_INT -1
#define UNSET_STR "\01"
char * configfile = UNSET_STR;
char * address = UNSET_STR;
int port = UNSET_INT;
int foreground_mode = UNSET_INT;
char * appname = UNSET_STR;
static int report_level = UNSET_INT;
static int report_dest = UNSET_INT;
Menu * main_menu;
/* Other variables */
int sock;
/* Function prototypes */
int process_command_line( int argc, char **argv );
int process_configfile( char * configfile );
int split( char * str, char delim, char * parts[], int maxparts );
int connect_and_setup ();
int process_response( char * str );
int exec_command( char * command );
int main_loop ();
#define CHAIN(e,f) { if( e>=0 ) { e=(f); }}
#define CHAIN_END(e) { if( e<0 ) { report( RPT_CRIT,"Critical error, abort"); exit(e); }}
int main( int argc, char **argv )
{
int error = 0;
CHAIN( error, process_command_line( argc, argv ));
if( configfile == NULL )
configfile = DEFAULT_CONFIGFILE;
CHAIN( error, process_configfile( configfile ));
if( report_dest == UNSET_INT || report_level == UNSET_INT ) {
report_dest = RPT_DEST_STDERR;
report_level = RPT_ERR;
}
set_reporting( progname, report_level, report_dest );
CHAIN_END( error );
CHAIN( error, connect_and_setup() );
CHAIN_END( error );
if(!foreground_mode) {
if (daemon(1,1)!=0) {
report(RPT_ERR, "Error: daemonize failed");
}
}
main_loop();
return 0;
}
int process_command_line( int argc, char **argv )
{
char c;
char * p;
int temp_int;
int error = 0;
/* No error output from getopt */
opterr = 0;
while(( c = getopt( argc, argv, "c:O:a:p:f:r:s:h" )) > 0) {
switch( c ) {
case 'c':
configfile = strdup( optarg );
break;
case 'O':
config_read_string( progname, optarg );
break;
case 'a':
address = strdup( optarg );
break;
case 'p':
temp_int = strtol( optarg, &p, 0 );
if( *optarg != 0 && *p == 0 ) {
port = temp_int;
} else {
report( RPT_ERR, "Could not interpret value for -%c", c );
error = -1;
}
break;
case 'f':
temp_int = strtol( optarg, &p, 0 );
if( *optarg != 0 && *p == 0 ) {
foreground_mode = temp_int;
} else {
report( RPT_ERR, "Could not interpret value for -%c", c );
error = -1;
}
break;
case 'r':
temp_int = strtol( optarg, &p, 0 );
if( *optarg != 0 && *p == 0 ) {
report_level = temp_int;
} else {
report( RPT_ERR, "Could not interpret value for -%c", c );
error = -1;
}
break;
break;
case 's':
temp_int = strtol( optarg, &p, 0 );
if( *optarg != 0 && *p == 0 ) {
report_dest = (temp_int?RPT_DEST_SYSLOG:RPT_DEST_STDERR);
} else {
report( RPT_ERR, "Could not interpret value for -%c", c );
error = -1;
}
break;
case 'h':
fprintf( stderr, "%s", help_text );
exit( 0 );
case ':':
report( RPT_ERR, "Missing option argument for %c", optopt );
error = -1;
break;
case '?':
report( RPT_ERR, "Unknown option: %c", optopt );
error = -1;
break;
}
}
return error;
}
int process_configfile( char * configfile )
{
if( strcmp( configfile, UNSET_STR ) == 0 ) {
configfile = DEFAULT_CONFIGFILE;
}
if( config_read_file( configfile ) < 0 ) {
report( RPT_WARNING, "Could not read config file: %s", configfile );
}
if( strcmp( address, UNSET_STR ) == 0 ) {
address = strdup( config_get_string( progname, "Address", 0, "localhost" ));
}
if( port == UNSET_INT ) {
port = config_get_int( progname, "Port", 0, 13666 );
}
if( report_level == UNSET_INT ) {
report_level = config_get_int( progname, "ReportLevel", 0, RPT_WARNING );
}
if( report_dest == UNSET_INT ) {
if( config_get_bool( progname, "ReportToSyslog", 0, 0 )) {
report_dest = RPT_DEST_SYSLOG;
} else {
report_dest = RPT_DEST_STDERR;
}
}
if( foreground_mode == UNSET_INT ) {
foreground_mode = config_get_bool( progname, "Foreground", 0, 1 );
}
main_menu = menu_read( "", progname );
if( main_menu->num_menucmds == 0 && main_menu->num_submenus == 0 ) {
main_menu->menucmd_name[0] = "echo test";
main_menu->menucmd_exec[0] = "echo \"This is a test using the echo command.\"";
main_menu->num_menucmds ++;
}
return 0;
}
int connect_and_setup ()
{
char buf[200];
report( RPT_INFO, "Connecting to %s:%d", address, port );
sock = sock_connect( address, port );
if( sock <= 0 ) {
return -1;
}
/* Create our menu */
sock_send_string( sock, "hello\n" );
snprintf( buf, sizeof(buf)-1, "client_set -name \"%s\"\n", progname );
sock_send_string( sock, buf );
if( menu_send_to_LCDd( main_menu, "", sock ) < 0 ) {
return -1;
}
return 0;
}
int process_response( char * str )
{
char *argv[10];
int argc;
char * str2 = strdup( str ); /* get_args modifies str2 */
report( RPT_DEBUG, "Server said: \"%s\"", str );
/* Check what the server just said to us... */
argc = get_args( argv, str2, 10 );
if( argc < 1 ) {
free( str2 );
return 0;
}
if( strcmp( argv[0], "menuevent" ) == 0 ) {
/* Ah, this is what we were waiting for ! */
if( argc < 2 ) {
report( RPT_WARNING, "Server gave invalid response" );
free( str2 );
return -1;
}
if( strcmp( argv[1], "select" ) == 0 ) {
char * exec;
if( argc < 3 ) {
report( RPT_WARNING, "Server gave invalid response" );
free( str2 );
return -1;
}
/* Find the id */
exec = menu_find_cmd_of_id( main_menu, argv[2] );
if( !exec ) {
report( RPT_WARNING, "Could not find the item id given by the server" );
free( str2 );
return -1;
}
/* The id has been found */
exec_command( exec );
}
else {
; /* Ignore other menuevents */
}
}
else if( strcmp( argv[0], "huh?" ) == 0 ) {
/* Report errors */
report( RPT_WARNING, "Server said: \"%s\"", str );
}
else {
; /* Ignore all other responses */
}
free( str2 );
return 0;
}
int exec_command( char * command )
{
char *argv[4];
report( RPT_NOTICE, "Executing: %s", command );
argv[0] = getenv( "SHELL" );
argv[1] = "-c";
argv[2] = command;
argv[3] = NULL;
if( !argv[0] ) {
report( RPT_ERR, "SHELL environment variable not set." );
return -1;
}
switch( fork() ) {
case 0:
/* We're the child. Execute the command. */
execv( argv[0], argv );
exit(0);
break;
case -1:
report( RPT_ERR, "Could not fork" );
return -1;
default:
/* We're the parent */
}
return 0;
}
int main_loop ()
{
int num_bytes;
char buf[80];
int w = 0;
/* Continuously check if we get a menu event... */
while(( num_bytes = sock_recv_string( sock, buf, sizeof(buf)-1)) >= 0 ) {
if( num_bytes == 0 ) {
usleep( 100000 );
/* Send an empty line every 3 seconds to make sure the server still exists */
if( w++ >= 30 ) {
w = 0;
if( sock_send_string( sock, "\n" ) < 0 ) {
break; /* Out of while loop */
}
}
}
else {
process_response (buf);
}
}
report( RPT_ERR, "Server disconnected (or connection error)" );
return 0;
}
+220
View File
@@ -0,0 +1,220 @@
/*
* lcdexec.c
* This file is part of lcdexec, an LCDproc client.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2002, Joris Robijn
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "shared/str.h"
#include "shared/report.h"
#include "shared/configfile.h"
#include "shared/sockets.h"
#include "menu.h"
Menu * menu_find_submenu( Menu * menu, char * submenu_id );
Menu * menu_read( char * menu_id, char * progname )
{
char buf[100];
char * str;
char * parts[3];
int i;
Menu * menu;
report( RPT_DEBUG, "Reading menu: [%s]", menu_id );
menu = malloc( sizeof(Menu) );
/* Read the commands */
str = "";
while( str && menu->num_menucmds < MAX_NUM_MENUCMDS ) {
snprintf( buf, sizeof(buf)-1, "%s%sMenuCommand",
menu_id, menu_id[0]?"_":"" );
buf[sizeof(buf)-1] = 0;
str = config_get_string( progname, buf, menu->num_menucmds, NULL );
if( !str ) {
; /* No more menucommands */
} else {
char * str2 = strdup( str );
if( split( str2, ',', parts, 2 ) == 2 ) {
menu->menucmd_name[menu->num_menucmds] = parts[0];
while( parts[1][0] == ' ' ) parts[1]++; /* Skip spaces */
menu->menucmd_exec[menu->num_menucmds] = parts[1];
report( RPT_DEBUG, "Found command: [%s] [%s]", parts[0], parts[1] );
} else {
report( RPT_ERR, "Cannot read MenuCommand: \"%s\"", str );
return NULL;
}
menu->num_menucmds ++;
}
}
/* Read the submenus */
str = "";
while( str && menu->num_submenus < MAX_NUM_SUBMENUS ) {
snprintf( buf, sizeof(buf)-1, "%s%sSubmenu",
menu_id, menu_id[0]?"_":"" );
buf[sizeof(buf)-1] = 0;
str = config_get_string( progname, buf, menu->num_submenus, NULL );
if( !str ) {
; /* No more submenus */
} else {
char * str2 = strdup( str );
if( split( str2, ',', parts, 2 ) == 2 ) {
menu->submenu_name[menu->num_submenus] = parts[0];
while( parts[1][0] == ' ' ) parts[1]++; /* Skip spaces */
menu->submenu_id[menu->num_submenus] = parts[1];
report( RPT_DEBUG, "Found submenu: [%s] [%s]", parts[0], parts[1] );
} else {
report( RPT_ERR, "Cannot read Submenu: \"%s\"", str );
return NULL;
}
menu->num_submenus ++;
}
}
/* And do the same for all submenus */
for( i = 0; i < menu->num_submenus; i++ ) {
menu->submenu[i] = menu_read (menu->submenu_id[i], progname );
}
return menu;
}
int menu_send_to_LCDd( Menu * menu, char * id, int sock )
{
int i;
char buf[100];
for( i = 0; i < menu->num_menucmds; i++ ) {
snprintf( buf, sizeof(buf)-1,
"menu_add_item \"%s\" \"%s%s%d\" action \"%s\"\n",
id, id, id[0]?"_":"", i, menu->menucmd_name[i] );
buf[sizeof(buf)-1] = 0;
if( sock_send_string( sock, buf ) < 0 )
return -1;
snprintf( buf, sizeof(buf)-1,
"menu_set_item \"%s\" \"%s%s%d\" -menu_result quit\n",
id, id, id[0]?"_":"", i );
buf[sizeof(buf)-1] = 0;
if( sock_send_string( sock, buf ) < 0 )
return -1;
}
for( i = 0; i < menu->num_submenus; i++ ) {
snprintf( buf, sizeof(buf)-1,
"menu_add_item \"%s\" \"%s\" menu \"%s\"\n",
id, menu->submenu_id[i], menu->submenu_name[i] );
buf[sizeof(buf)-1] = 0;
if( sock_send_string( sock, buf ) < 0 )
return -1;
}
/* And do the same for all submenus */
for( i = 0; i < menu->num_submenus; i++ ) {
if( menu_send_to_LCDd( menu->submenu[i], menu->submenu_id[i], sock ) < 0 )
return -1;
}
return 0;
}
char * menu_find_cmd_of_id( Menu * menu, char * id )
{
char * p;
char * submenu_id;
char * item_id;
int i;
/* Find the submenu_id part of the id */
submenu_id = strdup( id );
p = strrchr( submenu_id, '_' );
/* Do we need to search the submenus ? */
if( p ) {
/* There is a menu id prepended to the id */
*p = 0; /* Crop the submenu_id string */
item_id = p + 1;
menu = menu_find_submenu( menu, submenu_id );
if( !menu ) {
report( RPT_WARNING, "Server reported an unknown id: %s", id );
free( submenu_id );
return NULL;
}
}
else {
item_id = id;
}
/* Determine the number at the end of the id */
i = strtol( item_id, &p, 10 );
if( *item_id != 0 && *p == 0
&& i >= 0 && i < menu->num_menucmds ) {
/* OK */
free( submenu_id );
return menu->menucmd_exec[i];
} else {
report( RPT_WARNING, "Server reported an unknown id: %s", id );
free( submenu_id );
return NULL;
}
}
Menu * menu_find_submenu( Menu * menu, char * submenu_id )
{
int i;
Menu * found;
/* Search for the submenu in this menu and all submenus */
for( i = 0; i < menu->num_submenus; i++ ) {
if( strcmp( menu->submenu_id[i], submenu_id ) == 0 )
return menu->submenu[i];
found = menu_find_submenu( menu->submenu[i], submenu_id );
if( found )
return found;
}
return NULL;
}
int split( char * str, char delim, char * parts[], int maxparts )
/* Splits a string into parts, to which pointers will be returned in &parts.
* The return value is the number of parts.
* maxparts is the maximum number of parts returned. If more parts exist
* they are (unsplit) in the last part.
* The parts are split at the character delim.
* No new space will be allocated, the string str will be mutated !
*/
{
char * p1 = str;
char * p2;
int part_nr = 0;
/* Find the delim char to end the current part */
while( part_nr < maxparts - 1 && (p2 = strchr( p1, delim )) ) {
/* subsequent parts... */
*p2 = 0;
parts[part_nr] = p1;
p1 = p2 + 1; /* Just after the delim char */
part_nr ++;
}
/* and the last part... */
parts[part_nr] = p1;
part_nr ++;
return part_nr;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* lcdexec.c
* This file is part of lcdexec, an LCDproc client.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2002, Joris Robijn
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "shared/str.h"
#include "shared/report.h"
#include "shared/configfile.h"
#include "shared/sockets.h"
#define MAX_NUM_MENUCMDS 40
#define MAX_NUM_SUBMENUS 20
typedef struct Menu {
char * menucmd_name[MAX_NUM_MENUCMDS];
char * menucmd_exec[MAX_NUM_MENUCMDS];
int num_menucmds;
char * submenu_name[MAX_NUM_SUBMENUS];
char * submenu_id[MAX_NUM_SUBMENUS];
struct Menu * submenu[MAX_NUM_SUBMENUS];
int num_submenus;
} Menu;
Menu * menu_read (char * menu_id, char * progname);
int menu_send_to_LCDd( Menu * menu, char * id, int sock );
char * menu_find_cmd_of_id( Menu * menu, char * id );
int split( char * str, char delim, char * parts[], int maxparts );
+1
View File
@@ -189,6 +189,7 @@ AC_OUTPUT(Makefile
server/drivers/Makefile
clients/Makefile
clients/lcdproc/Makefile
clients/lcdexec/Makefile
clients/examples/Makefile
clients/headlines/Makefile
clients/metar/Makefile