From 7ba426116326af469bc8c73aae4fc1c56ebb3612 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 4 Mar 2011 16:44:50 +0800 Subject: [PATCH] Implementing item file editing (server-side implemented) --- notes/proto.txt | 18 +++++- src/server/common.h | 2 + src/server/itemdb.c | 154 ++++++++++++++++++++++++++++++++++++++++++++ src/server/server.c | 56 +++++++++++++++- 4 files changed, 226 insertions(+), 4 deletions(-) diff --git a/notes/proto.txt b/notes/proto.txt index d48031e..8a1a1da 100644 --- a/notes/proto.txt +++ b/notes/proto.txt @@ -57,7 +57,7 @@ s 200 Auth OK as \n or 401 Untrusted\n or 404 Bad Card ID\n c SETEUSER \n s 200 User set\n or 403 Not in coke\n or 404 User not found\n -=== Commands === +=== Standard User Commands === --- Dispense an item --- c DISPENSE \n s 200 Dispense OK\n or 402 Poor You\n or 406 Bad Item\n or 500 Dispense Error\n @@ -67,10 +67,20 @@ s 200 Give OK\n or 402 Poor You\n or 404 Bad User\n --- Donate to the club --- c DONATE \n s 200 Give OK\n or 402 Poor You\n + +=== Coke Member Commands (Account Manipulation) === --- Alter balance --- c ADD \n s 200 Add OK\n or 402 No balance\n or 403 Not Coke\n or 404 Bad User\n +--- Set balance --- +c SET \n +s 200 Add OK\n or 402 No balance\n or 403 Not Coke\n or 404 Bad User\n +--- Refund a drink --- +c REFUND [ ]\n +s 200 Add OK\n or 403 Not Coke\n or 404 Bad User\n 406 Bad Item\n + +=== Items === --- Get Item list --- c ENUM_ITEMS\n s 201 Items \n @@ -81,6 +91,11 @@ s 200 List End\n c ITEM_INFO \n s 202 Item \n "avail", "sold", or "error" +--- Update an item --- +c UPDATE_ITEM \n +s 200 Item updated + +=== Users === --- Get Users' Balances --- c ENUM_USERS[ min_balance:][ max_balance:][ flags:][ last_seen_before:][ last_seen_after:][ sort:[-desc]]\n s 201 Users \n @@ -95,6 +110,7 @@ s 200 List End\n c USER_INFO\n s 202 User \n +=== User Manipulation === --- Add a new user --- c USER_ADD \n s 200 User Added\n or 403 Not Wheel\n or 404 User Exists\n diff --git a/src/server/common.h b/src/server/common.h index cf68523..d5fd43c 100644 --- a/src/server/common.h +++ b/src/server/common.h @@ -72,6 +72,8 @@ extern int giNumHandlers; extern int giDebugLevel; // === FUNCTIONS === +extern void Items_UpdateFile(void); + // --- Helpers -- extern void AddPeriodicFunction(void (*Fcn)(void)); extern void CompileRegex(regex_t *Regex, const char *Pattern, int Flags); diff --git a/src/server/itemdb.c b/src/server/itemdb.c index 0c4df3f..dc188fd 100644 --- a/src/server/itemdb.c +++ b/src/server/itemdb.c @@ -102,6 +102,7 @@ void Load_Itemlist(void) // TODO: Be less lazy here and check the timestamp AddPeriodicFunction( Items_ReadFromFile ); } + /** * \brief Read the item list from disk */ @@ -221,6 +222,159 @@ void Items_ReadFromFile(void) gItems_LastUpdated = time(NULL); } +/** + * \brief Update the item file from the internal database + */ +void Items_UpdateFile(void) +{ + FILE *fp; + char buffer[BUFSIZ]; + char *line; + int lineNum = 0; + int i; + regmatch_t matches[5]; + char **line_comments; + int *line_items; + + // Error check + fp = fopen(gsItemListFile, "r"); + if(!fp) { + fprintf(stderr, "Unable to open item file '%s'\n", gsItemListFile); + perror("Unable to open item file"); + return ; + } + + // Count lines + while( fgets(buffer, BUFSIZ, fp) ) + { + lineNum ++; + } + + line_comments = malloc(lineNum * sizeof(char*)); + line_items = malloc(lineNum * sizeof(int)); + + // Parse file + lineNum = 0; + fseek(fp, 0, SEEK_SET); + while( fgets(buffer, BUFSIZ, fp) ) + { + char *hashPos, *semiPos; + char *type; + int num; + tHandler *handler; + + lineNum ++; + line_items[lineNum-1] = -1; + line_comments[lineNum-1] = NULL; + + // Get comments + hashPos = strchr(buffer, '#'); + semiPos = strchr(buffer, ';'); + if( hashPos && semiPos ) { + if( hashPos < semiPos ) + line_comments[lineNum-1] = strdup(hashPos); + } + else if( hashPos ) { + line_comments[lineNum-1] = strdup(hashPos); + } + else if( semiPos ) { + line_comments[lineNum-1] = strdup(semiPos); + } + if(hashPos) *hashPos = '\0'; + if(semiPos) *semiPos = '\0'; + + // Trim whitespace + line = trim(buffer); + if(strlen(line) == 0) continue; + + // Pass regex over line + if( RunRegex( &gItemFile_Regex, line, 5, matches, NULL) ) { + fprintf(stderr, "Syntax error on line %i of item file '%s'\n", lineNum, gsItemListFile); + return ; + } + + // Read line data + type = line + matches[1].rm_so; line[ matches[1].rm_eo ] = '\0'; + num = atoi( line + matches[2].rm_so ); + + // Find handler + handler = NULL; + for( i = 0; i < giNumHandlers; i ++ ) + { + if( strcmp(type, gaHandlers[i]->Name) == 0 ) { + handler = gaHandlers[i]; + break; + } + } + if( !handler ) { + fprintf(stderr, "Warning: Unknown item type '%s' on line %i\n", type, lineNum); + continue ; + } + + for( i = 0; i < giNumItems; i ++ ) + { + if( gaItems[i].Handler != handler ) continue; + if( gaItems[i].ID != num ) continue; + + line_items[lineNum-1] = i; + break; + } + if( i >= giNumItems ) { + continue; + } + } + + fclose(fp); + + fp = fopen("items.cfg.new", "w"); // DEBUG: Don't kill the real item file until debugged + + // Create new file + { + int done_items[giNumItems]; + memset(done_items, 0, sizeof(done_items)); + + // Existing items + for( i = 0; i < lineNum; i ++ ) + { + if( line_items[i] != -1 ) { + tItem *item = &gaItems[ line_items[i] ]; + + if( done_items[ line_items[i] ] ) { + fprintf(fp, "; DUP -"); + } + + done_items[ line_items[i] ] = 1; + fprintf(fp, "%s\t%i\t%i\t%s\t", + item->Handler->Name, item->ID, item->Price, item->Name + ); + } + + if( line_comments[i] ) { + fprintf(fp, "%s", line_comments[i]); + free( line_comments[i] ); + } + + fprintf(fp, "\n"); + } + + // New items + for( i = 0; i < giNumItems; i ++ ) + { + tItem *item = &gaItems[i]; + if( done_items[i] ) continue ; + + fprintf(fp, "%s\t%i\t%i\t%s\n", + item->Handler->Name, item->ID, item->Price, item->Name + ); + } + } + + free( line_comments ); + free( line_items ); + fclose(fp); +} + + char *trim(char *__str) { char *ret; diff --git a/src/server/server.c b/src/server/server.c index de79f41..1ebb612 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -70,6 +70,7 @@ void Server_Cmd_USERINFO(tClient *Client, char *Args); void _SendUserInfo(tClient *Client, int UserID); void Server_Cmd_USERADD(tClient *Client, char *Args); void Server_Cmd_USERFLAGS(tClient *Client, char *Args); +void Server_Cmd_UPDATEITEM(tClient *Client, char *Args); // --- Helpers --- void Debug(tClient *Client, const char *Format, ...); int sendf(int Socket, const char *Format, ...); @@ -97,7 +98,8 @@ const struct sClientCommand { {"ENUM_USERS", Server_Cmd_ENUMUSERS}, {"USER_INFO", Server_Cmd_USERINFO}, {"USER_ADD", Server_Cmd_USERADD}, - {"USER_FLAGS", Server_Cmd_USERFLAGS} + {"USER_FLAGS", Server_Cmd_USERFLAGS}, + {"UPDATE_ITEM", Server_Cmd_UPDATEITEM} }; #define NUM_COMMANDS ((int)(sizeof(gaServer_Commands)/sizeof(gaServer_Commands[0]))) @@ -177,8 +179,10 @@ void Server_Start(void) // write pidfile { FILE *fp = fopen("/var/run/dispsrv.pid", "w"); - fprintf(fp, "%i", getpid()); - fclose(fp); + if( fp ) { + fprintf(fp, "%i", getpid()); + fclose(fp); + } } for(;;) @@ -1283,6 +1287,52 @@ void Server_Cmd_USERFLAGS(tClient *Client, char *Args) sendf(Client->Socket, "200 User Updated\n"); } +void Server_Cmd_UPDATEITEM(tClient *Client, char *Args) +{ + char *itemname, *price_str, *description; + int price; + tItem *item; + + if( Server_int_ParseArgs(1, Args, &itemname, &price_str, &description, NULL) ) { + sendf(Client->Socket, "407 UPDATE_ITEM takes 3 arguments\n"); + return ; + } + + if( !Client->bIsAuthed ) { + sendf(Client->Socket, "401 Not Authenticated\n"); + return ; + } + + // Check user permissions + if( !(Bank_GetFlags(Client->UID) & (USER_FLAG_COKE|USER_FLAG_ADMIN)) ) { + sendf(Client->Socket, "403 Not in coke\n"); + return ; + } + + item = _GetItemFromString(itemname); + if( !item ) { + // TODO: Create item? + sendf(Client->Socket, "406 Bad Item ID\n"); + return ; + } + + price = atoi(price_str); + if( price <= 0 && price_str[0] != '0' ) { + sendf(CLient->Socket, "407 Invalid price set\n"); + } + + // Update the item + free(item->Name); + item->Name = strdup(description); + item->Price = price; + + // Update item file + Items_UpdateFile(); + + // Return OK + sendf(Client->Socket, "200 Item updated\n"); +} + // --- INTERNAL HELPERS --- void Debug(tClient *Client, const char *Format, ...) { -- 2.20.1