1999-12-09 23:15:14 +00:00
|
|
|
/*
|
2001-12-27 23:30:36 +00:00
|
|
|
* parse.c
|
|
|
|
|
* 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, Scott Scriven
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* Handles input commands from clients, by splitting strings into tokens
|
|
|
|
|
* and passing arguments to the appropriate handler.
|
|
|
|
|
*
|
|
|
|
|
* It works much like a command line. Only the first token is used to
|
|
|
|
|
* determine what function to call.
|
|
|
|
|
*
|
1999-12-09 23:15:14 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
2001-05-25 03:14:27 +00:00
|
|
|
#include "shared/LL.h"
|
|
|
|
|
#include "shared/sockets.h"
|
2001-11-29 14:09:13 +00:00
|
|
|
#include "shared/report.h"
|
1999-12-09 23:15:14 +00:00
|
|
|
#include "clients.h"
|
2002-04-26 00:00:31 +00:00
|
|
|
#include "commands/command_list.h"
|
1999-12-09 23:15:14 +00:00
|
|
|
#include "parse.h"
|
|
|
|
|
|
2001-10-19 17:44:09 +00:00
|
|
|
|
2002-06-28 23:35:55 +00:00
|
|
|
#define MAX_ARGUMENTS 40
|
2001-10-19 17:44:09 +00:00
|
|
|
|
1999-12-09 23:15:14 +00:00
|
|
|
|
2005-07-02 12:29:42 +00:00
|
|
|
static inline int is_whitespace(char x) {
|
|
|
|
|
return ((x == ' ') || (x == '\t') || (x == '\r'));
|
|
|
|
|
}
|
2002-04-26 00:00:31 +00:00
|
|
|
|
2005-07-02 12:29:42 +00:00
|
|
|
static inline int is_final(char x) {
|
|
|
|
|
return ((x == '\n') || (x == '\0'));
|
|
|
|
|
}
|
2002-06-28 23:35:55 +00:00
|
|
|
|
2005-07-02 12:29:42 +00:00
|
|
|
static inline int is_opening_quote(char x, char q) {
|
|
|
|
|
return ((q == '\0') && ((x == '\"') || (x == '{')));
|
|
|
|
|
}
|
2002-06-28 23:35:55 +00:00
|
|
|
|
2005-07-02 12:29:42 +00:00
|
|
|
static inline int is_closing_quote(char x, char q) {
|
|
|
|
|
return (((q == '{') && (x == '}')) || ((q == '\"') && (x == '\"')));
|
2002-06-28 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
|
|
|
|
|
static int parse_message (const char *str, Client *c)
|
2002-06-28 23:35:55 +00:00
|
|
|
{
|
2005-06-28 17:12:30 +00:00
|
|
|
typedef enum { ST_INITIAL, ST_WHITESPACE, ST_ARGUMENT, ST_FINAL } State;
|
2002-06-28 23:35:55 +00:00
|
|
|
State state = ST_INITIAL;
|
|
|
|
|
|
|
|
|
|
int error = 0;
|
2005-06-28 17:12:30 +00:00
|
|
|
char quote = '\0'; /* The quote used to open a quote string */
|
2002-06-28 23:35:55 +00:00
|
|
|
int pos = 0;
|
2005-06-28 17:12:30 +00:00
|
|
|
char *arg_space;
|
|
|
|
|
int argc = 0;
|
2002-06-28 23:35:55 +00:00
|
|
|
char *argv[MAX_ARGUMENTS];
|
|
|
|
|
int argpos = 0;
|
2005-07-02 12:29:42 +00:00
|
|
|
CommandFunc function = NULL;
|
2002-06-28 23:35:55 +00:00
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
void close_arg() {
|
|
|
|
|
if (argc >= MAX_ARGUMENTS-1) {
|
2002-07-17 22:09:06 +00:00
|
|
|
error = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2005-06-28 17:12:30 +00:00
|
|
|
argv[argc][argpos] = '\0';
|
2002-07-17 22:09:06 +00:00
|
|
|
argv[argc+1] = argv[argc] + argpos + 1;
|
2005-06-28 17:12:30 +00:00
|
|
|
argc++;
|
2002-07-17 22:09:06 +00:00
|
|
|
argpos = 0;
|
|
|
|
|
}
|
2002-06-28 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
2002-07-14 20:30:33 +00:00
|
|
|
debug( RPT_DEBUG, "%s( str=\"%.120s\", client=[%d] )", __FUNCTION__, str, c->sock );
|
|
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
/* We will create a list of strings that is shorter or equally long as
|
2002-06-28 23:35:55 +00:00
|
|
|
* the original string str.
|
|
|
|
|
*/
|
2005-06-28 17:12:30 +00:00
|
|
|
arg_space = malloc(strlen(str)+1);
|
|
|
|
|
if (arg_space == NULL) {
|
|
|
|
|
report (RPT_ERR, "%s: Could not allocate memory", __FUNCTION__);
|
2005-07-17 16:14:07 +00:00
|
|
|
sock_send_error(c->sock, "error allocating memory!\n");
|
2005-06-28 17:12:30 +00:00
|
|
|
}
|
2002-06-28 23:35:55 +00:00
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
argv[0] = arg_space;
|
2002-06-28 23:35:55 +00:00
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
while ((state != ST_FINAL) && !error) {
|
|
|
|
|
char ch = str[pos++];
|
|
|
|
|
|
|
|
|
|
switch (state) {
|
2002-06-28 23:35:55 +00:00
|
|
|
case ST_INITIAL:
|
|
|
|
|
case ST_WHITESPACE:
|
2005-06-28 17:12:30 +00:00
|
|
|
if (is_whitespace(ch))
|
2002-06-28 23:35:55 +00:00
|
|
|
break;
|
2005-06-28 17:12:30 +00:00
|
|
|
if (is_final(ch)) {
|
2002-06-28 23:35:55 +00:00
|
|
|
state = ST_FINAL;
|
|
|
|
|
break;
|
2005-06-28 17:12:30 +00:00
|
|
|
}
|
|
|
|
|
/* otherwise fall through */
|
|
|
|
|
state = ST_ARGUMENT;
|
2002-06-28 23:35:55 +00:00
|
|
|
case ST_ARGUMENT:
|
2005-06-28 17:12:30 +00:00
|
|
|
if (is_final(ch)) {
|
|
|
|
|
if (quote)
|
2002-06-28 23:35:55 +00:00
|
|
|
error = 2;
|
|
|
|
|
close_arg();
|
|
|
|
|
state = ST_FINAL;
|
2005-06-28 17:12:30 +00:00
|
|
|
}
|
|
|
|
|
else if (ch == '\\') {
|
2002-06-28 23:35:55 +00:00
|
|
|
if (str[pos]) {
|
|
|
|
|
/* We solve quoted chars here right away */
|
2005-06-28 17:12:30 +00:00
|
|
|
const char escape_chars[] = "nrt";
|
|
|
|
|
const char escape_trans[] = "\n\r\t";
|
|
|
|
|
char *p = strchr( escape_chars, str[pos] );
|
2006-04-27 15:10:59 +00:00
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
/* Is it wise to have the characters \n, \r & \t expanded ?
|
|
|
|
|
* Can the displays deal with them ?
|
|
|
|
|
*/
|
2002-06-28 23:35:55 +00:00
|
|
|
if (p != NULL) {
|
|
|
|
|
/* Insert a replacement for the code */
|
2005-06-28 17:12:30 +00:00
|
|
|
argv[argc][argpos++] = escape_trans[p - escape_chars];
|
2002-06-28 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2005-06-28 17:12:30 +00:00
|
|
|
/* Copy char literally */
|
2002-06-28 23:35:55 +00:00
|
|
|
argv[argc][argpos++] = str[pos];
|
|
|
|
|
}
|
2002-07-17 22:09:06 +00:00
|
|
|
pos++;
|
2002-06-28 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
error = 2;
|
2005-06-28 17:12:30 +00:00
|
|
|
/* alternative: argv[argc][argpos++] = ch; */
|
|
|
|
|
close_arg();
|
2002-06-28 23:35:55 +00:00
|
|
|
state = ST_FINAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-06-28 17:12:30 +00:00
|
|
|
else if (is_opening_quote(ch, quote)) {
|
|
|
|
|
quote = ch;
|
|
|
|
|
}
|
|
|
|
|
else if (is_closing_quote(ch, quote)) {
|
|
|
|
|
quote = '\0';
|
|
|
|
|
close_arg();
|
|
|
|
|
state = ST_WHITESPACE;
|
|
|
|
|
}
|
|
|
|
|
else if (is_whitespace(ch) && (quote == '\0')) {
|
|
|
|
|
close_arg();
|
|
|
|
|
state = ST_WHITESPACE;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
argv[argc][argpos++] = ch;
|
|
|
|
|
}
|
2002-06-28 23:35:55 +00:00
|
|
|
break;
|
|
|
|
|
case ST_FINAL:
|
|
|
|
|
/* This will never be reached */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-06-28 17:12:30 +00:00
|
|
|
if (argc < MAX_ARGUMENTS)
|
|
|
|
|
argv[argc] = NULL;
|
|
|
|
|
else
|
|
|
|
|
error = 1;
|
|
|
|
|
|
2002-06-28 23:35:55 +00:00
|
|
|
if (error) {
|
2005-07-17 16:14:07 +00:00
|
|
|
sock_send_error(c->sock, "Could not parse command\n");
|
2002-07-13 22:25:18 +00:00
|
|
|
free( arg_space );
|
|
|
|
|
return 0;
|
2002-06-28 23:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
2005-07-02 12:29:42 +00:00
|
|
|
#if 0 /* show what we have parsed */
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
|
|
|
printf("%s%c", argv[i], (i == argc-1) ? '\n' : ' ');
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2002-06-28 23:35:55 +00:00
|
|
|
/* Now find and call the appropriate function...*/
|
2005-07-02 12:29:42 +00:00
|
|
|
function = get_command_function(argv[0]);
|
2002-06-28 23:35:55 +00:00
|
|
|
|
2005-06-28 17:12:30 +00:00
|
|
|
if (function != NULL) {
|
|
|
|
|
error = function (c, argc, argv);
|
|
|
|
|
if (error) {
|
2005-07-17 16:14:07 +00:00
|
|
|
sock_printf_error(c->sock, "Function returned error \"%.40s\"\n", argv[0]);
|
2005-06-28 17:12:30 +00:00
|
|
|
report( RPT_WARNING, "Command function returned an error after command from client on socket %d: %.40s", c->sock, str );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2005-07-17 16:14:07 +00:00
|
|
|
sock_printf_error(c->sock, "Invalid command \"%.40s\"\n", argv[0]);
|
2002-07-17 22:09:06 +00:00
|
|
|
report( RPT_WARNING, "Invalid command from client on socket %d: %.40s", c->sock, str );
|
2002-06-28 23:35:55 +00:00
|
|
|
}
|
2006-04-27 15:10:59 +00:00
|
|
|
|
2002-07-13 22:25:18 +00:00
|
|
|
free( arg_space );
|
2002-06-28 23:35:55 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2005-06-28 17:12:30 +00:00
|
|
|
|
2005-07-02 12:29:42 +00:00
|
|
|
|
|
|
|
|
int
|
|
|
|
|
parse_all_client_messages ()
|
|
|
|
|
{
|
|
|
|
|
Client * c;
|
|
|
|
|
|
|
|
|
|
debug( RPT_DEBUG, "%s()", __FUNCTION__ );
|
|
|
|
|
|
|
|
|
|
for (c = clients_getfirst(); c != NULL; c = clients_getnext()) {
|
|
|
|
|
char * str;
|
|
|
|
|
|
|
|
|
|
/* And parse all its messages...*/
|
|
|
|
|
/*debug(RPT_DEBUG, "parse: Getting messages...");*/
|
|
|
|
|
for (str = client_get_message (c); str != NULL; str = client_get_message (c)) {
|
|
|
|
|
parse_message (str, c);
|
|
|
|
|
free (str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|