import from HEAD
[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 #       define do_timestr_debug 1
46 #else
47 #       define timestr_debug if (0) printf
48 #endif
49
50 /*
51  *      String code.
52  */
53 static int strcode (const char **str)
54 {
55         int i;
56         size_t l;
57
58         timestr_debug("strcode %s called\n", *str);
59
60         for (i = 0; i < 10; i++) {
61                 l = strlen(days[i]);
62                 if (l > strlen(*str))
63                         continue;
64                 if (strncmp(*str, days[i], l) == 0) {
65                         *str += l;
66                         break;
67                 }
68         }
69         timestr_debug("strcode result %d\n", i);
70
71         return (i >= 10) ? -1 : i;
72
73 }
74
75 /*
76  *      Fill bitmap with hours/mins.
77  */
78 static int hour_fill(char *bitmap, const char *tm)
79 {
80         char *p;
81         int start, end;
82         int i, bit, byte;
83
84         timestr_debug("hour_fill called for %s\n", tm);
85
86         /*
87          *      Get timerange in start and end.
88          */
89         end = -1;
90         if ((p = strchr(tm, '-')) != NULL) {
91                 p++;
92                 if (p - tm != 5 || strlen(p) < 4 || !isdigit((int) *p))
93                         return 0;
94                 end = 600 * val(p[0]) + 60 * val(p[1]) + atoi(p + 2);
95         }
96         if (*tm == 0) {
97                 start = 0;
98                 end = DAYMIN - 1;
99         } else {
100                 if (strlen(tm) < 4 || !isdigit((int) *tm))
101                         return 0;
102                 start = 600 * val(tm[0]) + 60 * val(tm[1]) + atoi(tm + 2);
103                 if (end < 0) end = start;
104         }
105         /* Treat 2400 as 0000, and do some more silent error checks. */
106         if (end < 0) end = 0;
107         if (start < 0) start = 0;
108         if (end >= DAYMIN) end = DAYMIN - 1;
109         if (start >= DAYMIN) start = DAYMIN - 1;
110
111         timestr_debug("hour_fill: range from %d to %d\n", start, end);
112
113         /*
114          *      Fill bitmap.
115          */
116         i = start;
117         while (1) {
118                 byte = (i / 8);
119                 bit = i % 8;
120                 timestr_debug("setting byte %d, bit %d\n", byte, bit);
121                 bitmap[byte] |= (1 << bit);
122                 if (i == end) break;
123                 i++;
124                 i %= DAYMIN;
125         }
126         return 1;
127 }
128
129 /*
130  *      Call the fill bitmap function for every day listed.
131  */
132 static int day_fill(char *bitmap, const char *tm)
133 {
134         const char *hr;
135         int n;
136         int start, end;
137
138         for (hr = tm; *hr; hr++)
139                 if (isdigit((int) *hr))
140                         break;
141         if (hr == tm)
142                 tm = "Al";
143
144         timestr_debug("dayfill: hr %s    tm %s\n", hr, tm);
145
146         while ((start = strcode(&tm)) >= 0) {
147                 /*
148                  *      Find start and end weekdays and
149                  *      build a valid range 0 - 6.
150                  */
151                 if (*tm == '-') {
152                         tm++;
153                         if ((end = strcode(&tm)) < 0)
154                                 break;
155                 } else
156                         end = start;
157                 if (start == 7) {
158                         start = 1;
159                         end = 5;
160                 }
161                 if (start > 7) {
162                         start = 0;
163                         end = 6;
164                 }
165                 n = start;
166                 timestr_debug("day_fill: range from %d to %d\n", start, end);
167                 while (1) {
168                         hour_fill(bitmap + 180 * n, hr);
169                         if (n == end) break;
170                         n++;
171                         n %= 7;
172                 }
173         }
174
175         return 1;
176 }
177
178 /*
179  *      Fill the week bitmap with allowed times.
180  */
181 static int week_fill(char *bitmap, char *tm)
182 {
183         char *s;
184         char tmp[128];
185
186         strncpy(tmp, tm, 128);
187         tmp[127] = 0;
188         for (s = tmp; *s; s++)
189                 if (isupper(*s)) *s = tolower(*s);
190
191         s = strtok(tmp, ",|");
192         while (s) {
193                 day_fill(bitmap, s);
194                 s = strtok(NULL, ",|");
195         }
196
197         return 0;
198 }
199
200 /*
201  *      Match a timestring and return seconds left.
202  *      -1 for no match, 0 for unlimited.
203  */
204 int timestr_match(char *tmstr, time_t t)
205 {
206         struct tm *tm, s_tm;
207         char bitmap[WEEKMIN / 8];
208         int now, tot, i;
209         int byte, bit;
210 #ifdef do_timestr_debug
211         int y;
212         char *s;
213         char null[8];
214 #endif
215
216         tm = localtime_r(&t, &s_tm);
217         now = tm->tm_wday * DAYMIN + tm->tm_hour * 60 + tm->tm_min;
218         tot = 0;
219         memset(bitmap, 0, sizeof(bitmap));
220         week_fill(bitmap, tmstr);
221
222 #ifdef do_timestr_debug
223         memset(null, 0, 8);
224         for (i = 0; i < 7; i++) {
225                 timestr_debug("%d: ", i);
226                 s = bitmap + 180 * i;
227                 for (y = 0; y < 23; y++) {
228                         s = bitmap + 180 * i + (75 * y) / 10;
229                         timestr_debug("%c", memcmp(s, null, 8) == 0 ? '.' : '#');
230                 }
231                 timestr_debug("\n");
232         }
233 #endif
234
235         /*
236          *      See how many minutes we have.
237          */
238         i = now;
239         while (1) {
240                 byte = i / 8;
241                 bit = i % 8;
242                 timestr_debug("READ: checking byte %d bit %d\n", byte, bit);
243                 if (!(bitmap[byte] & (1 << bit)))
244                         break;
245                 tot += 60;
246                 i++;
247                 i %= WEEKMIN;
248                 if (i == now)
249                         break;
250         }
251
252         if (tot == 0)
253                 return -1;
254
255         return (i == now) ? 0 : tot;
256 }
257
258 #ifdef STANDALONE
259
260 int main(int argc, char **argv)
261 {
262         int l;
263
264         if (argc != 2) {
265                 fprintf(stderr, "Usage: test timestring\n");
266                 exit(1);
267         }
268         l = timestr_match(argv[1], time(NULL));
269         printf ("%s: %d seconds left\n", argv[1], l);
270         return 0;
271 }
272
273 #endif
274