--- /dev/null
+== Item Database Format ==
+(Simple Version)
+
+Each line denotes a "slot"
+ <system>\t<code>\t<price>\t<description>
+Comments are denoted by '#' or ';' (with # usually being for info comments
+and ; for commenting out)
+comments are allowed anywhere on a line and act until the end of the line.
+
+
+For example, a coke could be
+ drink 06 96 Coke
+A pseudo-item could le
+ pseudo 01 10 Laserprint
+Or a snack
+ snack 64 128 Mars Bar
+
+The <system> denotes what controller plugin to use for the item.
+Currently there are only three:
+ "drink" is the drinks machine
+ "pseudo" is essentially a no-op, no action is taken on dispense (save
+ for logging)
+ "snack" controls the snack machine, dropping an item on dispense
+
*/
int GetUserID(const char *Username)
{
- return 0;
+ return -1;
}
// === CONSTANTS ===
#define DEFAULT_CONFIG_FILE "/etc/opendispense/main.cfg"
+#define DEFAULT_ITEM_FILE "/etc/opendispense/items.cfg"
// === HELPER MACROS ===
#define _EXPSTR(x) #x
#include <stdlib.h>
// === CODE ===
+/**
+ * \brief Dispense an item for a user
+ *
+ * The core of the dispense system, I kinda like it :)
+ */
int DispenseItem(int User, int Item)
{
int ret;
tHandler *handler;
char *username;
+ // Sanity check please?
if(Item < 0 || Item >= giNumItems)
return -1;
+ // Get item pointers
item = &gaItems[Item];
handler = &gaHandlers[ item->Type ];
- username = GetUserName(User);
-
+ // Check if the dispense is possible
ret = handler->CanDispense( User, item->ID );
if(!ret) return ret;
+ // Subtract the balance
ret = AlterBalance( User, -item->Price );
// What value should I use for this error?
// AlterBalance should return the final user balance
if(ret == 0) return 1;
+ // Get username for debugging
+ username = GetUserName(User);
+
+ // Actually do the dispense
ret = handler->DoDispense( User, item->ID );
if(ret) {
Log_Error("Dispense failed after deducting cost (%s dispensing %s - %ic)",
return 1;
}
+ // And log that it happened
Log_Info("Dispensed %s (%i:%i) for %s [cost %i, balance %i cents]",
item->Name, item->Type, item->ID,
username, item->Price, GetBalance(User)
int giNumItems = 0;
tItem *gaItems = NULL;
tHandler *gaHandlers = NULL;
+char *gsItemListFile = DEFAULT_ITEM_FILE;
// === CODE ===
+/**
+ * \brief Read the item list from disk
+ */
+void Load_Itemlist(void)
+{
+ FILE *fp = fopen(gsItemListFile, "r");
+ char buffer[BUFSIZ];
+ char *line;
+
+ // Error check
+ if(!fp) {
+ fprintf(stderr, "Unable to open item file '%s'\n", gsItemListFile);
+ perror("Unable to open item file");
+ }
+
+ while( fgets(buffer, BUFSIZ, fp) )
+ {
+ char *tmp;
+ char *type, *num, *price, *desc;
+ // Remove comments
+ tmp = strchr(buffer, '#');
+ if(tmp) *tmp = '\0';
+ tmp = strchr(buffer, ';');
+ if(tmp) *tmp = '\0';
+
+ // Trim whitespace
+ line = trim(buffer);
+
+ // Parse Line
+ // - Type
+ type = line;
+ // - Number
+ num = strchr(type, ' ');
+ if(num) while(*num == ' ' || *num == '\t');
+ if(!num) {
+ fprintf(stderr, "Syntax error on line %i of item file\n", lineNum);
+ continue;
+ }
+ // - Price
+ price = strchr(num, ' ');
+ }
+
+}
Init_Cokebank();
- //Load_Itemlist();
+ Load_Itemlist();
Server_Start();
// Get UID
Client->UID = GetUserID( Args );
- if( Client->UID <= 0 ) {
+ if( Client->UID < 0 ) {
if(giDebugLevel)
printf("Client %i: Unknown user '%s'\n", Client->ID, Args);
return strdup("401 Auth Failure\n");
for( ; i < BufSize; i++ )
Dest[i] = 0;
}
+
+/**
+ * \brief Decode a Base64 value
+ */
+int UnBase64(uint8_t *Dest, char *Src, int BufSize)
+{
+ uint32_t val;
+ int i, j;
+ char *start_src = Src;
+
+ for( i = 0; i+2 < BufSize; i += 3 )
+ {
+ val = 0;
+ for( j = 0; j < 4; j++, Src ++ ) {
+ if('A' <= *Src && *Src <= 'Z')
+ val |= (*Src - 'A') << ((3-j)*6);
+ else if('a' <= *Src && *Src <= 'z')
+ val |= (*Src - 'a' + 26) << ((3-j)*6);
+ else if('0' <= *Src && *Src <= '9')
+ val |= (*Src - '0' + 52) << ((3-j)*6);
+ else if(*Src == '+')
+ val |= 62 << ((3-j)*6);
+ else if(*Src == '/')
+ val |= 63 << ((3-j)*6);
+ else if(!*Src)
+ break;
+ else if(*Src != '=')
+ j --; // Ignore invalid characters
+ }
+ Dest[i ] = (val >> 16) & 0xFF;
+ Dest[i+1] = (val >> 8) & 0xFF;
+ Dest[i+2] = val & 0xFF;
+ if(j != 4) break;
+ }
+
+ // Finish things off
+ if(i < BufSize)
+ Dest[i] = (val >> 16) & 0xFF;
+ if(i+1 < BufSize)
+ Dest[i+1] = (val >> 8) & 0xFF;
+
+ return Src - start_src;
+}