From: John Hodge Date: Tue, 23 Nov 2010 03:27:54 +0000 (+0800) Subject: Client work X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=7a5a062e4e9d9fdf7416104e91c74673d3c44c77;p=tpg%2Fopendispense2.git Client work - You could dispense now, if the client actually authed --- diff --git a/src/client/Makefile b/src/client/Makefile index 490e4dc..01a8c92 100644 --- a/src/client/Makefile +++ b/src/client/Makefile @@ -14,6 +14,9 @@ all: $(BIN) clean: $(RM) $(BIN) $(OBJ) +$(BIN): $(OBJ) + $(CC) -o $(BIN) $(OBJ) $(LDFLAGS) + %.o: %.c $(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS) $(CC) -M -MT $@ -o $*.d $< $(CPPFLAGS) diff --git a/src/client/main.c b/src/client/main.c index 8411181..2bb4f63 100644 --- a/src/client/main.c +++ b/src/client/main.c @@ -8,31 +8,308 @@ * This file is licenced under the 3-clause BSD Licence. See the file * COPYING for full details. */ +#include #include +#include +#include // isspace +#include +#include + +#include // close +#include // gethostbyname +#include +#include +#include + +// === TYPES === +typedef struct sItem { + char *Ident; + char *Desc; + int Price; +} tItem; + +// === PROTOTYPES === + int sendf(int Socket, const char *Format, ...); + int OpenConnection(const char *Host, int Port); +char *trim(char *string); + int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage); +void CompileRegex(regex_t *regex, const char *pattern, int flags); // === GLOBALS === -char *gsDispenseServer = "martello"; +char *gsDispenseServer = "localhost"; int giDispensePort = 11020; +tItem *gaItems; + int giNumItems; +regex_t gArrayRegex; +regex_t gItemRegex; // === CODE === int main(int argc, char *argv[]) { - // Connect to server + int sock; + int i, responseCode, len; + char buffer[BUFSIZ]; + + // -- Create regular expressions + // > Code Type Count ... + CompileRegex(&gArrayRegex, "^([0-9]{3})\\s+([A-Za-z]+)\\s+([0-9]+)", REG_EXTENDED); // + // > Code Type Ident Price Desc + CompileRegex(&gItemRegex, "^([0-9]{3})\\s+(.+?)\\s+(.+?)\\s+([0-9]+)\\s+(.+)$", REG_EXTENDED); + // Connect to server + sock = OpenConnection(gsDispenseServer, giDispensePort); + if( sock < 0 ) return -1; // Determine what to do if( argc > 1 ) { if( strcmp(argv[1], "acct") == 0 ) { + // Alter account + // List accounts return 0; } } // Ask server for stock list + send(sock, "ENUM_ITEMS\n", 11, 0); + len = recv(sock, buffer, BUFSIZ-1, 0); + buffer[len] = '\0'; + + trim(buffer); + + printf("Output: %s\n", buffer); + + responseCode = atoi(buffer); + if( responseCode != 201 ) + { + fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n", responseCode); + return -1; + } + + // Get item list + { + char *itemType, *itemStart; + int count; + regmatch_t matches[4]; + + // Expected format: 201 Items ... + RunRegex(&gArrayRegex, buffer, 4, matches, "Malformed server response"); + + itemType = &buffer[ matches[2].rm_so ]; buffer[ matches[2].rm_eo ] = '\0'; + count = atoi( &buffer[ matches[3].rm_so ] ); + + // Check array type + if( strcmp(itemType, "Items") != 0 ) { + // What the?! + fprintf(stderr, "Unexpected array type, expected 'Items', got '%s'\n", + itemType); + return -1; + } + + itemStart = &buffer[ matches[3].rm_eo ]; + + gaItems = malloc( count * sizeof(tItem) ); + + for( giNumItems = 0; giNumItems < count && itemStart; giNumItems ++ ) + { + char *next = strchr( ++itemStart, ' ' ); + if( next ) *next = '\0'; + gaItems[giNumItems].Ident = strdup(itemStart); + itemStart = next; + } + } + // Display the list for the user + for( i = 0; i < giNumItems; i ++ ) + { + regmatch_t matches[6]; + + // Print item Ident + printf("%2i %s\t", i, gaItems[i].Ident); + + // Get item info + sendf(sock, "ITEM_INFO %s\n", gaItems[i].Ident); + len = recv(sock, buffer, BUFSIZ-1, 0); + buffer[len] = '\0'; + trim(buffer); + + responseCode = atoi(buffer); + if( responseCode != 202 ) { + fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n", responseCode); + return -1; + } + + RunRegex(&gItemRegex, buffer, 6, matches, "Malformed server response"); + + buffer[ matches[3].rm_eo ] = '\0'; + + gaItems[i].Price = atoi( buffer + matches[4].rm_so ); + gaItems[i].Desc = strdup( buffer + matches[5].rm_so ); + + printf("%3i %s\n", gaItems[i].Price, gaItems[i].Desc); + } + + // and choose what to dispense + for(;;) + { + char *buf; + + fgets(buffer, BUFSIZ, stdin); + + buf = trim(buffer); + + if( buf[0] == 'q' ) break; + + i = atoi(buf); + + printf("buf = '%s', atoi(buf) = %i\n", buf, i); + + if( i != 0 || buf[0] == '0' ) + { + printf("i = %i\n", i); + + if( i < 0 || i >= giNumItems ) { + printf("Bad item (should be between 0 and %i)\n", giNumItems); + continue; + } + + sendf(sock, "DISPENSE %s\n", gaItems[i].Ident); + + len = recv(sock, buffer, BUFSIZ-1, 0); + buffer[len] = '\0'; + trim(buffer); + + responseCode = atoi(buffer); + switch( responseCode ) + { + case 200: + printf("Dispense OK\n"); + break; + case 401: + printf("Not authenticated\n"); + break; + case 402: + printf("Insufficient balance\n"); + break; + case 406: + printf("Bad item name, bug report\n"); + break; + case 500: + printf("Item failed to dispense, is the slot empty?\n"); + break; + default: + printf("Unknown response code %i\n", responseCode); + break; + } + + break; + } + } + + close(sock); return 0; } + +// === HELPERS === +int sendf(int Socket, const char *Format, ...) +{ + va_list args; + int len; + + va_start(args, Format); + len = vsnprintf(NULL, 0, Format, args); + va_end(args); + + { + char buf[len+1]; + va_start(args, Format); + vsnprintf(buf, len+1, Format, args); + va_end(args); + + return send(Socket, buf, len, 0); + } +} + +int OpenConnection(const char *Host, int Port) +{ + struct hostent *host; + struct sockaddr_in serverAddr; + int sock; + + host = gethostbyname(Host); + if( !host ) { + fprintf(stderr, "Unable to look up '%s'\n", Host); + return -1; + } + + memset(&serverAddr, 0, sizeof(serverAddr)); + + serverAddr.sin_family = AF_INET; // IPv4 + // NOTE: I have a suspicion that IPv6 will play sillybuggers with this :) + serverAddr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); + serverAddr.sin_port = htons(Port); + + sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + if( sock < 0 ) { + fprintf(stderr, "Failed to create socket\n"); + return -1; + } + + if( connect(sock, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0 ) { + fprintf(stderr, "Failed to connect to server\n"); + return -1; + } + + return sock; +} + +char *trim(char *string) +{ + int i; + + while( isspace(*string) ) + string ++; + + for( i = strlen(string); i--; ) + { + if( isspace(string[i]) ) + string[i] = '\0'; + else + break; + } + + 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 ) { + 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); + } +} diff --git a/src/server/server.c b/src/server/server.c index 7866274..44f3fa7 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -283,6 +283,7 @@ char *Server_Cmd_USER(tClient *Client, char *Args) Client->Salt[6] = 0x21 + (rand()&0x3F); Client->Salt[7] = 0x21 + (rand()&0x3F); + // TODO: Also send hash type to use, (SHA1 or crypt according to [DAA]) // "100 Salt xxxxXXXX\n" ret = strdup("100 SALT xxxxXXXX\n"); sprintf(ret, "100 SALT %s\n", Client->Salt);