Made it 2.0.0, and removed the changes that are in 1.1.x, as
[freeradius.git] / src / modules / rlm_logintime / 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        <freeradius-devel/autoconf.h>
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include <freeradius-devel/radiusd.h>
34
35 static const char *days[] =
36         { "su", "mo", "tu", "we", "th", "fr", "sa", "wk", "any", "al" };
37
38 #define DAYMIN          (24*60)
39 #define WEEKMIN         (24*60*7)
40 #define val(x)          (( (x) < 48 || (x) > 57) ? 0 : ((x) - 48))
41
42 #if 0 /* Set to 1 if you're a developer and want to debug this code */
43 #       define timestr_debug DEBUG2
44 #       define do_timestr_debug 1
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((int) *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((int) *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((int) *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, s_tm;
206         char bitmap[WEEKMIN / 8];
207         int now, tot, i;
208         int byte, bit;
209 #ifdef do_timestr_debug
210         int y;
211         char *s;
212         char null[8];
213 #endif
214
215         tm = localtime_r(&t, &s_tm);
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 do_timestr_debug
222         memset(null, 0, 8);
223         for (i = 0; i < 7; i++) {
224                 timestr_debug("%d: ", i);
225                 s = bitmap + 180 * i;
226                 for (y = 0; y < 23; y++) {
227                         s = bitmap + 180 * i + (75 * y) / 10;
228                         timestr_debug("%c", memcmp(s, null, 8) == 0 ? '.' : '#');
229                 }
230                 timestr_debug("\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
254         return (i == now) ? 0 : tot;
255 }
256
257 #ifdef STANDALONE
258
259 int main(int argc, char **argv)
260 {
261         int l;
262
263         if (argc != 2) {
264                 fprintf(stderr, "Usage: test timestring\n");
265                 exit(1);
266         }
267         l = timestr_match(argv[1], time(NULL));
268         printf ("%s: %d seconds left\n", argv[1], l);
269         return 0;
270 }
271
272 #endif
273