Implementing item file editing (server-side implemented)
authorJohn Hodge <[email protected]>
Fri, 4 Mar 2011 08:44:50 +0000 (16:44 +0800)
committerJohn Hodge <[email protected]>
Fri, 4 Mar 2011 08:44:50 +0000 (16:44 +0800)
notes/proto.txt
src/server/common.h
src/server/itemdb.c
src/server/server.c

index d48031e..8a1a1da 100644 (file)
@@ -57,7 +57,7 @@ s     200 Auth OK as <username>\n or 401 Untrusted\n or 404 Bad Card ID\n
 c      SETEUSER <username>\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 <item_id>\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 <ammount> <reason>\n
 s      200 Give OK\n or 402 Poor You\n
+
+=== Coke Member Commands (Account Manipulation) ===
 --- Alter balance ---
 c      ADD <user> <ammount> <reason>\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 <user> <balance> <reason>\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 <user> <item>[ <price>]\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 <count>\n
@@ -81,6 +91,11 @@ s    200 List End\n
 c      ITEM_INFO <item_id>\n
 s      202 Item <item_id> <status> <price> <description>\n
 <status>       "avail", "sold", or "error"
+--- Update an item ---
+c      UPDATE_ITEM <item_id> <price> <name>\n
+s      200 Item updated
+
+=== Users ===
 --- Get Users' Balances ---
 c      ENUM_USERS[ min_balance:<balance>][ max_balance:<balance>][ flags:<flagset>][ last_seen_before:<unix_timestamp>][ last_seen_after:<unix_timestamp>][ sort:<field>[-desc]]\n
 s      201 Users <count>\n
@@ -95,6 +110,7 @@ s    200 List End\n
 c      USER_INFO\n
 s      202 User <username> <balance> <flags>\n
 
+=== User Manipulation ===
 --- Add a new user ---
 c      USER_ADD <username>\n
 s      200 User Added\n or 403 Not Wheel\n or 404 User Exists\n
index cf68523..d5fd43c 100644 (file)
@@ -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);
index 0c4df3f..dc188fd 100644 (file)
@@ -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;
index de79f41..1ebb612 100644 (file)
@@ -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, ...)
 {

UCC git Repository :: git.ucc.asn.au