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