* src/main/timestr.c: debugging not meant for end-user
[freeradius.git] / src / main / timestr.c
1 /*
2  * timestr.c    See if a string like 'Su2300-0700' matches (UUCP style).
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * Copyright 2000  The FreeRADIUS server project
21  * Copyright 2000  Alan DeKok <aland@ox.org>
22  */
23
24 static const char rcsid[] = "$Id$";
25
26 #include        "autoconf.h"
27 #include        "libradius.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33
34 #include "radiusd.h"
35
36 static const char *days[] =
37         { "su", "mo", "tu", "we", "th", "fr", "sa", "wk", "any", "al" };
38
39 #define DAYMIN          (24*60)
40 #define WEEKMIN         (24*60*7)
41 #define val(x)          (( (x) < 48 || (x) > 57) ? 0 : ((x) - 48))
42
43 #if 0 /* Set to 1 if you're a developer and want to debug this code */
44 #       define timestr_debug DEBUG2
45 #else
46 #       define timestr_debug if (0) printf
47 #endif
48
49 /*
50  *      String code.
51  */
52 static int strcode (const char **str)
53 {
54         int i;
55         size_t l;
56
57         timestr_debug("strcode %s called\n", *str);
58
59         for (i = 0; i < 10; i++) {
60                 l = strlen(days[i]);
61                 if (l > strlen(*str))
62                         continue;
63                 if (strncmp(*str, days[i], l) == 0) {
64                         *str += l;
65                         break;
66                 }
67         }
68         timestr_debug("strcode result %d\n", i);
69
70         return (i >= 10) ? -1 : i;
71
72 }
73
74 /*
75  *      Fill bitmap with hours/mins.
76  */
77 static int hour_fill(char *bitmap, const char *tm)
78 {
79         char *p;
80         int start, end;
81         int i, bit, byte;
82
83         timestr_debug("hour_fill called for %s\n", tm);
84
85         /*
86          *      Get timerange in start and end.
87          */
88         end = -1;
89         if ((p = strchr(tm, '-')) != NULL) {
90                 p++;
91                 if (p - tm != 5 || strlen(p) < 4 || !isdigit(*p))
92                         return 0;
93                 end = 600 * val(p[0]) + 60 * val(p[1]) + atoi(p + 2);
94         }
95         if (*tm == 0) {
96                 start = 0;
97                 end = DAYMIN - 1;
98         } else {
99                 if (strlen(tm) < 4 || !isdigit(*tm))
100                         return 0;
101                 start = 600 * val(tm[0]) + 60 * val(tm[1]) + atoi(tm + 2);
102                 if (end < 0) end = start;
103         }
104         /* Treat 2400 as 0000, and do some more silent error checks. */
105         if (end < 0) end = 0;
106         if (start < 0) start = 0;
107         if (end >= DAYMIN) end = DAYMIN - 1;
108         if (start >= DAYMIN) start = DAYMIN - 1;
109
110         timestr_debug("hour_fill: range from %d to %d\n", start, end);
111
112         /*
113          *      Fill bitmap.
114          */
115         i = start;
116         while (1) {
117                 byte = (i / 8);
118                 bit = i % 8;
119                 timestr_debug("setting byte %d, bit %d\n", byte, bit);
120                 bitmap[byte] |= (1 << bit);
121                 if (i == end) break;
122                 i++;
123                 i %= DAYMIN;
124         }
125         return 1;
126 }
127
128 /*
129  *      Call the fill bitmap function for every day listed.
130  */
131 static int day_fill(char *bitmap, const char *tm)
132 {
133         const char *hr;
134         int n;
135         int start, end;
136
137         for (hr = tm; *hr; hr++)
138                 if (isdigit(*hr))
139                         break;
140         if (hr == tm) 
141                 tm = "Al";
142
143         timestr_debug("dayfill: hr %s    tm %s\n", hr, tm);
144
145         while ((start = strcode(&tm)) >= 0) {
146                 /*
147                  *      Find start and end weekdays and
148                  *      build a valid range 0 - 6.
149                  */
150                 if (*tm == '-') {
151                         tm++;
152                         if ((end = strcode(&tm)) < 0)
153                                 break;
154                 } else
155                         end = start;
156                 if (start == 7) {
157                         start = 1;
158                         end = 5;
159                 }
160                 if (start > 7) {
161                         start = 0;
162                         end = 6;
163                 }
164                 n = start;
165                 timestr_debug("day_fill: range from %d to %d\n", start, end);
166                 while (1) {
167                         hour_fill(bitmap + 180 * n, hr);
168                         if (n == end) break;
169                         n++;
170                         n %= 7;
171                 }
172         }
173
174         return 1;
175 }
176
177 /*
178  *      Fill the week bitmap with allowed times.
179  */
180 static int week_fill(char *bitmap, char *tm)
181 {
182         char *s;
183         char tmp[128];
184
185         strncpy(tmp, tm, 128);
186         tmp[127] = 0;
187         for (s = tmp; *s; s++)
188                 if (isupper(*s)) *s = tolower(*s);
189
190         s = strtok(tmp, ",|");
191         while (s) {
192                 day_fill(bitmap, s);
193                 s = strtok(NULL, ",|");
194         }
195
196         return 0;
197 }
198
199 /*
200  *      Match a timestring and return seconds left.
201  *      -1 for no match, 0 for unlimited.
202  */
203 int timestr_match(char *tmstr, time_t t)
204 {
205         struct tm *tm;
206         char bitmap[WEEKMIN / 8];
207         int now, tot, i;
208         int byte, bit;
209 #ifdef timestr_debug
210         int y;
211         char *s;
212         char null[8];
213 #endif
214
215         tm = localtime(&t);
216         now = tm->tm_wday * DAYMIN + tm->tm_hour * 60 + tm->tm_min;
217         tot = 0;
218         memset(bitmap, 0, sizeof(bitmap));
219         week_fill(bitmap, tmstr);
220
221 #ifdef timestr_debug
222         memset(null, 0, 8);
223         for (i = 0; i < 7; i++) {
224                 printf("%d: ", i);
225                 s = bitmap + 180 * i;
226                 for (y = 0; y < 23; y++) {
227                         s = bitmap + 180 * i + (75 * y) / 10;
228                         printf("%c", memcmp(s, null, 8) == 0 ? '.' : '#');
229                 }
230                 printf("\n");
231         }
232 #endif
233
234         /*
235          *      See how many minutes we have.
236          */
237         i = now;
238         while (1) {
239                 byte = i / 8;
240                 bit = i % 8;
241                 timestr_debug("READ: checking byte %d bit %d\n", byte, bit);
242                 if (!(bitmap[byte] & (1 << bit)))
243                         break;
244                 tot += 60;
245                 i++;
246                 i %= WEEKMIN;
247                 if (i == now)
248                         break;
249         }
250
251         if (tot != 0) 
252                 return -1;
253         return (i == now) ? 0 : tot;
254 }
255
256 #ifdef STANDALONE
257
258 int main(int argc, char **argv)
259 {
260         int l;
261
262         if (argc != 2) {
263                 fprintf(stderr, "Usage: test timestring\n");
264                 exit(1);
265         }
266         l = timestr_match(argv[1], time(NULL));
267         printf ("%s: %d seconds left\n", argv[1], l);
268         return 0;
269 }
270
271 #endif
272