#include <unistd.h> // close/getuid
#include <limits.h> // INT_MIN/INT_MAX
#include "common.h"
+#include "../common/doregex.h"
+#include "../common/config.h"
#define USE_NCURSES_INTERFACE 0
#define DEBUG_TRACE_SERVER 0
void CompileRegex(regex_t *regex, const char *pattern, int flags);
// === GLOBALS ===
-char *gsDispenseServer = "merlo.ucc.gu.uwa.edu.au";
+const char *gsConfigFile = "/etc/opendispense/client.conf";
+
+const char *gsDispenseServer = "merlo.ucc.gu.uwa.edu.au";
int giDispensePort = 11020;
+ int giDispenseServerSet = 0; // True if set by command line
+ int giDispensePortSet = 0; // True if set by command line
tItem *gaItems;
int giNumItems;
" Show help text\n"
" -G\n"
" Use simple textual interface (instead of ncurses)\n"
+ " -D\n"
+ " Drinks only in user interface\n"
" -n\n"
" Dry run - Do not actually do dispenses\n"
" -m <min balance>\n"
" -M <max balance>\n"
" Set the Maximum/Minimum balances shown in `dispense acct`\n"
+ " -f <configfile>\n"
+ " Set the config file path (default: `/etc/opendispense/client.conf'\n"
+ " -H <host>\n"
+ " Set a different dispense host\n"
+ " -P <port>\n"
+ " Set a different dispense port\n"
"Definitions:\n"
" <itemid>\n"
" Item ID of the form <type>:<num> where <type> is a non-empty string of alpha-numeric characters, and <num> is a non-negative integer\n"
//
int subcommand_acct(void)
{
- int ret;
+ int ret = 0;
// Connect to server
int sock = OpenConnection(gsDispenseServer, giDispensePort);
if( gsTextArgs[2][0] == '=' ) {
// Set balance
+ ret = Dispense_ShowUser(sock, gsTextArgs[1]);
ret = Dispense_SetBalance(sock, gsTextArgs[1], balance, gsTextArgs[3]);
}
else {
if( ret )
return ret;
+ // Load config file
+ // - Don't check return value, leads to defaults being used
+ if( Config_ParseFile(gsConfigFile) ) {
+ fprintf(stderr, "NOTICE: Loading of config file '%s' failed, using defaults\n", gsConfigFile);
+ }
+
+ // Parse config values
+ if( !giDispenseServerSet ) {
+ Config_GetValue_Str("dispense_server", &gsDispenseServer);
+ }
+ if (!giDispensePortSet) {
+ Config_GetValue_Int("dispense_port", &giDispensePort);
+ }
+
+
// Sub-commands
if( strcmp(gsTextArgs[0], "finger") == 0 ) {
return subcommand_finger();
int ParseArguments(int argc, char *argv[])
{
+ bool rest_free = false;
for( int i = 1; i < argc; i ++ )
{
char *arg = argv[i];
- if( arg[0] == '-' )
+ // If it doesn't start with a '-', or -- has been seen
+ // XXX: Hack - If parsing "user type", don't parse - options
+ bool hack_usertype = (i > 2 && strcmp(argv[i-2], "user") == 0 && strcmp(argv[i-1], "type") == 0);
+ // XXX: Hack - Treat negative numbers as free
+ bool hack_is_int = (arg[0] == '-' && isdigit(arg[1]) != 0);
+ if( rest_free || arg[0] != '-' || hack_usertype || hack_is_int )
+ {
+ if( giTextArgc == MAX_TXT_ARGS )
+ {
+ fprintf(stderr, "ERROR: Too many arguments\n");
+ return RV_ARGUMENTS;
+ }
+
+ gsTextArgs[giTextArgc++] = argv[i];
+ }
+ else if( arg[1] != '-' )
{
switch(arg[1])
{
case 'h':
case '?':
ShowUsage();
- return 0;
+ exit(0);
case 'c':
- if( i > 2 && strcmp(argv[i-1], "type") == 0 )
- goto _default;
if( i + 1 >= argc ) {
fprintf(stderr, "%s: -c takes an argument\n", argv[0]);
ShowUsage();
giMaximumBalance = atoi(argv[++i]);
break;
+ case 'f': // Override Config File
+ if( i + 1 >= argc ) {
+ fprintf(stderr, "%s: -f takes an argument\n", argv[0]);
+ ShowUsage();
+ return RV_ARGUMENTS;
+ }
+ gsConfigFile = argv[++i];
+ break;
+
case 'u': // Override User
if( i + 1 >= argc ) {
fprintf(stderr, "%s: -u takes an argument\n", argv[0]);
return RV_ARGUMENTS;
}
gsDispenseServer = argv[++i];
+ giDispenseServerSet = 1;
break;
case 'P': // Override remote port
if( i + 1 >= argc ) {
return RV_ARGUMENTS;
}
giDispensePort = atoi(argv[++i]);
+ giDispensePortSet = 1;
break;
// Set slot name/price
case 'n': // Dry Run / read-only
gbDryRun = 1;
break;
- case '-':
- if( strcmp(argv[i], "--help") == 0 ) {
- ShowUsage();
- return 0;
- }
- else if( strcmp(argv[i], "--dry-run") == 0 ) {
- gbDryRun = 1;
- }
- else if( strcmp(argv[i], "--drinks-only") == 0 ) {
- giUIMode = UI_MODE_DRINKSONLY;
- }
- else if( strcmp(argv[i], "--can-select-all") == 0 ) {
- gbDisallowSelectWithoutBalance = 0;
- }
- else {
- fprintf(stderr, "%s: Unknown switch '%s'\n", argv[0], argv[i]);
- ShowUsage();
- return RV_ARGUMENTS;
- }
- break;
- default: _default:
- // The first argument is not allowed to begin with 'i'
- // (catches most bad flags)
- if( giTextArgc == 0 ) {
- fprintf(stderr, "%s: Unknown switch '%s'\n", argv[0], argv[i]);
- ShowUsage();
- return RV_ARGUMENTS;
- }
- if( giTextArgc == MAX_TXT_ARGS )
- {
- fprintf(stderr, "ERROR: Too many arguments\n");
- return RV_ARGUMENTS;
- }
- gsTextArgs[giTextArgc++] = argv[i];
- break;
+ default:
+ fprintf(stderr, "%s: Unknown switch '%s'\n", argv[0], argv[i]);
+ ShowUsage();
+ return RV_ARGUMENTS;
}
continue;
}
-
- if( giTextArgc == MAX_TXT_ARGS )
+ else
{
- fprintf(stderr, "ERROR: Too many arguments\n");
- return RV_ARGUMENTS;
+ // '--' : Terminate argument processing (remainder is free)
+ if( arg[2] == '\0' ) {
+ rest_free = true;
+ }
+ else if( strcmp(arg, "--help") == 0 ) {
+ ShowUsage();
+ exit(0);
+ }
+ else if( strcmp(arg, "--dry-run") == 0 ) {
+ gbDryRun = 1;
+ }
+ else if( strcmp(arg, "--drinks-only") == 0 ) {
+ giUIMode = UI_MODE_DRINKSONLY;
+ }
+ else if( strcmp(arg, "--can-select-all") == 0 ) {
+ gbDisallowSelectWithoutBalance = 0;
+ }
+ else if( strcmp(arg, "--configfile") == 0 ) {
+ if( i + 1 >= argc ) {
+ fprintf(stderr, "%s: %s takes an argument\n", argv[0], arg);
+ ShowUsage();
+ return RV_ARGUMENTS;
+ }
+ gsConfigFile = argv[++i];
+ }
+ else {
+ fprintf(stderr, "%s: Unknown switch '%s'\n", argv[0], arg);
+ ShowUsage();
+ return RV_ARGUMENTS;
+ }
}
-
- gsTextArgs[giTextArgc++] = argv[i];
-
}
return 0;
}
// ---------------
char *trim(char *string)
{
- int i;
-
+ // Increment pointer while it points to a space
while( isspace(*string) )
string ++;
- for( i = strlen(string); i--; )
- {
- if( isspace(string[i]) )
- string[i] = '\0';
- else
- break;
- }
+ // And repalce trailing spaces with NUL bytes
+ for( int i = strlen(string); i-- && isspace(string[i]); )
+ string[i] = '\0';
return string;
}
-
-int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
-{
- int ret;
-
- ret = regexec(regex, string, nMatches, matches, 0);
- if( ret && errorMessage ) {
- size_t len = regerror(ret, regex, NULL, 0);
- char errorStr[len];
- regerror(ret, regex, errorStr, len);
- printf("string = '%s'\n", string);
- fprintf(stderr, "%s\n%s", errorMessage, errorStr);
- exit(-1);
- }
-
- return ret;
-}
-
-void CompileRegex(regex_t *regex, const char *pattern, int flags)
-{
- int ret = regcomp(regex, pattern, flags);
- if( ret ) {
- size_t len = regerror(ret, regex, NULL, 0);
- char errorStr[len];
- regerror(ret, regex, errorStr, len);
- fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
- exit(-1);
- }
-}