f95637fe00de7365ccfac3858083a66bfe7fafa7
[tpg/opendispense2.git] / src / server / main.c
1 /*
2  * OpenDispense 2 
3  * UCC (University [of WA] Computer Club) Electronic Accounting System
4  *
5  * main.c - Initialisation Code
6  *
7  * This file is licenced under the 3-clause BSD Licence. See the file
8  * COPYING for full details.
9  */
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <signal.h>
14 #include "common.h"
15 #include <termios.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <stdarg.h>
20 #include <syslog.h>
21 #include <pthread.h>
22 #include "../cokebank.h"
23
24 // === IMPORTS ===
25 extern void     Init_Handlers(void);
26 extern void     Load_Itemlist(void);
27 extern void     Server_Start(void);
28 extern int      giServer_Port;
29 extern char     *gsItemListFile;
30 extern char     *gsCoke_SerialPort;
31 extern char     *gsSnack_SerialPort;
32 extern char     *gsDoor_Password;
33
34 // === PROTOTYPES ===
35 void    *Periodic_Thread(void *Unused);
36
37 // === GLOBALS ===
38  int    giDebugLevel = 0;
39 char    *gsCokebankPath = "cokebank.db";
40 // - Functions called every 20s (or so)
41 #define ciMaxPeriodics  10
42 struct sPeriodicCall {
43         void    (*Function)(void);
44 }       gaPeriodicCalls[ciMaxPeriodics];
45
46 // === CODE ===
47 void sigint_handler()
48 {
49         exit(0);
50 }
51
52 void PrintUsage(const char *progname)
53 {
54         fprintf(stderr, "Usage: %s\n", progname);
55         fprintf(stderr, "  -p    Set server port (default 11020)\n");
56         fprintf(stderr, "  -d    Set debug level (0 - 2, default 0)\n");
57         fprintf(stderr, "  --itemsfile\n");
58         fprintf(stderr, "        Set debug level (0 - 2, default 0)\n");
59         fprintf(stderr, "  --cokeport\n");
60         fprintf(stderr, "        Coke machine serial port (Default \"/dev/ttyS0\")\n");
61         fprintf(stderr, "  --doorpass\n");
62         fprintf(stderr, "        Door LAT password file (Default empty password)\n");
63         fprintf(stderr, "  --cokebank\n");
64         fprintf(stderr, "        Coke bank database file (Default \"cokebank.db\")\n");
65 }
66
67 int main(int argc, char *argv[])
68 {
69          int    i;
70         pthread_t       timer_thread;
71         
72         // Parse Arguments
73         for( i = 1; i < argc; i++ )
74         {
75                 char    *arg = argv[i];
76                 if( arg[0] == '-' && arg[1] != '-')
77                 {
78                         switch(arg[1])
79                         {
80                         case 'p':
81                                 if( i + 1 >= argc )     return -1;
82                                 giServer_Port = atoi(argv[++i]);
83                                 break;
84                         case 'd':
85                                 if( i + 1 >= argc )     return -1;
86                                 giDebugLevel = atoi(argv[++i]);
87                                 break;
88                         default:
89                                 // Usage Error?
90                                 PrintUsage(argv[0]);
91                                 return -1;
92                         }
93                 }
94                 else if( arg[0] == '-' && arg[1] == '-' ) {
95                         if( strcmp(arg, "--itemsfile") == 0 ) {
96                                 if( i + 1 >= argc )     return -1;
97                                 gsItemListFile = argv[++i];
98                         }
99                         else if( strcmp(arg, "--cokeport") == 0 ) {
100                                 if( i + 1 >= argc )     return -1;
101                                 gsCoke_SerialPort = argv[++i];
102                         }
103                         else if( strcmp(arg, "--snackport") == 0 ) {
104                                 if( i + 1 >= argc )     return -1;
105                                 gsSnack_SerialPort = argv[++i];
106                         }
107                         else if( strcmp(arg, "--doorpass") == 0 ) {
108                                 FILE    *fp;
109                                 char    buf[30];
110                                 if( i + 1 >= argc )     return -1;
111                                 fp = fopen(argv[++i], "r");
112                                 fgets(buf, sizeof buf, fp);
113                                 fclose(fp);
114                                 gsDoor_Password = strdup(buf);;
115                         }
116                         else if( strcmp(arg, "--cokebank") == 0 ) {
117                                 if( i + 1 >= argc )     return -1;
118                                 gsCokebankPath = argv[++i];
119                         }
120                         else {
121                                 // Usage error?
122                                 PrintUsage(argv[0]);
123                                 return -1;
124                         }
125                 }
126                 else {
127                         // Usage Error?
128                         PrintUsage(argv[0]);
129                         return -1;
130                 }
131         }
132         
133         signal(SIGINT, sigint_handler);
134         
135         openlog("odispense2", 0, LOG_LOCAL4);
136         
137         if( Bank_Initialise(gsCokebankPath) )
138                 return -1;
139
140         Init_Handlers();
141
142         Load_Itemlist();
143         
144         pthread_create( &timer_thread, NULL, Periodic_Thread, NULL );
145         
146         Server_Start();
147         
148         pthread_kill(timer_thread, SIGKILL);
149
150         return 0;
151 }
152
153 void *Periodic_Thread(void *Unused)
154 {
155          int    i;
156         Unused = NULL;  // quiet, gcc
157         
158         for( ;; )
159         {
160                 sleep(10);      // Sleep for a while
161 //              printf("Periodic firing\n");
162                 for( i = 0; i < ciMaxPeriodics; i ++ )
163                 {
164                         if( gaPeriodicCalls[i].Function )
165                                 gaPeriodicCalls[i].Function();
166                 }
167         }
168         return NULL;
169 }
170
171 void AddPeriodicFunction(void (*Fcn)(void))
172 {
173         int i;
174         for( i = 0; i < ciMaxPeriodics; i ++ )
175         {
176                 if( gaPeriodicCalls[i].Function )       continue;
177                 gaPeriodicCalls[i].Function = Fcn;
178                 return ;
179         }
180         
181         fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
182 }
183
184 int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
185 {
186          int    ret;
187         
188         ret = regexec(regex, string, nMatches, matches, 0);
189         if( ret == REG_NOMATCH ) {
190                 return -1;
191         }
192         if( ret ) {
193                 size_t  len = regerror(ret, regex, NULL, 0);
194                 char    errorStr[len];
195                 regerror(ret, regex, errorStr, len);
196                 printf("string = '%s'\n", string);
197                 fprintf(stderr, "%s\n%s", errorMessage, errorStr);
198                 exit(-1);
199         }
200         
201         return ret;
202 }
203
204 void CompileRegex(regex_t *regex, const char *pattern, int flags)
205 {
206          int    ret = regcomp(regex, pattern, flags);
207         if( ret ) {
208                 size_t  len = regerror(ret, regex, NULL, 0);
209                 char    errorStr[len];
210                 regerror(ret, regex, errorStr, len);
211                 fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
212                 exit(-1);
213         }
214 }
215
216 // Serial helper
217 int InitSerial(const char *File, int BaudRate)
218 {
219         struct termios  info;
220          int    baud;
221          int    fd;
222         
223         fd = open(File, O_RDWR | O_NOCTTY | O_NONBLOCK);
224         if( fd == -1 )  return -1;
225         
226         switch(BaudRate)
227         {
228         case 9600:      baud = B9600;   break;
229         default:        close(fd);      return -1;
230         }
231         
232         info.c_lflag = 0;       // Non-Canoical, No Echo
233         info.c_cflag = baud | CS8 | CLOCAL | CREAD;     // baud, 8N1
234         cfsetspeed(&info, baud);
235         info.c_cc[VTIME] = 0;   // No time limit
236         info.c_cc[VMIN] = 1;    // Block until 1 char
237         
238         tcflush(fd, TCIFLUSH);
239         tcsetattr(fd, TCSANOW, &info);
240         
241         return fd;
242 }
243
244
245 /**
246  * \brief Create a formatted heap string
247  */
248 char *mkstr(const char *Format, ...)
249 {
250         va_list args;
251          int    len;
252         char    *ret;
253
254         va_start(args, Format);
255         len = vsnprintf(NULL, 0, Format, args);
256         va_end(args);
257
258         ret = malloc( len + 1 );
259         if(!ret)        return NULL;
260
261         va_start(args, Format);
262         vsprintf(ret, Format, args);
263         va_end(args);
264         
265         return ret;
266 }
267

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