3 * UCC (University [of WA] Computer Club) Electronic Accounting System
6 * main.c - Core and Initialisation
8 * This file is licenced under the 3-clause BSD Licence. See the file
9 * COPYING for full details.
14 #include <ctype.h> // isspace
18 #include <unistd.h> // close
19 #include <netdb.h> // gethostbyname
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
25 typedef struct sItem {
32 int sendf(int Socket, const char *Format, ...);
33 int OpenConnection(const char *Host, int Port);
34 char *trim(char *string);
35 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage);
36 void CompileRegex(regex_t *regex, const char *pattern, int flags);
39 char *gsDispenseServer = "localhost";
40 int giDispensePort = 11020;
47 int main(int argc, char *argv[])
50 int i, responseCode, len;
53 // -- Create regular expressions
54 // > Code Type Count ...
55 CompileRegex(&gArrayRegex, "^([0-9]{3})\\s+([A-Za-z]+)\\s+([0-9]+)", REG_EXTENDED); //
56 // > Code Type Ident Price Desc
57 CompileRegex(&gItemRegex, "^([0-9]{3})\\s+(.+?)\\s+(.+?)\\s+([0-9]+)\\s+(.+)$", REG_EXTENDED);
60 sock = OpenConnection(gsDispenseServer, giDispensePort);
61 if( sock < 0 ) return -1;
63 // Determine what to do
66 if( strcmp(argv[1], "acct") == 0 )
74 // Ask server for stock list
75 send(sock, "ENUM_ITEMS\n", 11, 0);
76 len = recv(sock, buffer, BUFSIZ-1, 0);
81 printf("Output: %s\n", buffer);
83 responseCode = atoi(buffer);
84 if( responseCode != 201 )
86 fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n", responseCode);
92 char *itemType, *itemStart;
94 regmatch_t matches[4];
96 // Expected format: 201 Items <count> <item1> <item2> ...
97 RunRegex(&gArrayRegex, buffer, 4, matches, "Malformed server response");
99 itemType = &buffer[ matches[2].rm_so ]; buffer[ matches[2].rm_eo ] = '\0';
100 count = atoi( &buffer[ matches[3].rm_so ] );
103 if( strcmp(itemType, "Items") != 0 ) {
105 fprintf(stderr, "Unexpected array type, expected 'Items', got '%s'\n",
110 itemStart = &buffer[ matches[3].rm_eo ];
112 gaItems = malloc( count * sizeof(tItem) );
114 for( giNumItems = 0; giNumItems < count && itemStart; giNumItems ++ )
116 char *next = strchr( ++itemStart, ' ' );
117 if( next ) *next = '\0';
118 gaItems[giNumItems].Ident = strdup(itemStart);
124 // Display the list for the user
125 for( i = 0; i < giNumItems; i ++ )
127 regmatch_t matches[6];
130 printf("%2i %s\t", i, gaItems[i].Ident);
133 sendf(sock, "ITEM_INFO %s\n", gaItems[i].Ident);
134 len = recv(sock, buffer, BUFSIZ-1, 0);
138 responseCode = atoi(buffer);
139 if( responseCode != 202 ) {
140 fprintf(stderr, "Unknown response from dispense server (Response Code %i)\n", responseCode);
144 RunRegex(&gItemRegex, buffer, 6, matches, "Malformed server response");
146 buffer[ matches[3].rm_eo ] = '\0';
148 gaItems[i].Price = atoi( buffer + matches[4].rm_so );
149 gaItems[i].Desc = strdup( buffer + matches[5].rm_so );
151 printf("%3i %s\n", gaItems[i].Price, gaItems[i].Desc);
155 // and choose what to dispense
160 fgets(buffer, BUFSIZ, stdin);
164 if( buf[0] == 'q' ) break;
168 printf("buf = '%s', atoi(buf) = %i\n", buf, i);
170 if( i != 0 || buf[0] == '0' )
172 printf("i = %i\n", i);
174 if( i < 0 || i >= giNumItems ) {
175 printf("Bad item (should be between 0 and %i)\n", giNumItems);
179 sendf(sock, "DISPENSE %s\n", gaItems[i].Ident);
181 len = recv(sock, buffer, BUFSIZ-1, 0);
185 responseCode = atoi(buffer);
186 switch( responseCode )
189 printf("Dispense OK\n");
192 printf("Not authenticated\n");
195 printf("Insufficient balance\n");
198 printf("Bad item name, bug report\n");
201 printf("Item failed to dispense, is the slot empty?\n");
204 printf("Unknown response code %i\n", responseCode);
218 int sendf(int Socket, const char *Format, ...)
223 va_start(args, Format);
224 len = vsnprintf(NULL, 0, Format, args);
229 va_start(args, Format);
230 vsnprintf(buf, len+1, Format, args);
233 return send(Socket, buf, len, 0);
237 int OpenConnection(const char *Host, int Port)
239 struct hostent *host;
240 struct sockaddr_in serverAddr;
243 host = gethostbyname(Host);
245 fprintf(stderr, "Unable to look up '%s'\n", Host);
249 memset(&serverAddr, 0, sizeof(serverAddr));
251 serverAddr.sin_family = AF_INET; // IPv4
252 // NOTE: I have a suspicion that IPv6 will play sillybuggers with this :)
253 serverAddr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
254 serverAddr.sin_port = htons(Port);
256 sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
258 fprintf(stderr, "Failed to create socket\n");
262 if( connect(sock, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0 ) {
263 fprintf(stderr, "Failed to connect to server\n");
270 char *trim(char *string)
274 while( isspace(*string) )
277 for( i = strlen(string); i--; )
279 if( isspace(string[i]) )
288 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
292 ret = regexec(regex, string, nMatches, matches, 0);
294 size_t len = regerror(ret, regex, NULL, 0);
296 regerror(ret, regex, errorStr, len);
297 printf("string = '%s'\n", string);
298 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
305 void CompileRegex(regex_t *regex, const char *pattern, int flags)
307 int ret = regcomp(regex, pattern, flags);
309 size_t len = regerror(ret, regex, NULL, 0);
311 regerror(ret, regex, errorStr, len);
312 fprintf(stderr, "Regex compilation failed - %s\n", errorStr);