+ if( !gsUserName )
+ {
+ if( gsEffectiveUser ) {
+ gsUserName = gsEffectiveUser;
+ }
+ else {
+ pwd = getpwuid( getuid() );
+ gsUserName = strdup(pwd->pw_name);
+ }
+ }
+
+ sendf(Socket, "USER_INFO %s\n", gsUserName);
+ buf = ReadLine(Socket);
+ responseCode = atoi(buf);
+ switch(responseCode)
+ {
+ case 202: break; // Ok
+
+ case 404:
+ printf("Invalid user? (USER_INFO failed)\n");
+ free(buf);
+ return -1;
+
+ default:
+ fprintf(stderr, "Unkown response code %i from server\n", responseCode);
+ printf("%s\n", buf);
+ free(buf);
+ exit(-1);
+ }
+
+ RunRegex(&gUserInfoRegex, buf, 6, matches, "Malformed server response");
+
+ giUserBalance = atoi( buf + matches[4].rm_so );
+ gsUserFlags = strdup( buf + matches[5].rm_so );
+
+ free(buf);
+
+ return 0;
+}
+
+/**
+ * \brief Read an item info response from the server
+ * \param Dest Destination for the read item (strings will be on the heap)
+ */
+int ReadItemInfo(int Socket, tItem *Dest)
+{
+ char *buf;
+ int responseCode;
+
+ regmatch_t matches[8];
+ char *statusStr;
+
+ // Get item info
+ buf = ReadLine(Socket);
+ responseCode = atoi(buf);
+
+ switch(responseCode)
+ {
+ case 202: break;
+
+ case 406:
+ printf("Bad item name\n");
+ free(buf);
+ return 1;
+
+ default:
+ fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n%s", responseCode, buf);
+ exit(-1);
+ }
+
+ RunRegex(&gItemRegex, buf, 8, matches, "Malformed server response");
+
+ buf[ matches[3].rm_eo ] = '\0';
+ buf[ matches[5].rm_eo ] = '\0';
+ buf[ matches[7].rm_eo ] = '\0';
+
+ statusStr = &buf[ matches[5].rm_so ];
+
+ Dest->ID = atoi( buf + matches[4].rm_so );
+
+ if( strcmp(statusStr, "avail") == 0 )
+ Dest->Status = 0;
+ else if( strcmp(statusStr, "sold") == 0 )
+ Dest->Status = 1;
+ else if( strcmp(statusStr, "error") == 0 )
+ Dest->Status = -1;
+ else {
+ fprintf(stderr, "Unknown response from dispense server (status '%s')\n",
+ statusStr);
+ return 1;
+ }
+ Dest->Price = atoi( buf + matches[6].rm_so );
+
+ // Hack a little to reduce heap fragmentation
+ {
+ char tmpType[strlen(buf + matches[3].rm_so) + 1];
+ char tmpDesc[strlen(buf + matches[7].rm_so) + 1];
+ strcpy(tmpType, buf + matches[3].rm_so);
+ strcpy(tmpDesc, buf + matches[7].rm_so);
+ free(buf);
+ Dest->Type = strdup( tmpType );
+ Dest->Desc = strdup( tmpDesc );
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Fill the item information structure
+ * \return Boolean Failure
+ */
+void PopulateItemList(int Socket)
+{
+ char *buf;
+ int responseCode;
+
+ char *itemType, *itemStart;
+ int count, i;
+ regmatch_t matches[4];
+
+ // Ask server for stock list
+ send(Socket, "ENUM_ITEMS\n", 11, 0);
+ buf = ReadLine(Socket);
+
+ //printf("Output: %s\n", buf);
+
+ responseCode = atoi(buf);
+ if( responseCode != 201 ) {
+ fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n", responseCode);
+ exit(-1);
+ }
+
+ // - Get item list -
+
+ // Expected format:
+ // 201 Items <count>
+ // 202 Item <count>
+ RunRegex(&gArrayRegex, buf, 4, matches, "Malformed server response");
+
+ itemType = &buf[ matches[2].rm_so ]; buf[ matches[2].rm_eo ] = '\0';
+ count = atoi( &buf[ 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 = &buf[ matches[3].rm_eo ];
+
+ free(buf);
+
+ giNumItems = count;
+ gaItems = malloc( giNumItems * sizeof(tItem) );
+
+ // Fetch item information
+ for( i = 0; i < giNumItems; i ++ )
+ {
+ ReadItemInfo( Socket, &gaItems[i] );
+ }
+
+ // Read end of list
+ buf = ReadLine(Socket);
+ responseCode = atoi(buf);
+
+ if( responseCode != 200 ) {
+ fprintf(stderr, "Unknown response from dispense server %i\n'%s'",
+ responseCode, buf
+ );
+ exit(-1);
+ }
+
+ free(buf);
+}
+
+
+/**
+ * \brief Get information on an item
+ * \return Boolean Failure
+ */
+int Dispense_ItemInfo(int Socket, const char *Type, int ID)
+{
+ tItem item;
+
+ // Query
+ sendf(Socket, "ITEM_INFO %s:%i\n", Type, ID);
+
+ if( ReadItemInfo(Socket, &item) )
+ {
+ return -1;
+ }
+
+ printf("%8s:%-2i %2i.%02i %s\n",
+ item.Type, item.ID,
+ item.Price/100, item.Price%100,
+ item.Desc);
+
+ free(item.Type);
+ free(item.Desc);
+
+ return 0;
+}
+
+/**
+ * \brief Dispense an item
+ * \return Boolean Failure
+ */
+int DispenseItem(int Socket, const char *Type, int ID)
+{
+ int ret, responseCode;
+ char *buf;
+
+ // Check for a dry run
+ if( gbDryRun ) {
+ printf("Dry Run - No action\n");
+ return 0;
+ }
+
+ // Dispense!
+ sendf(Socket, "DISPENSE %s:%i\n", Type, ID);
+ buf = ReadLine(Socket);