+ // - Get item list -
+
+ // Expected format: 201 Items <count> <item1> <item2> ...
+ 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);
+ exit(-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;
+ }
+
+ // Fetch item information
+ for( i = 0; i < giNumItems; i ++ )
+ {
+ regmatch_t matches[6];
+
+ // Get item info
+ sendf(Socket, "ITEM_INFO %s\n", gaItems[i].Ident);
+ len = recv(Socket, 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);
+ exit(-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 );
+ }
+}
+
+/**
+ * \brief Dispense an item
+ * \return Boolean Failure
+ */
+int DispenseItem(int Socket, int ItemID)
+{
+ int ret, responseCode;
+ char *buf;
+
+ if( ItemID < 0 || ItemID > giNumItems ) return -1;
+
+ // Dispense!
+ sendf(Socket, "DISPENSE %s\n", gaItems[ItemID].Ident);
+ buf = ReadLine(Socket);
+
+ responseCode = atoi(buf);
+ switch( responseCode )
+ {
+ case 200:
+ printf("Dispense OK\n");
+ ret = 0;
+ break;
+ case 401:
+ printf("Not authenticated\n");
+ ret = 1;
+ break;
+ case 402:
+ printf("Insufficient balance\n");
+ ret = 1;
+ break;
+ case 406:
+ printf("Bad item name, bug report\n");
+ ret = 1;
+ break;
+ case 500:
+ printf("Item failed to dispense, is the slot empty?\n");
+ ret = 1;
+ break;
+ case 501:
+ printf("Dispense not possible (slot empty/permissions)\n");
+ ret = 1;
+ break;
+ default:
+ printf("Unknown response code %i ('%s')\n", responseCode, buf);
+ ret = -2;
+ break;
+ }
+
+ free(buf);
+ return ret;
+}
+
+/**
+ * \brief Alter a user's balance
+ */
+int Dispense_AlterBalance(int Socket, const char *Username, int Ammount, const char *Reason)
+{
+ char *buf;
+ int responseCode;
+
+ sendf(Socket, "ADD %s %i %s\n", Username, Ammount, Reason);
+ buf = ReadLine(Socket);
+
+ responseCode = atoi(buf);
+ free(buf);
+
+ switch(responseCode)
+ {
+ case 200: return 0; // OK
+ case 403: // Not in coke
+ fprintf(stderr, "You are not in coke (sucker)\n");
+ return 1;
+ case 404: // Unknown user
+ fprintf(stderr, "Unknown user '%s'\n", Username);
+ return 2;
+ default:
+ fprintf(stderr, "Unknown response code %i\n", responseCode);
+ return -1;
+ }
+
+ return -1;
+}
+
+/**
+ * \brief Alter a user's balance
+ */
+int Dispense_SetBalance(int Socket, const char *Username, int Ammount, const char *Reason)
+{
+ char *buf;
+ int responseCode;
+
+ sendf(Socket, "SET %s %i %s\n", Username, Ammount, Reason);
+ buf = ReadLine(Socket);
+
+ responseCode = atoi(buf);
+ free(buf);
+
+ switch(responseCode)
+ {
+ case 200: return 0; // OK
+ case 403: // Not in coke
+ fprintf(stderr, "You are not in coke (sucker)\n");
+ return 1;
+ case 404: // Unknown user
+ fprintf(stderr, "Unknown user '%s'\n", Username);
+ return 2;
+ default:
+ fprintf(stderr, "Unknown response code %i\n", responseCode);
+ return -1;
+ }
+
+ return -1;
+}
+
+int Dispense_EnumUsers(int Socket)
+{
+ printf("TODO: Dispense_EnumUsers\n");
+ return -1;
+}
+
+int Dispense_ShowUser(int Socket, const char *Username)
+{
+ char *buf;
+ int responseCode, ret;
+
+ sendf(Socket, "USER_INFO %s\n", Username);
+ buf = ReadLine(Socket);
+
+ responseCode = atoi(buf);
+
+ switch(responseCode)
+ {
+ case 202:
+ _PrintUserLine(buf);
+ ret = 0;
+ break;
+
+ case 404:
+ printf("Unknown user '%s'\n", Username);
+ ret = 1;
+ break;
+
+ default:
+ fprintf(stderr, "Unknown response code %i '%s'\n", responseCode, buf);
+ ret = -1;
+ break;
+ }
+
+ free(buf);
+
+ return ret;
+}
+
+void _PrintUserLine(const char *Line)
+{
+ regmatch_t matches[6];
+ int bal;
+
+ RunRegex(&gUserInfoRegex, Line, 6, matches, "Malformed server response");
+ // 3: Username
+ // 4: Balance
+ // 5: Flags
+ {
+ int usernameLen = matches[3].rm_eo - matches[3].rm_so;
+ char username[usernameLen + 1];
+ int flagsLen = matches[5].rm_eo - matches[5].rm_so;
+ char flags[flagsLen + 1];
+
+ memcpy(username, Line + matches[3].rm_so, usernameLen);
+ username[usernameLen] = '\0';
+ memcpy(flags, Line + matches[5].rm_so, flagsLen);
+ flags[flagsLen] = '\0';
+
+ bal = atoi(Line + matches[4].rm_so);
+ printf("%-15s: $%i.%02i (%s)\n", username, bal/100, bal%100, flags);
+ }
+}
+
+// ---------------
+// --- Helpers ---
+// ---------------
+char *ReadLine(int Socket)
+{
+ static char buf[BUFSIZ];
+ static int bufPos = 0;
+ int len;
+ char *newline = NULL;
+ int retLen = 0;
+ char *ret = malloc(10);
+
+ #if DBG_TRACE_SERVER
+ printf("ReadLine: ");
+ #endif
+ fflush(stdout);
+
+ ret[0] = '\0';
+
+ while( !newline )
+ {
+ len = recv(Socket, buf+bufPos, BUFSIZ-1-bufPos, 0);
+ buf[bufPos+len] = '\0';
+
+ newline = strchr( buf+bufPos, '\n' );
+ if( newline ) {
+ *newline = '\0';
+ }
+
+ retLen += strlen(buf+bufPos);
+ ret = realloc(ret, retLen + 1);
+ strcat( ret, buf+bufPos );
+
+ if( newline ) {
+ bufPos += newline - (buf+bufPos) + 1;
+ }
+ if( len + bufPos == BUFSIZ - 1 ) bufPos = 0;
+ }
+
+ #if DBG_TRACE_SERVER
+ printf("%i '%s'\n", retLen, ret);
+ #endif
+
+ return ret;
+}
+
+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);
+
+ #if DBG_TRACE_SERVER
+ printf("sendf: %s", buf);
+ #endif
+
+ return send(Socket, buf, len, 0);
+ }