Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * Copyright (C) 2020 OpenSIPS Solutions |
4 | | * |
5 | | * This file is part of opensips, a free SIP server. |
6 | | * |
7 | | * opensips is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version |
11 | | * |
12 | | * opensips is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | #include <stdio.h> |
23 | | #include <string.h> |
24 | | #include <time.h> |
25 | | |
26 | | #include "mem/mem.h" |
27 | | #include "mem/shm_mem.h" |
28 | | #include "lib/osips_malloc.h" |
29 | | #include "time_rec.h" |
30 | | #include "ut.h" |
31 | | |
32 | | /* |
33 | | * USE_YWEEK_U -- Sunday system - see strftime %U |
34 | | * USE_YWEEK_V -- ISO 8601 - see strftime %V |
35 | | * USE_YWEEK_W -- Monday system - see strftime %W |
36 | | */ |
37 | | |
38 | | #ifndef USE_YWEEK_U |
39 | | #ifndef USE_YWEEK_V |
40 | | #ifndef USE_YWEEK_W |
41 | | #define USE_YWEEK_W /* Monday system */ |
42 | | #endif |
43 | | #endif |
44 | | #endif |
45 | | |
46 | 0 | #define WDAY_SU 0 |
47 | 0 | #define WDAY_MO 1 |
48 | 0 | #define WDAY_TU 2 |
49 | 0 | #define WDAY_WE 3 |
50 | 0 | #define WDAY_TH 4 |
51 | 0 | #define WDAY_FR 5 |
52 | 0 | #define WDAY_SA 6 |
53 | | #define WDAY_NU 7 |
54 | | |
55 | 0 | #define SEC_DAILY (60 * 60 * 24) |
56 | 0 | #define SEC_WEEKLY (7 * SEC_DAILY) |
57 | 0 | #define SEC_MONTHLY_MAX (31 * SEC_DAILY) |
58 | 0 | #define SEC_YEARLY_MAX (366 * SEC_DAILY) |
59 | | |
60 | | #ifdef USE_YWEEK_U |
61 | | #define SUN_WEEK(t) (int)(((t)->tm_yday + 7 - \ |
62 | | ((t)->tm_wday)) / 7) |
63 | | #else |
64 | 0 | #define MON_WEEK(t) (int)(((t)->tm_yday + 7 - \ |
65 | 0 | ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7) |
66 | | #endif |
67 | | |
68 | 0 | #define ac_get_wday_yr(t) (int)((t)->tm_yday/7) |
69 | 0 | #define ac_get_wday_mr(t) (int)(((t)->tm_mday-1)/7) |
70 | | |
71 | 0 | #define is_leap_year(yyyy) ((((yyyy)%400))?(((yyyy)%100)?(((yyyy)%4)?0:1):0):1) |
72 | | |
73 | | #define REC_ERR -1 |
74 | 0 | #define REC_MATCH 0 |
75 | 0 | #define REC_NOMATCH 1 |
76 | | |
77 | 0 | #define _IS_SET(x) ((x) != TR_NOVAL) |
78 | 0 | #define _D(c) ((c) -'0') |
79 | | |
80 | 0 | #define TR_SEPARATOR '|' |
81 | | |
82 | | #define load_TR_value( _p,_s, _tr, _func, _err, _done) \ |
83 | 0 | do{ \ |
84 | 0 | int _rc = 0; \ |
85 | 0 | _s = strchr(_p, (int)TR_SEPARATOR); \ |
86 | 0 | if (_s) \ |
87 | 0 | *_s = 0; \ |
88 | 0 | /* LM_DBG("----parsing tr param <%s>\n",_p); \ */\ |
89 | 0 | if(_s != _p) {\ |
90 | 0 | _rc = _func( _tr, _p); \ |
91 | 0 | if (_rc < 0) {\ |
92 | 0 | LM_DBG("func error\n"); \ |
93 | 0 | if (_s) *_s = TR_SEPARATOR; \ |
94 | 0 | goto _err; \ |
95 | 0 | } \ |
96 | 0 | } \ |
97 | 0 | if (_s) { \ |
98 | 0 | *_s = TR_SEPARATOR; \ |
99 | 0 | if (_rc == 0) \ |
100 | 0 | _p = _s+1; /* rc > 1 means: "input not consumed" */ \ |
101 | 0 | if ( *(_p)==0 ) \ |
102 | 0 | goto _done; \ |
103 | 0 | } else if (_rc == 0) { /* if all "input is consumed" */ \ |
104 | 0 | goto _done; \ |
105 | 0 | }\ |
106 | 0 | } while(0) |
107 | | |
108 | | #if 0 /* debugging mode */ |
109 | | #define LM_DEV LM_ERR |
110 | | #else |
111 | | #define LM_DEV(...) |
112 | | #endif |
113 | | |
114 | | typedef struct _ac_maxval |
115 | | { |
116 | | int yweek; |
117 | | int yday; /* current year's max days (365-366) */ |
118 | | int ywday; |
119 | | int mweek; /* current month's max number of weeks (4-5) */ |
120 | | int mday; /* current month's max days (28-31) */ |
121 | | int mwday; /* current month's max occurrences of current day (4-5) */ |
122 | | } ac_maxval_t, *ac_maxval_p; |
123 | | |
124 | | typedef struct _ac_tm |
125 | | { |
126 | | time_t time; |
127 | | struct tm t; |
128 | | int mweek; |
129 | | int yweek; |
130 | | int ywday; |
131 | | int wom; /* current day's week of the month (0-4) */ |
132 | | char flags; |
133 | | } ac_tm_t, *ac_tm_p; |
134 | | |
135 | 0 | #define TR_OP_NUL 0 |
136 | 0 | #define TR_OP_AND 1 |
137 | 0 | #define TR_OP_OR 2 |
138 | | |
139 | | int ac_tm_reset(ac_tm_p); |
140 | | |
141 | | int ac_get_mweek(struct tm*); |
142 | | int ac_get_yweek(struct tm*); |
143 | | int ac_get_wkst(); |
144 | | |
145 | | int ac_print(ac_tm_p); |
146 | | |
147 | | time_t ic_parse_datetime(char*,struct tm*); |
148 | | time_t ic_parse_duration(char*); |
149 | | |
150 | | tr_byxxx_p ic_parse_byday(char*, char); |
151 | | tr_byxxx_p ic_parse_byxxx(char*, char); |
152 | | int ic_parse_wkst(char*); |
153 | | |
154 | | |
155 | | static inline int strz2int(char *_bp) |
156 | 0 | { |
157 | 0 | int _v; |
158 | 0 | char *_p; |
159 | |
|
160 | 0 | _v = 0; |
161 | 0 | _p = _bp; |
162 | 0 | while(*_p && *_p>='0' && *_p<='9') |
163 | 0 | { |
164 | 0 | _v += *_p - '0'; |
165 | 0 | _p++; |
166 | 0 | } |
167 | 0 | return _v; |
168 | 0 | } |
169 | | |
170 | | |
171 | | /** |
172 | | * Check if @x falls within the recurring [@bgn, @end) time interval, |
173 | | * according to @freq. |
174 | | * |
175 | | * @x: value to check |
176 | | * @bgn: interval start |
177 | | * @end: interval end |
178 | | * @dur: duration of the interval (effectively: @end - @bgn) |
179 | | * @freq: FREQ_WEEKLY / FREQ_MONTHLY / FREQ_YEARLY |
180 | | * |
181 | | * Return: REC_MATCH or REC_NOMATCH |
182 | | */ |
183 | | int check_recur_itv(struct tm *x, struct tm *bgn, struct tm *end, |
184 | | time_t dur, int freq); |
185 | | |
186 | | |
187 | | static inline void ac_tm_fill(ac_tm_p _atp, struct tm* _tm) |
188 | 0 | { |
189 | 0 | _atp->t = *_tm; |
190 | |
|
191 | | #if 0 |
192 | | _atp->mweek = ac_get_mweek(_tm); |
193 | | #endif |
194 | 0 | _atp->yweek = ac_get_yweek(_tm); |
195 | 0 | _atp->ywday = ac_get_wday_yr(_tm); |
196 | 0 | _atp->wom = ac_get_wday_mr(_tm); |
197 | 0 | } |
198 | | |
199 | | |
200 | 0 | #define TZ_INTACT ((char *)-1) |
201 | | static char *old_tz = TZ_INTACT; |
202 | | |
203 | | void tz_set(const str *tz) |
204 | 0 | { |
205 | 0 | #define TZBUF_SZ 50 |
206 | 0 | char tzbuf[TZBUF_SZ]; |
207 | |
|
208 | 0 | if (tz->len >= TZBUF_SZ) |
209 | 0 | return; |
210 | | |
211 | 0 | memcpy(tzbuf, tz->s, tz->len); |
212 | 0 | tzbuf[tz->len] = '\0'; |
213 | |
|
214 | 0 | _tz_set(tzbuf); |
215 | 0 | #undef TZBUF_SZ |
216 | 0 | } |
217 | | |
218 | | |
219 | | void _tz_set(const char *tz) |
220 | 0 | { |
221 | 0 | LM_DBG("setting timezone to: '%s'\n", tz); |
222 | |
|
223 | 0 | old_tz = getenv("TZ"); |
224 | |
|
225 | 0 | setenv("TZ", tz, 1); |
226 | 0 | tzset(); |
227 | 0 | } |
228 | | |
229 | | |
230 | | void tz_reset(void) |
231 | 0 | { |
232 | 0 | if (old_tz == TZ_INTACT) |
233 | 0 | return; |
234 | | |
235 | 0 | if (!old_tz) { |
236 | 0 | LM_DBG("resetting timezone to system default\n"); |
237 | 0 | unsetenv("TZ"); |
238 | 0 | } else { |
239 | 0 | LM_DBG("resetting timezone to '%s'\n", old_tz); |
240 | 0 | setenv("TZ", old_tz, 1); |
241 | 0 | } |
242 | |
|
243 | 0 | tzset(); |
244 | 0 | old_tz = TZ_INTACT; |
245 | 0 | } |
246 | | |
247 | | |
248 | | time_t tz_adjust_ts(time_t unix_time, const str *tz) |
249 | 0 | { |
250 | 0 | struct tm local_tm; |
251 | 0 | time_t adj_ts; |
252 | |
|
253 | 0 | tz_set(_str("UTC")); |
254 | 0 | localtime_r(&unix_time, &local_tm ); |
255 | 0 | tz_reset(); |
256 | |
|
257 | 0 | if (tz) |
258 | 0 | tz_set(tz); |
259 | |
|
260 | 0 | adj_ts = mktime(&local_tm); |
261 | 0 | tz_reset(); |
262 | |
|
263 | 0 | if (local_tm.tm_isdst > 0) |
264 | 0 | adj_ts -= 3600; |
265 | |
|
266 | 0 | LM_DBG("UNIX ts: %ld, local-adjusted ts: %ld (tz: '%.*s', DST: %s)\n", |
267 | 0 | (long int)unix_time, (long int)adj_ts, tz ? tz->len : 4, |
268 | 0 | tz ? tz->s : "null", local_tm.tm_isdst == 1 ? "on" : |
269 | 0 | local_tm.tm_isdst == 0 ? "off" : "unavail"); |
270 | |
|
271 | 0 | return adj_ts; |
272 | 0 | } |
273 | | |
274 | | |
275 | | static inline void ac_tm_set_time(ac_tm_p _atp, time_t _t) |
276 | 0 | { |
277 | 0 | struct tm ltime; |
278 | |
|
279 | 0 | memset(_atp, 0, sizeof *_atp); |
280 | 0 | _atp->time = _t; |
281 | |
|
282 | 0 | localtime_r(&_t, <ime); |
283 | 0 | ac_tm_fill(_atp, <ime); |
284 | 0 | } |
285 | | |
286 | | int ac_get_mweek(struct tm* _tm) |
287 | 0 | { |
288 | 0 | if(!_tm) |
289 | 0 | return -1; |
290 | | #ifdef USE_YWEEK_U |
291 | | return ((_tm->tm_mday-1)/7 + (7-_tm->tm_wday+(_tm->tm_mday-1)%7)/7); |
292 | | #else |
293 | 0 | return ((_tm->tm_mday-1)/7 + (7-(6+_tm->tm_wday)%7+(_tm->tm_mday-1)%7)/7); |
294 | 0 | #endif |
295 | 0 | } |
296 | | |
297 | | |
298 | | int ac_get_yweek(struct tm* _tm) |
299 | 0 | { |
300 | 0 | int week = -1; |
301 | | #ifdef USE_YWEEK_V |
302 | | int days; |
303 | | #endif |
304 | |
|
305 | 0 | if(!_tm) |
306 | 0 | return -1; |
307 | | |
308 | | #ifdef USE_YWEEK_U |
309 | | week = SUN_WEEK(_tm); |
310 | | #else |
311 | 0 | week = MON_WEEK(_tm); |
312 | 0 | #endif |
313 | |
|
314 | | #ifdef USE_YWEEK_V |
315 | | days = ((_tm->tm_yday + 7 - (_tm->tm_wday ? _tm->tm_wday-1 : 6)) % 7); |
316 | | |
317 | | if(days >= 4) |
318 | | week++; |
319 | | else |
320 | | if(week == 0) |
321 | | week = 53; |
322 | | #endif |
323 | 0 | return week; |
324 | 0 | } |
325 | | |
326 | | int ac_get_wkst(void) |
327 | 0 | { |
328 | | #ifdef USE_YWEEK_U |
329 | | return 0; |
330 | | #else |
331 | 0 | return 1; |
332 | 0 | #endif |
333 | 0 | } |
334 | | |
335 | | int ac_tm_reset(ac_tm_p _atp) |
336 | 0 | { |
337 | 0 | if(!_atp) |
338 | 0 | return -1; |
339 | 0 | memset(_atp, 0, sizeof(ac_tm_t)); |
340 | 0 | return 0; |
341 | 0 | } |
342 | | |
343 | | static ac_maxval_p ac_get_maxval(ac_tm_p _atp) |
344 | 0 | { |
345 | 0 | static ac_maxval_t _amp; |
346 | 0 | struct tm _tm; |
347 | 0 | int _v; |
348 | | |
349 | | /* the number of the days in the year */ |
350 | 0 | _amp.yday = 365 + is_leap_year(_atp->t.tm_year+1900); |
351 | | |
352 | | /* the number of the days in the month */ |
353 | 0 | switch(_atp->t.tm_mon) |
354 | 0 | { |
355 | 0 | case 1: |
356 | 0 | if(_amp.yday == 366) |
357 | 0 | _amp.mday = 29; |
358 | 0 | else |
359 | 0 | _amp.mday = 28; |
360 | 0 | break; |
361 | 0 | case 3: case 5: case 8: case 10: |
362 | 0 | _amp.mday = 30; |
363 | 0 | break; |
364 | 0 | default: |
365 | 0 | _amp.mday = 31; |
366 | 0 | } |
367 | | |
368 | | /* maximum occurrences of a week day in the year */ |
369 | 0 | memset(&_tm, 0, sizeof(struct tm)); |
370 | 0 | _tm.tm_year = _atp->t.tm_year; |
371 | 0 | _tm.tm_mon = 11; |
372 | 0 | _tm.tm_mday = 31; |
373 | 0 | mktime(&_tm); |
374 | 0 | _v = 0; |
375 | 0 | if(_atp->t.tm_wday > _tm.tm_wday) |
376 | 0 | _v = _atp->t.tm_wday - _tm.tm_wday + 1; |
377 | 0 | else |
378 | 0 | _v = _tm.tm_wday - _atp->t.tm_wday; |
379 | 0 | _amp.ywday = (int)((_tm.tm_yday-_v)/7) + 1; |
380 | | |
381 | | /* maximum number of weeks in the year */ |
382 | 0 | _amp.yweek = ac_get_yweek(&_tm) + 1; |
383 | | |
384 | | /* maximum number of the week day in the month */ |
385 | 0 | _amp.mwday=(int)((_amp.mday-1-(_amp.mday-_atp->t.tm_mday)%7)/7)+1; |
386 | |
|
387 | | #if 0 |
388 | | /* maximum number of weeks in the month */ |
389 | | _v = (_atp->t.tm_wday + (_amp.mday - _atp->t.tm_mday)%7)%7; |
390 | | #ifdef USE_YWEEK_U |
391 | | _amp.mweek = (int)((_amp.mday-1)/7+(7-_v+(_amp.mday-1)%7)/7)+1; |
392 | | #else |
393 | | _amp.mweek = (int)((_amp.mday-1)/7+(7-(6+_v)%7+(_amp.mday-1)%7)/7)+1; |
394 | | #endif |
395 | | #endif |
396 | |
|
397 | 0 | return &_amp; |
398 | 0 | } |
399 | | |
400 | | |
401 | | int ac_print(ac_tm_p _atp) |
402 | 0 | { |
403 | 0 | static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; |
404 | 0 | if(!_atp) |
405 | 0 | { |
406 | 0 | printf("\n(null)\n"); |
407 | 0 | return -1; |
408 | 0 | } |
409 | | |
410 | 0 | printf("\nSys time: %d\nTime: %02d:%02d:%02d\n", (int)_atp->time, |
411 | 0 | _atp->t.tm_hour, _atp->t.tm_min, _atp->t.tm_sec); |
412 | 0 | printf("Date: %s, %04d-%02d-%02d\n", _wdays[_atp->t.tm_wday], |
413 | 0 | _atp->t.tm_year+1900, _atp->t.tm_mon+1, _atp->t.tm_mday); |
414 | 0 | printf("Year day: %d\nYear week-day: %d\nYear week: %d\n", _atp->t.tm_yday, |
415 | 0 | _atp->ywday, _atp->yweek); |
416 | 0 | printf("Month week: %d\nMonth week-day: %d\n", _atp->mweek, _atp->wom); |
417 | 0 | return 0; |
418 | 0 | } |
419 | | |
420 | | |
421 | | |
422 | | |
423 | | |
424 | | |
425 | | tr_byxxx_p tr_byxxx_new(char alloc) |
426 | 0 | { |
427 | 0 | tr_byxxx_p _bxp = NULL; |
428 | 0 | if (alloc & PKG_ALLOC) |
429 | 0 | _bxp = (tr_byxxx_p)pkg_malloc(sizeof(tr_byxxx_t)); |
430 | 0 | else |
431 | 0 | _bxp = (tr_byxxx_p)shm_malloc(sizeof(tr_byxxx_t)); |
432 | 0 | if(!_bxp) |
433 | 0 | return NULL; |
434 | 0 | memset(_bxp, 0, sizeof(tr_byxxx_t)); |
435 | 0 | _bxp->flags = alloc; |
436 | 0 | return _bxp; |
437 | 0 | } |
438 | | |
439 | | int tr_byxxx_init(tr_byxxx_p _bxp, int _nr) |
440 | 0 | { |
441 | 0 | _bxp->nr = _nr; |
442 | 0 | if (_bxp->flags & PKG_ALLOC) { |
443 | 0 | _bxp->xxx = (int*)pkg_malloc(_nr*sizeof(int)); |
444 | 0 | _bxp->req = (int*)pkg_malloc(_nr*sizeof(int)); |
445 | 0 | } else { |
446 | 0 | _bxp->xxx = (int*)shm_malloc(_nr*sizeof(int)); |
447 | 0 | _bxp->req = (int*)shm_malloc(_nr*sizeof(int)); |
448 | 0 | } |
449 | |
|
450 | 0 | if (!_bxp->xxx || !_bxp->req) |
451 | 0 | goto oom; |
452 | | |
453 | 0 | memset(_bxp->xxx, 0, _nr*sizeof(int)); |
454 | 0 | memset(_bxp->req, 0, _nr*sizeof(int)); |
455 | |
|
456 | 0 | return 0; |
457 | 0 | oom: |
458 | 0 | LM_ERR("oom\n"); |
459 | 0 | if (_bxp->flags & PKG_ALLOC) { |
460 | 0 | pkg_free(_bxp->xxx); |
461 | 0 | pkg_free(_bxp->req); |
462 | 0 | } else { |
463 | 0 | shm_free(_bxp->xxx); |
464 | 0 | shm_free(_bxp->req); |
465 | 0 | } |
466 | 0 | _bxp->xxx = NULL; |
467 | 0 | _bxp->req = NULL; |
468 | 0 | return -1; |
469 | 0 | } |
470 | | |
471 | | |
472 | | int tr_byxxx_free(tr_byxxx_p _bxp) |
473 | 0 | { |
474 | 0 | if (!_bxp) |
475 | 0 | return -1; |
476 | | |
477 | 0 | if (_bxp->flags & PKG_ALLOC) { |
478 | 0 | pkg_free(_bxp->xxx); |
479 | 0 | pkg_free(_bxp->req); |
480 | 0 | pkg_free(_bxp); |
481 | 0 | } else { |
482 | 0 | shm_free(_bxp->xxx); |
483 | 0 | shm_free(_bxp->req); |
484 | 0 | shm_free(_bxp); |
485 | 0 | } |
486 | |
|
487 | 0 | return 0; |
488 | 0 | } |
489 | | |
490 | | void tmrec_init(tmrec_p t) |
491 | 0 | { |
492 | 0 | memset(t, 0, sizeof *t); |
493 | | |
494 | | /* these values may be legitimately set to 0 (i.e. UNIX start time) */ |
495 | 0 | t->dtstart = TR_NOVAL; |
496 | 0 | t->dtend = TR_NOVAL; |
497 | 0 | t->duration = TR_NOVAL; |
498 | |
|
499 | 0 | t->freq = TR_NOVAL; |
500 | 0 | t->until = TR_NOVAL; |
501 | 0 | t->interval = TR_NOVAL; |
502 | 0 | } |
503 | | |
504 | | static inline void tmrec_expr_init(tmrec_expr_t *e) |
505 | 0 | { |
506 | 0 | memset(e, 0, sizeof *e); |
507 | 0 | INIT_LIST_HEAD(&e->operands); |
508 | 0 | tmrec_init(&e->tr); |
509 | 0 | } |
510 | | |
511 | | static void tmrec_free_members(tmrec_p, char); |
512 | | |
513 | | tmrec_p tmrec_new(char alloc) |
514 | 0 | { |
515 | 0 | tmrec_p _trp; |
516 | 0 | if (alloc & PKG_ALLOC) |
517 | 0 | _trp = (tmrec_p)pkg_malloc(sizeof(tmrec_t)); |
518 | 0 | else |
519 | 0 | _trp = (tmrec_p)shm_malloc(sizeof(tmrec_t)); |
520 | 0 | if(!_trp) |
521 | 0 | return NULL; |
522 | | |
523 | 0 | tmrec_init(_trp); |
524 | 0 | _trp->flags = alloc; |
525 | 0 | return _trp; |
526 | 0 | } |
527 | | |
528 | | void tmrec_free(tmrec *tr) |
529 | 0 | { |
530 | 0 | tmrec_p _trp = (tmrec_p)tr; |
531 | |
|
532 | 0 | if(!_trp) |
533 | 0 | return; |
534 | | |
535 | 0 | tmrec_free_members(_trp, _trp->flags); |
536 | |
|
537 | 0 | if (_trp->flags & PKG_ALLOC) { |
538 | 0 | pkg_free(_trp); |
539 | 0 | } else { |
540 | 0 | shm_free(_trp); |
541 | 0 | } |
542 | 0 | } |
543 | | |
544 | | static void tmrec_free_members(tmrec_p _trp, char alloc) |
545 | 0 | { |
546 | 0 | if (!_trp) |
547 | 0 | return; |
548 | | |
549 | 0 | tr_byxxx_free(_trp->byday); |
550 | 0 | tr_byxxx_free(_trp->bymday); |
551 | 0 | tr_byxxx_free(_trp->byyday); |
552 | 0 | tr_byxxx_free(_trp->bymonth); |
553 | 0 | tr_byxxx_free(_trp->byweekno); |
554 | |
|
555 | 0 | if (alloc & PKG_ALLOC) |
556 | 0 | pkg_free(_trp->tz); |
557 | 0 | else |
558 | 0 | shm_free(_trp->tz); |
559 | |
|
560 | 0 | _trp->byday = NULL; |
561 | 0 | _trp->bymday = NULL; |
562 | 0 | _trp->byyday = NULL; |
563 | 0 | _trp->bymonth = NULL; |
564 | 0 | _trp->byweekno = NULL; |
565 | 0 | _trp->tz = NULL; |
566 | 0 | } |
567 | | |
568 | | int tr_parse_tz(tmrec_p _trp, char *_in) |
569 | 0 | { |
570 | 0 | if (!_trp || !_in) |
571 | 0 | return -1; |
572 | | |
573 | 0 | if (*_in < 'A' || *_in > 'Z') |
574 | 0 | return 1; |
575 | | |
576 | 0 | if (_trp->flags & PKG_ALLOC) |
577 | 0 | _trp->tz = pkg_strdup(_in); |
578 | 0 | else |
579 | 0 | _trp->tz = shm_strdup(_in); |
580 | |
|
581 | 0 | if (!_trp->tz) { |
582 | 0 | LM_ERR("oom\n"); |
583 | 0 | return -1; |
584 | 0 | } |
585 | | |
586 | 0 | return 0; |
587 | 0 | } |
588 | | |
589 | | int tr_parse_dtstart(tmrec_p _trp, char *_in) |
590 | 0 | { |
591 | 0 | if (!_in) |
592 | 0 | return -1; |
593 | 0 | _trp->dtstart = ic_parse_datetime(_in, &(_trp->ts)); |
594 | 0 | return (_trp->dtstart == TR_NOVAL) ? -1 : 0; |
595 | 0 | } |
596 | | |
597 | | int tr_parse_dtend(tmrec_p _trp, char *_in) |
598 | 0 | { |
599 | 0 | struct tm _tm; |
600 | 0 | if (!_in) |
601 | 0 | return -1; |
602 | 0 | _trp->dtend = ic_parse_datetime(_in,&_tm); |
603 | 0 | return (_trp->dtend == TR_NOVAL) ? -1 : 0; |
604 | 0 | } |
605 | | |
606 | | int tr_parse_duration(tmrec_p _trp, char *_in) |
607 | 0 | { |
608 | 0 | if (!_in) |
609 | 0 | return -1; |
610 | 0 | _trp->duration = ic_parse_duration(_in); |
611 | 0 | return (_trp->duration == TR_NOVAL) ? -1 : 0; |
612 | 0 | } |
613 | | |
614 | | int tr_parse_until(tmrec_p _trp, char *_in) |
615 | 0 | { |
616 | 0 | struct tm _tm; |
617 | 0 | if (!_in) |
618 | 0 | return -1; |
619 | 0 | _trp->until = ic_parse_datetime(_in, &_tm); |
620 | 0 | return (_trp->until == TR_NOVAL) ? -1 : 0; |
621 | 0 | } |
622 | | |
623 | | int tr_parse_freq(tmrec_p _trp, char *_in) |
624 | 0 | { |
625 | 0 | if (!_in) |
626 | 0 | return -1; |
627 | | |
628 | 0 | if(strlen(_in)<5) |
629 | 0 | { |
630 | 0 | _trp->freq = FREQ_NOFREQ; |
631 | 0 | return 0; |
632 | 0 | } |
633 | 0 | if(!strcasecmp(_in, "daily")) |
634 | 0 | { |
635 | 0 | _trp->freq = FREQ_DAILY; |
636 | 0 | return 0; |
637 | 0 | } |
638 | 0 | if(!strcasecmp(_in, "weekly")) |
639 | 0 | { |
640 | 0 | _trp->freq = FREQ_WEEKLY; |
641 | 0 | return 0; |
642 | 0 | } |
643 | 0 | if(!strcasecmp(_in, "monthly")) |
644 | 0 | { |
645 | 0 | _trp->freq = FREQ_MONTHLY; |
646 | 0 | return 0; |
647 | 0 | } |
648 | 0 | if(!strcasecmp(_in, "yearly")) |
649 | 0 | { |
650 | 0 | _trp->freq = FREQ_YEARLY; |
651 | 0 | return 0; |
652 | 0 | } |
653 | | |
654 | 0 | _trp->freq = FREQ_NOFREQ; |
655 | 0 | return 0; |
656 | 0 | } |
657 | | |
658 | | int tr_parse_interval(tmrec_p _trp, char *_in) |
659 | 0 | { |
660 | 0 | if (!_in) |
661 | 0 | return -1; |
662 | 0 | _trp->interval = strz2int(_in); |
663 | 0 | return 0; |
664 | 0 | } |
665 | | |
666 | | int tr_parse_byday(tmrec_p _trp, char *_in) |
667 | 0 | { |
668 | 0 | tr_byxxx_p byday; |
669 | |
|
670 | 0 | if (!_in) |
671 | 0 | return -1; |
672 | | |
673 | 0 | byday = ic_parse_byday(_in, _trp->flags); |
674 | 0 | if (!byday) |
675 | 0 | return -1; |
676 | 0 | tr_byxxx_free(_trp->byday); |
677 | 0 | _trp->byday = byday; |
678 | 0 | _trp->flags |= TR_BYXXX; |
679 | 0 | return 0; |
680 | 0 | } |
681 | | |
682 | | int tr_parse_bymday(tmrec_p _trp, char *_in) |
683 | 0 | { |
684 | 0 | tr_byxxx_p bymday; |
685 | |
|
686 | 0 | if (!_in) |
687 | 0 | return -1; |
688 | | |
689 | 0 | bymday = ic_parse_byxxx(_in, _trp->flags); |
690 | 0 | if (!bymday) |
691 | 0 | return -1; |
692 | 0 | tr_byxxx_free(_trp->bymday); |
693 | 0 | _trp->bymday = bymday; |
694 | 0 | _trp->flags |= TR_BYXXX; |
695 | 0 | return 0; |
696 | 0 | } |
697 | | |
698 | | int tr_parse_byyday(tmrec_p _trp, char *_in) |
699 | 0 | { |
700 | 0 | tr_byxxx_p byyday; |
701 | |
|
702 | 0 | if (!_in) |
703 | 0 | return -1; |
704 | | |
705 | 0 | byyday = ic_parse_byxxx(_in, _trp->flags); |
706 | 0 | if (!byyday) |
707 | 0 | return -1; |
708 | 0 | tr_byxxx_free(_trp->byyday); |
709 | 0 | _trp->byyday = byyday; |
710 | 0 | _trp->flags |= TR_BYXXX; |
711 | 0 | return 0; |
712 | 0 | } |
713 | | |
714 | | int tr_parse_bymonth(tmrec_p _trp, char *_in) |
715 | 0 | { |
716 | 0 | tr_byxxx_p bymonth; |
717 | |
|
718 | 0 | if (!_in) |
719 | 0 | return -1; |
720 | | |
721 | 0 | bymonth = ic_parse_byxxx(_in, _trp->flags); |
722 | 0 | if (!bymonth) |
723 | 0 | return -1; |
724 | 0 | tr_byxxx_free(_trp->bymonth); |
725 | 0 | _trp->bymonth = bymonth; |
726 | 0 | _trp->flags |= TR_BYXXX; |
727 | 0 | return 0; |
728 | 0 | } |
729 | | |
730 | | int tr_parse_byweekno(tmrec_p _trp, char *_in) |
731 | 0 | { |
732 | 0 | tr_byxxx_p byweekno; |
733 | |
|
734 | 0 | if (!_in) |
735 | 0 | return -1; |
736 | | |
737 | 0 | byweekno = ic_parse_byxxx(_in, _trp->flags); |
738 | 0 | if (!byweekno) |
739 | 0 | return -1; |
740 | 0 | tr_byxxx_free(_trp->byweekno); |
741 | 0 | _trp->byweekno = byweekno; |
742 | 0 | _trp->flags |= TR_BYXXX; |
743 | 0 | return 0; |
744 | 0 | } |
745 | | |
746 | | int tr_parse_wkst(tmrec_p _trp, char *_in) |
747 | 0 | { |
748 | 0 | if (!_in) |
749 | 0 | return -1; |
750 | | |
751 | 0 | _trp->wkst = ic_parse_wkst(_in); |
752 | 0 | return 0; |
753 | 0 | } |
754 | | |
755 | | int tmrec_print(const tmrec *tr) |
756 | 0 | { |
757 | 0 | static char *_wdays[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"}; |
758 | 0 | tmrec_p _trp = (tmrec_p)tr; |
759 | 0 | int i; |
760 | |
|
761 | 0 | if(!_trp) |
762 | 0 | { |
763 | 0 | printf("\n(null)\n"); |
764 | 0 | return -1; |
765 | 0 | } |
766 | 0 | printf("Recurrence definition\n-- start time ---\n"); |
767 | 0 | printf("Sys time: %d\n", (int)_trp->dtstart); |
768 | 0 | printf("Time: %02d:%02d:%02d\n", _trp->ts.tm_hour, |
769 | 0 | _trp->ts.tm_min, _trp->ts.tm_sec); |
770 | 0 | printf("Date: %s, %04d-%02d-%02d\n", _wdays[_trp->ts.tm_wday], |
771 | 0 | _trp->ts.tm_year+1900, _trp->ts.tm_mon+1, _trp->ts.tm_mday); |
772 | 0 | printf("---\n"); |
773 | 0 | printf("End time: %d\n", (int)_trp->dtend); |
774 | 0 | printf("Duration: %d\n", (int)_trp->duration); |
775 | 0 | printf("Until: %d\n", (int)_trp->until); |
776 | 0 | printf("Freq: %d\n", (int)_trp->freq); |
777 | 0 | printf("Interval: %d\n", (int)_trp->interval); |
778 | 0 | if(_trp->byday) |
779 | 0 | { |
780 | 0 | printf("Byday: "); |
781 | 0 | for(i=0; i<_trp->byday->nr; i++) |
782 | 0 | printf(" %d%s", _trp->byday->req[i], _wdays[_trp->byday->xxx[i]]); |
783 | 0 | printf("\n"); |
784 | 0 | } |
785 | 0 | if(_trp->bymday) |
786 | 0 | { |
787 | 0 | printf("Bymday: %d:", _trp->bymday->nr); |
788 | 0 | for(i=0; i<_trp->bymday->nr; i++) |
789 | 0 | printf(" %d", _trp->bymday->xxx[i]*_trp->bymday->req[i]); |
790 | 0 | printf("\n"); |
791 | 0 | } |
792 | 0 | if(_trp->byyday) |
793 | 0 | { |
794 | 0 | printf("Byyday:"); |
795 | 0 | for(i=0; i<_trp->byyday->nr; i++) |
796 | 0 | printf(" %d", _trp->byyday->xxx[i]*_trp->byyday->req[i]); |
797 | 0 | printf("\n"); |
798 | 0 | } |
799 | 0 | if(_trp->bymonth) |
800 | 0 | { |
801 | 0 | printf("Bymonth: %d:", _trp->bymonth->nr); |
802 | 0 | for(i=0; i< _trp->bymonth->nr; i++) |
803 | 0 | printf(" %d", _trp->bymonth->xxx[i]*_trp->bymonth->req[i]); |
804 | 0 | printf("\n"); |
805 | 0 | } |
806 | 0 | if(_trp->byweekno) |
807 | 0 | { |
808 | 0 | printf("Byweekno: "); |
809 | 0 | for(i=0; i<_trp->byweekno->nr; i++) |
810 | 0 | printf(" %d", _trp->byweekno->xxx[i]*_trp->byweekno->req[i]); |
811 | 0 | printf("\n"); |
812 | 0 | } |
813 | 0 | printf("Weekstart: %d\n", _trp->wkst); |
814 | 0 | return 0; |
815 | 0 | } |
816 | | |
817 | | time_t ic_parse_datetime(char *_in, struct tm *_tm) |
818 | 0 | { |
819 | 0 | struct tm t; |
820 | |
|
821 | 0 | if (!_in || strlen(_in)!=15) |
822 | 0 | return TR_NOVAL; |
823 | | |
824 | 0 | t.tm_year = _D(_in[0])*1000 + _D(_in[1])*100 |
825 | 0 | + _D(_in[2])*10 + _D(_in[3]); |
826 | 0 | if (t.tm_year < 1970) { |
827 | 0 | LM_ERR("invalid year in Date-Time: '%s'\n", _in); |
828 | 0 | return TR_NOVAL; |
829 | 0 | } |
830 | | |
831 | 0 | t.tm_year -= 1900; /* per man ctime(3) */ |
832 | 0 | t.tm_mon = _D(_in[4])*10 + _D(_in[5]) - 1; |
833 | 0 | t.tm_mday = _D(_in[6])*10 + _D(_in[7]); |
834 | 0 | if (t.tm_mon == -1 || t.tm_mday == 0) { |
835 | 0 | LM_ERR("month or month day cannot be zero in Date-Time: '%s'\n", _in); |
836 | 0 | return TR_NOVAL; |
837 | 0 | } |
838 | | |
839 | 0 | t.tm_hour = _D(_in[9])*10 + _D(_in[10]); |
840 | 0 | t.tm_min = _D(_in[11])*10 + _D(_in[12]); |
841 | 0 | t.tm_sec = _D(_in[13])*10 + _D(_in[14]); |
842 | 0 | t.tm_isdst = -1 /*daylight*/; |
843 | |
|
844 | 0 | *_tm = t; |
845 | 0 | return mktime(_tm); |
846 | 0 | } |
847 | | |
848 | | time_t ic_parse_duration(char *_in) |
849 | 0 | { |
850 | 0 | time_t _t, _ft; |
851 | 0 | char *_p; |
852 | 0 | int _fl; |
853 | |
|
854 | 0 | if(!_in || strlen(_in)<2) |
855 | 0 | return TR_NOVAL; |
856 | | |
857 | 0 | if(*_in == 'P' || *_in=='p') |
858 | 0 | { |
859 | 0 | _p = _in+1; |
860 | 0 | _fl = 1; |
861 | 0 | } else { |
862 | 0 | _p = _in; |
863 | 0 | _fl = 0; |
864 | 0 | } |
865 | |
|
866 | 0 | _t = _ft = 0; |
867 | |
|
868 | 0 | while(*_p) |
869 | 0 | { |
870 | 0 | switch(*_p) |
871 | 0 | { |
872 | 0 | case '0': case '1': case '2': |
873 | 0 | case '3': case '4': case '5': |
874 | 0 | case '6': case '7': case '8': |
875 | 0 | case '9': |
876 | 0 | _t = _t*10 + *_p - '0'; |
877 | 0 | break; |
878 | | |
879 | 0 | case 'w': |
880 | 0 | case 'W': |
881 | 0 | if(!_fl) |
882 | 0 | { |
883 | 0 | LM_ERR("week duration not allowed" |
884 | 0 | " here (%d) [%s]\n", (int)(_p-_in), _in); |
885 | 0 | return 0; |
886 | 0 | } |
887 | 0 | _ft += _t*7*24*3600; |
888 | 0 | _t = 0; |
889 | 0 | break; |
890 | 0 | case 'd': |
891 | 0 | case 'D': |
892 | 0 | if(!_fl) |
893 | 0 | { |
894 | 0 | LM_ERR("day duration not allowed" |
895 | 0 | " here (%d) [%s]\n", (int)(_p-_in), _in); |
896 | 0 | return 0; |
897 | 0 | } |
898 | 0 | _ft += _t*24*3600; |
899 | 0 | _t = 0; |
900 | 0 | break; |
901 | 0 | case 'h': |
902 | 0 | case 'H': |
903 | 0 | if(_fl) |
904 | 0 | { |
905 | 0 | LM_ERR("hour duration not allowed" |
906 | 0 | " here (%d) [%s]\n", (int)(_p-_in), _in); |
907 | 0 | return 0; |
908 | 0 | } |
909 | 0 | _ft += _t*3600; |
910 | 0 | _t = 0; |
911 | 0 | break; |
912 | 0 | case 'm': |
913 | 0 | case 'M': |
914 | 0 | if(_fl) |
915 | 0 | { |
916 | 0 | LM_ERR("minute duration not allowed" |
917 | 0 | " here (%d) [%s]\n", (int)(_p-_in), _in); |
918 | 0 | return 0; |
919 | 0 | } |
920 | 0 | _ft += _t*60; |
921 | 0 | _t = 0; |
922 | 0 | break; |
923 | 0 | case 's': |
924 | 0 | case 'S': |
925 | 0 | if(_fl) |
926 | 0 | { |
927 | 0 | LM_ERR("second duration not allowed" |
928 | 0 | " here (%d) [%s]\n", (int)(_p-_in), _in); |
929 | 0 | return 0; |
930 | 0 | } |
931 | 0 | _ft += _t; |
932 | 0 | _t = 0; |
933 | 0 | break; |
934 | 0 | case 't': |
935 | 0 | case 'T': |
936 | 0 | if(!_fl) |
937 | 0 | { |
938 | 0 | LM_ERR("'T' not allowed" |
939 | 0 | " here (%d) [%s]\n", (int)(_p-_in), _in); |
940 | 0 | return 0; |
941 | 0 | } |
942 | 0 | _fl = 0; |
943 | 0 | break; |
944 | 0 | default: |
945 | 0 | LM_ERR("bad character here (%d) [%s]\n", |
946 | 0 | (int)(_p-_in), _in); |
947 | 0 | return 0; |
948 | 0 | } |
949 | 0 | _p++; |
950 | 0 | } |
951 | | |
952 | 0 | return _ft; |
953 | 0 | } |
954 | | |
955 | | tr_byxxx_p ic_parse_byday(char *_in, char type) |
956 | 0 | { |
957 | 0 | tr_byxxx_p _bxp = NULL; |
958 | 0 | int _nr, _s, _v; |
959 | 0 | char *_p; |
960 | |
|
961 | 0 | if(!_in) |
962 | 0 | return NULL; |
963 | 0 | _bxp = tr_byxxx_new(type); |
964 | 0 | if(!_bxp) |
965 | 0 | return NULL; |
966 | 0 | _p = _in; |
967 | 0 | _nr = 1; |
968 | 0 | while(*_p) |
969 | 0 | { |
970 | 0 | if(*_p == ',') |
971 | 0 | _nr++; |
972 | 0 | _p++; |
973 | 0 | } |
974 | 0 | if(tr_byxxx_init(_bxp, _nr) < 0) |
975 | 0 | { |
976 | 0 | tr_byxxx_free(_bxp); |
977 | 0 | return NULL; |
978 | 0 | } |
979 | 0 | _p = _in; |
980 | 0 | _nr = _v = 0; |
981 | 0 | _s = 1; |
982 | 0 | while(*_p && _nr < _bxp->nr) |
983 | 0 | { |
984 | 0 | switch(*_p) |
985 | 0 | { |
986 | 0 | case '0': case '1': case '2': |
987 | 0 | case '3': case '4': case '5': |
988 | 0 | case '6': case '7': case '8': |
989 | 0 | case '9': |
990 | 0 | _v = _v*10 + *_p - '0'; |
991 | 0 | break; |
992 | | |
993 | 0 | case 's': |
994 | 0 | case 'S': |
995 | 0 | _p++; |
996 | 0 | switch(*_p) |
997 | 0 | { |
998 | 0 | case 'a': |
999 | 0 | case 'A': |
1000 | 0 | _bxp->xxx[_nr] = WDAY_SA; |
1001 | 0 | break; |
1002 | 0 | case 'u': |
1003 | 0 | case 'U': |
1004 | 0 | _bxp->xxx[_nr] = WDAY_SU; |
1005 | 0 | break; |
1006 | 0 | default: |
1007 | 0 | goto error; |
1008 | 0 | } |
1009 | | |
1010 | 0 | _bxp->req[_nr] = _s * _v; |
1011 | 0 | if (_bxp->req[_nr] > 0) |
1012 | 0 | _bxp->req[_nr]--; |
1013 | 0 | _s = 1; |
1014 | 0 | _v = 0; |
1015 | 0 | break; |
1016 | 0 | case 'm': |
1017 | 0 | case 'M': |
1018 | 0 | _p++; |
1019 | 0 | if(*_p!='o' && *_p!='O') |
1020 | 0 | goto error; |
1021 | 0 | _bxp->xxx[_nr] = WDAY_MO; |
1022 | |
|
1023 | 0 | _bxp->req[_nr] = _s * _v; |
1024 | 0 | if (_bxp->req[_nr] > 0) |
1025 | 0 | _bxp->req[_nr]--; |
1026 | 0 | _s = 1; |
1027 | 0 | _v = 0; |
1028 | 0 | break; |
1029 | 0 | case 't': |
1030 | 0 | case 'T': |
1031 | 0 | _p++; |
1032 | 0 | switch(*_p) |
1033 | 0 | { |
1034 | 0 | case 'h': |
1035 | 0 | case 'H': |
1036 | 0 | _bxp->xxx[_nr] = WDAY_TH; |
1037 | 0 | break; |
1038 | 0 | case 'u': |
1039 | 0 | case 'U': |
1040 | 0 | _bxp->xxx[_nr] = WDAY_TU; |
1041 | 0 | break; |
1042 | 0 | default: |
1043 | 0 | goto error; |
1044 | 0 | } |
1045 | | |
1046 | 0 | _bxp->req[_nr] = _s * _v; |
1047 | 0 | if (_bxp->req[_nr] > 0) |
1048 | 0 | _bxp->req[_nr]--; |
1049 | 0 | _s = 1; |
1050 | 0 | _v = 0; |
1051 | 0 | break; |
1052 | 0 | case 'w': |
1053 | 0 | case 'W': |
1054 | 0 | _p++; |
1055 | 0 | if(*_p!='e' && *_p!='E') |
1056 | 0 | goto error; |
1057 | 0 | _bxp->xxx[_nr] = WDAY_WE; |
1058 | 0 | _s = 1; |
1059 | 0 | _v = 0; |
1060 | |
|
1061 | 0 | _bxp->req[_nr] = _s * _v; |
1062 | 0 | if (_bxp->req[_nr] > 0) |
1063 | 0 | _bxp->req[_nr]--; |
1064 | 0 | break; |
1065 | 0 | case 'f': |
1066 | 0 | case 'F': |
1067 | 0 | _p++; |
1068 | 0 | if(*_p!='r' && *_p!='R') |
1069 | 0 | goto error; |
1070 | 0 | _bxp->xxx[_nr] = WDAY_FR; |
1071 | |
|
1072 | 0 | _bxp->req[_nr] = _s * _v; |
1073 | 0 | if (_bxp->req[_nr] > 0) |
1074 | 0 | _bxp->req[_nr]--; |
1075 | 0 | _s = 1; |
1076 | 0 | _v = 0; |
1077 | 0 | break; |
1078 | 0 | case '-': |
1079 | 0 | _s = -1; |
1080 | 0 | break; |
1081 | 0 | case '+': |
1082 | 0 | case ' ': |
1083 | 0 | case '\t': |
1084 | 0 | break; |
1085 | 0 | case ',': |
1086 | 0 | _nr++; |
1087 | 0 | break; |
1088 | 0 | default: |
1089 | 0 | goto error; |
1090 | 0 | } |
1091 | 0 | _p++; |
1092 | 0 | } |
1093 | | |
1094 | 0 | return _bxp; |
1095 | | |
1096 | 0 | error: |
1097 | 0 | tr_byxxx_free(_bxp); |
1098 | 0 | return NULL; |
1099 | 0 | } |
1100 | | |
1101 | | tr_byxxx_p ic_parse_byxxx(char *_in, char type) |
1102 | 0 | { |
1103 | 0 | tr_byxxx_p _bxp = NULL; |
1104 | 0 | int _nr, _s, _v; |
1105 | 0 | char *_p; |
1106 | |
|
1107 | 0 | if(!_in) |
1108 | 0 | return NULL; |
1109 | 0 | _bxp = tr_byxxx_new(type); |
1110 | 0 | if(!_bxp) |
1111 | 0 | return NULL; |
1112 | 0 | _p = _in; |
1113 | 0 | _nr = 1; |
1114 | 0 | while(*_p) |
1115 | 0 | { |
1116 | 0 | if(*_p == ',') |
1117 | 0 | _nr++; |
1118 | 0 | _p++; |
1119 | 0 | } |
1120 | 0 | if(tr_byxxx_init(_bxp, _nr) < 0) |
1121 | 0 | { |
1122 | 0 | tr_byxxx_free(_bxp); |
1123 | 0 | return NULL; |
1124 | 0 | } |
1125 | | |
1126 | 0 | _nr = _v = 0; |
1127 | 0 | _s = 1; |
1128 | |
|
1129 | 0 | for (_p = _in; *_p; _p++) { |
1130 | 0 | switch (*_p) { |
1131 | 0 | case '0': case '1': case '2': |
1132 | 0 | case '3': case '4': case '5': |
1133 | 0 | case '6': case '7': case '8': |
1134 | 0 | case '9': |
1135 | 0 | _v = _v*10 + *_p - '0'; |
1136 | 0 | break; |
1137 | | |
1138 | 0 | case '-': |
1139 | 0 | _s = -1; |
1140 | 0 | break; |
1141 | 0 | case '+': |
1142 | 0 | case ' ': |
1143 | 0 | case '\t': |
1144 | 0 | break; |
1145 | | |
1146 | 0 | case ',': |
1147 | 0 | _bxp->xxx[_nr] = _v; |
1148 | 0 | _bxp->req[_nr] = _s; |
1149 | 0 | _s = 1; |
1150 | 0 | _v = 0; |
1151 | 0 | _nr++; |
1152 | 0 | break; |
1153 | | |
1154 | 0 | default: |
1155 | 0 | goto error; |
1156 | 0 | } |
1157 | 0 | } |
1158 | | |
1159 | | /* store the last item of the list */ |
1160 | 0 | _bxp->xxx[_nr] = _v; |
1161 | 0 | _bxp->req[_nr] = _s; |
1162 | |
|
1163 | 0 | return _bxp; |
1164 | | |
1165 | 0 | error: |
1166 | 0 | tr_byxxx_free(_bxp); |
1167 | 0 | return NULL; |
1168 | 0 | } |
1169 | | |
1170 | | int ic_parse_wkst(char *_in) |
1171 | 0 | { |
1172 | 0 | if(!_in || strlen(_in)!=2) |
1173 | 0 | goto error; |
1174 | | |
1175 | 0 | switch(_in[0]) |
1176 | 0 | { |
1177 | 0 | case 's': |
1178 | 0 | case 'S': |
1179 | 0 | switch(_in[1]) |
1180 | 0 | { |
1181 | 0 | case 'a': |
1182 | 0 | case 'A': |
1183 | 0 | return WDAY_SA; |
1184 | 0 | case 'u': |
1185 | 0 | case 'U': |
1186 | 0 | return WDAY_SU; |
1187 | 0 | default: |
1188 | 0 | goto error; |
1189 | 0 | } |
1190 | 0 | case 'm': |
1191 | 0 | case 'M': |
1192 | 0 | if(_in[1]!='o' && _in[1]!='O') |
1193 | 0 | goto error; |
1194 | 0 | return WDAY_MO; |
1195 | 0 | case 't': |
1196 | 0 | case 'T': |
1197 | 0 | switch(_in[1]) |
1198 | 0 | { |
1199 | 0 | case 'h': |
1200 | 0 | case 'H': |
1201 | 0 | return WDAY_TH; |
1202 | 0 | case 'u': |
1203 | 0 | case 'U': |
1204 | 0 | return WDAY_TU; |
1205 | 0 | default: |
1206 | 0 | goto error; |
1207 | 0 | } |
1208 | 0 | case 'w': |
1209 | 0 | case 'W': |
1210 | 0 | if(_in[1]!='e' && _in[1]!='E') |
1211 | 0 | goto error; |
1212 | 0 | return WDAY_WE; |
1213 | 0 | case 'f': |
1214 | 0 | case 'F': |
1215 | 0 | if(_in[1]!='r' && _in[1]!='R') |
1216 | 0 | goto error; |
1217 | 0 | return WDAY_FR; |
1218 | 0 | break; |
1219 | 0 | default: |
1220 | 0 | goto error; |
1221 | 0 | } |
1222 | | |
1223 | 0 | error: |
1224 | | #ifdef USE_YWEEK_U |
1225 | | return WDAY_SU; |
1226 | | #else |
1227 | 0 | return WDAY_MO; |
1228 | 0 | #endif |
1229 | 0 | } |
1230 | | |
1231 | | |
1232 | | |
1233 | | /*** local headers ***/ |
1234 | | int check_min_unit(tmrec_p _trp, ac_tm_p _atp); |
1235 | | int check_freq_interval(tmrec_p _trp, ac_tm_p _atp); |
1236 | | int check_byxxx(tmrec_p, ac_tm_p); |
1237 | | |
1238 | | /** |
1239 | | * |
1240 | | * return 0/REC_MATCH - the time falls in |
1241 | | * -1/REC_ERR - error |
1242 | | * 1/REC_NOMATCH - the time falls out |
1243 | | */ |
1244 | | int check_tmrec(const tmrec_p _trp, ac_tm_p _atp) |
1245 | 0 | { |
1246 | | /* it is before the start date or outside a non-recurring interval? */ |
1247 | 0 | if (_atp->time < _trp->dtstart || |
1248 | 0 | (!_IS_SET(_trp->freq) && _atp->time >= _trp->dtend)) |
1249 | 0 | return REC_NOMATCH; |
1250 | | |
1251 | 0 | LM_DEV("1) %ld + %ld = %ld\n", _trp->dtstart, _trp->duration, _trp->dtend); |
1252 | |
|
1253 | 0 | if (!_IS_SET(_trp->freq) && _atp->time < _trp->dtend) |
1254 | 0 | return REC_MATCH; |
1255 | | |
1256 | 0 | LM_DEV("2) check freq\n"); |
1257 | | |
1258 | | /* check if the instance of recurrence matches the 'interval' */ |
1259 | 0 | if (check_freq_interval(_trp, _atp) != REC_MATCH) |
1260 | 0 | return REC_NOMATCH; |
1261 | | |
1262 | 0 | LM_DEV("3) check min unit\n"); |
1263 | |
|
1264 | 0 | if (check_min_unit(_trp, _atp) != REC_MATCH) |
1265 | 0 | return REC_NOMATCH; |
1266 | | |
1267 | 0 | LM_DEV("4) check byxxx\n"); |
1268 | |
|
1269 | 0 | if (check_byxxx(_trp, _atp) != REC_MATCH) |
1270 | 0 | return REC_NOMATCH; |
1271 | | |
1272 | 0 | LM_DEV("5) check until\n"); |
1273 | |
|
1274 | 0 | return (!_IS_SET(_trp->until) || _atp->time <= _trp->until) ? |
1275 | 0 | REC_MATCH : REC_NOMATCH; |
1276 | 0 | } |
1277 | | |
1278 | | |
1279 | | int check_freq_interval(tmrec_p _trp, ac_tm_p _atp) |
1280 | 0 | { |
1281 | 0 | int _t0, _t1; |
1282 | 0 | struct tm _tm; |
1283 | |
|
1284 | 0 | if(!_IS_SET(_trp->freq)) |
1285 | 0 | return REC_NOMATCH; |
1286 | | |
1287 | 0 | LM_DEV("have freq\n"); |
1288 | |
|
1289 | 0 | if(!_IS_SET(_trp->interval) || _trp->interval==1) |
1290 | 0 | return REC_MATCH; |
1291 | | |
1292 | 0 | LM_DEV("have interval (%d)\n", _trp->interval); |
1293 | |
|
1294 | 0 | switch(_trp->freq) |
1295 | 0 | { |
1296 | 0 | case FREQ_DAILY: |
1297 | 0 | case FREQ_WEEKLY: |
1298 | 0 | memset(&_tm, 0, sizeof(struct tm)); |
1299 | 0 | _tm.tm_year = _trp->ts.tm_year; |
1300 | 0 | _tm.tm_mon = _trp->ts.tm_mon; |
1301 | 0 | _tm.tm_mday = _trp->ts.tm_mday; |
1302 | 0 | _t0 = (int)mktime(&_tm); |
1303 | 0 | memset(&_tm, 0, sizeof(struct tm)); |
1304 | 0 | _tm.tm_year = _atp->t.tm_year; |
1305 | 0 | _tm.tm_mon = _atp->t.tm_mon; |
1306 | 0 | _tm.tm_mday = _atp->t.tm_mday; |
1307 | 0 | _t1 = (int)mktime(&_tm); |
1308 | 0 | if(_trp->freq == FREQ_DAILY) |
1309 | 0 | return (((_t1-_t0)/(24*3600))%_trp->interval==0)? |
1310 | 0 | REC_MATCH:REC_NOMATCH; |
1311 | | #ifdef USE_YWEEK_U |
1312 | | _t0 -= _trp->ts.tm_wday*24*3600; |
1313 | | _t1 -= _atp->t.tm_wday*24*3600; |
1314 | | #else |
1315 | 0 | _t0 -= ((_trp->ts.tm_wday+6)%7)*24*3600; |
1316 | 0 | _t1 -= ((_atp->t.tm_wday+6)%7)*24*3600; |
1317 | 0 | #endif |
1318 | 0 | return (((_t1-_t0)/(7*24*3600))%_trp->interval==0)? |
1319 | 0 | REC_MATCH:REC_NOMATCH; |
1320 | 0 | case FREQ_MONTHLY: |
1321 | 0 | _t0 = (_atp->t.tm_year-_trp->ts.tm_year)*12 |
1322 | 0 | + _atp->t.tm_mon-_trp->ts.tm_mon; |
1323 | 0 | return (_t0%_trp->interval==0)?REC_MATCH:REC_NOMATCH; |
1324 | 0 | case FREQ_YEARLY: |
1325 | 0 | return ((_atp->t.tm_year-_trp->ts.tm_year)%_trp->interval==0)? |
1326 | 0 | REC_MATCH:REC_NOMATCH; |
1327 | 0 | } |
1328 | | |
1329 | 0 | return REC_NOMATCH; |
1330 | 0 | } |
1331 | | |
1332 | | static inline int get_min_interval(tmrec_p _trp) |
1333 | 0 | { |
1334 | 0 | if(_trp->freq == FREQ_DAILY || _trp->byday || _trp->bymday || _trp->byyday) |
1335 | 0 | return FREQ_DAILY; |
1336 | 0 | if(_trp->freq == FREQ_WEEKLY || _trp->byweekno) |
1337 | 0 | return FREQ_WEEKLY; |
1338 | 0 | if(_trp->freq == FREQ_MONTHLY || _trp->bymonth) |
1339 | 0 | return FREQ_MONTHLY; |
1340 | 0 | if(_trp->freq == FREQ_YEARLY) |
1341 | 0 | return FREQ_YEARLY; |
1342 | | |
1343 | 0 | return FREQ_NOFREQ; |
1344 | 0 | } |
1345 | | |
1346 | | |
1347 | | int check_recur_itv(struct tm *x, struct tm *bgn, struct tm *end, |
1348 | | time_t dur, int freq) |
1349 | 0 | { |
1350 | 0 | int d1, d2, dx; |
1351 | 0 | long diff; |
1352 | |
|
1353 | 0 | switch (freq) { |
1354 | 0 | case FREQ_YEARLY: |
1355 | 0 | LM_DEV("YEARLY\n"); |
1356 | 0 | d1 = bgn->tm_yday; |
1357 | 0 | d2 = end->tm_yday; |
1358 | 0 | dx = x->tm_yday; |
1359 | 0 | break; |
1360 | | |
1361 | 0 | case FREQ_MONTHLY: |
1362 | 0 | LM_DEV("MONTHLY\n"); |
1363 | 0 | d1 = bgn->tm_mday; |
1364 | 0 | d2 = end->tm_mday; |
1365 | 0 | dx = x->tm_mday; |
1366 | 0 | break; |
1367 | | |
1368 | 0 | case FREQ_WEEKLY: |
1369 | 0 | LM_DEV("WEEKLY\n"); |
1370 | 0 | d1 = bgn->tm_wday; |
1371 | 0 | d2 = end->tm_wday; |
1372 | 0 | dx = x->tm_wday; |
1373 | 0 | break; |
1374 | | |
1375 | 0 | case FREQ_DAILY: |
1376 | 0 | default: |
1377 | 0 | LM_DEV("DAILY\n"); |
1378 | 0 | if (bgn->tm_mday == end->tm_mday) { |
1379 | 0 | LM_DEV("DAILY-1\n"); |
1380 | 0 | diff = x->tm_hour*3600 + x->tm_min*60 + x->tm_sec - |
1381 | 0 | (bgn->tm_hour*3600 + bgn->tm_min*60 + bgn->tm_sec); |
1382 | 0 | if (diff < 0) |
1383 | 0 | return REC_NOMATCH; |
1384 | | |
1385 | 0 | diff = end->tm_hour*3600 + end->tm_min*60 + end->tm_sec - |
1386 | 0 | (x->tm_hour*3600 + x->tm_min*60 + x->tm_sec); |
1387 | 0 | if (diff <= 0) |
1388 | 0 | return REC_NOMATCH; |
1389 | | |
1390 | 0 | LM_DEV("MATCH\n"); |
1391 | 0 | return REC_MATCH; |
1392 | |
|
1393 | 0 | } else { |
1394 | 0 | LM_DEV("DAILY-2\n"); |
1395 | 0 | diff = bgn->tm_hour*3600 + bgn->tm_min*60 + bgn->tm_sec - |
1396 | 0 | (x->tm_hour*3600 + x->tm_min*60 + x->tm_sec); |
1397 | 0 | if (diff <= 0) |
1398 | 0 | return REC_MATCH; |
1399 | | |
1400 | 0 | diff = x->tm_hour*3600 + x->tm_min*60 + x->tm_sec - |
1401 | 0 | (end->tm_hour*3600 + end->tm_min*60 + end->tm_sec); |
1402 | 0 | if (diff < 0) |
1403 | 0 | return REC_MATCH; |
1404 | | |
1405 | 0 | LM_DEV("NOMATCH\n"); |
1406 | 0 | return REC_NOMATCH; |
1407 | 0 | } |
1408 | 0 | } |
1409 | | |
1410 | 0 | LM_DEV("check intervals\n"); |
1411 | | |
1412 | | /* continuous interval (e.g. "M [ T W T F ] S S") */ |
1413 | 0 | if (d1 < d2) { |
1414 | 0 | LM_DEV("CI-1\n"); |
1415 | 0 | if (dx < d1 || dx > d2) |
1416 | 0 | return REC_NOMATCH; |
1417 | | |
1418 | 0 | if (dx > d1 && dx < d2) |
1419 | 0 | return REC_MATCH; |
1420 | | |
1421 | | /* overlapping interval (e.g. "1 2 ... 20 ] 21 ... 29 [ 30 31") */ |
1422 | 0 | } else if (d2 < d1) { |
1423 | 0 | LM_DEV("CI-2\n"); |
1424 | 0 | if (dx > d2 && dx < d1) |
1425 | 0 | return REC_NOMATCH; |
1426 | | |
1427 | 0 | if (dx < d2 || dx > d1) |
1428 | 0 | return REC_MATCH; |
1429 | |
|
1430 | 0 | } else if (dx != d1) { |
1431 | 0 | LM_DEV("CI-3\n"); |
1432 | 0 | if (dur <= SEC_DAILY) |
1433 | 0 | return REC_NOMATCH; |
1434 | 0 | else |
1435 | 0 | return REC_MATCH; |
1436 | |
|
1437 | 0 | } else { |
1438 | 0 | LM_DEV("CI-4\n"); |
1439 | 0 | diff = x->tm_hour*3600 + x->tm_min*60 + x->tm_sec - |
1440 | 0 | (bgn->tm_hour*3600 + bgn->tm_min*60 + bgn->tm_sec); |
1441 | 0 | if (diff < 0) |
1442 | 0 | return REC_NOMATCH; |
1443 | | |
1444 | 0 | diff = end->tm_hour*3600 + end->tm_min*60 + end->tm_sec - |
1445 | 0 | (x->tm_hour*3600 + x->tm_min*60 + x->tm_sec); |
1446 | 0 | if (diff <= 0) |
1447 | 0 | return REC_NOMATCH; |
1448 | | |
1449 | 0 | return REC_MATCH; |
1450 | 0 | } |
1451 | | |
1452 | 0 | if (dx == d1) |
1453 | 0 | diff = x->tm_hour*3600 + x->tm_min*60 + x->tm_sec - |
1454 | 0 | (bgn->tm_hour*3600 + bgn->tm_min*60 + bgn->tm_sec); |
1455 | 0 | else |
1456 | 0 | diff = end->tm_hour*3600 + end->tm_min*60 + end->tm_sec - |
1457 | 0 | (x->tm_hour*3600 + x->tm_min*60 + x->tm_sec); |
1458 | |
|
1459 | 0 | return diff > 0 ? REC_MATCH : REC_NOMATCH; |
1460 | 0 | } |
1461 | | |
1462 | | |
1463 | | int check_min_unit(tmrec_p _trp, ac_tm_p _atp) |
1464 | 0 | { |
1465 | 0 | int min_itv; |
1466 | 0 | struct tm end; |
1467 | |
|
1468 | 0 | min_itv = get_min_interval(_trp); |
1469 | 0 | LM_DEV("min_itv: %d\n", min_itv); |
1470 | |
|
1471 | 0 | switch (min_itv) { |
1472 | 0 | case FREQ_DAILY: |
1473 | 0 | if (_trp->duration >= SEC_DAILY) |
1474 | 0 | return REC_MATCH; |
1475 | 0 | break; |
1476 | | |
1477 | 0 | case FREQ_WEEKLY: |
1478 | 0 | if (_trp->duration >= SEC_WEEKLY) |
1479 | 0 | return REC_MATCH; |
1480 | 0 | break; |
1481 | | |
1482 | 0 | case FREQ_MONTHLY: |
1483 | 0 | if (_trp->duration >= SEC_MONTHLY_MAX) |
1484 | 0 | return REC_MATCH; |
1485 | 0 | break; |
1486 | | |
1487 | 0 | case FREQ_YEARLY: |
1488 | 0 | if (_trp->duration >= SEC_YEARLY_MAX) |
1489 | 0 | return REC_MATCH; |
1490 | 0 | break; |
1491 | | |
1492 | 0 | default: |
1493 | 0 | return REC_NOMATCH; |
1494 | 0 | } |
1495 | | |
1496 | 0 | LM_DEV("check recur...\n"); |
1497 | |
|
1498 | 0 | localtime_r(&_trp->dtend, &end); |
1499 | 0 | return check_recur_itv(&_atp->t, &_trp->ts, &end, _trp->duration, min_itv); |
1500 | 0 | } |
1501 | | |
1502 | | int check_byxxx(tmrec_p _trp, ac_tm_p _atp) |
1503 | 0 | { |
1504 | 0 | int i; |
1505 | 0 | ac_maxval_p _amp; |
1506 | |
|
1507 | 0 | if (!(_trp->flags & TR_BYXXX)) |
1508 | 0 | return REC_MATCH; |
1509 | | |
1510 | 0 | _amp = ac_get_maxval(_atp); |
1511 | |
|
1512 | 0 | if(_trp->bymonth) |
1513 | 0 | { |
1514 | 0 | for(i=0; i<_trp->bymonth->nr; i++) |
1515 | 0 | { |
1516 | 0 | if(_atp->t.tm_mon == |
1517 | 0 | ((_trp->bymonth->xxx[i] - 1)*_trp->bymonth->req[i]+12)%12) |
1518 | 0 | break; |
1519 | 0 | } |
1520 | 0 | if(i>=_trp->bymonth->nr) |
1521 | 0 | return REC_NOMATCH; |
1522 | 0 | } |
1523 | 0 | if(_trp->freq==FREQ_YEARLY && _trp->byweekno) |
1524 | 0 | { |
1525 | 0 | for(i=0; i<_trp->byweekno->nr; i++) |
1526 | 0 | { |
1527 | 0 | if(_atp->yweek == ((_trp->byweekno->xxx[i] - 1) *_trp->byweekno->req[i]+ |
1528 | 0 | _amp->yweek)%_amp->yweek) |
1529 | 0 | break; |
1530 | 0 | } |
1531 | 0 | if(i>=_trp->byweekno->nr) |
1532 | 0 | return REC_NOMATCH; |
1533 | 0 | } |
1534 | 0 | if(_trp->byyday) |
1535 | 0 | { |
1536 | 0 | for(i=0; i<_trp->byyday->nr; i++) |
1537 | 0 | { |
1538 | 0 | if(_atp->t.tm_yday == ((_trp->byyday->xxx[i] - 1)*_trp->byyday->req[i]+ |
1539 | 0 | _amp->yday)%_amp->yday) |
1540 | 0 | break; |
1541 | 0 | } |
1542 | 0 | if(i>=_trp->byyday->nr) |
1543 | 0 | return REC_NOMATCH; |
1544 | 0 | } |
1545 | 0 | if(_trp->bymday) |
1546 | 0 | { |
1547 | 0 | for(i=0; i<_trp->bymday->nr; i++) |
1548 | 0 | { |
1549 | | #ifdef EXTRA_DEBUG |
1550 | | LM_DBG("%d == %d\n", _atp->t.tm_mday, |
1551 | | (_trp->bymday->xxx[i]*_trp->bymday->req[i]+ |
1552 | | _amp->mday)%_amp->mday + ((_trp->bymday->req[i]<0)?1:0)); |
1553 | | #endif |
1554 | 0 | if(_atp->t.tm_mday == (_trp->bymday->xxx[i]*_trp->bymday->req[i]+ |
1555 | 0 | _amp->mday)%_amp->mday + ((_trp->bymday->req[i]<0)?1:0)) |
1556 | 0 | break; |
1557 | 0 | } |
1558 | 0 | if(i>=_trp->bymday->nr) |
1559 | 0 | return REC_NOMATCH; |
1560 | 0 | } |
1561 | 0 | if(_trp->byday) |
1562 | 0 | { |
1563 | 0 | for(i=0; i<_trp->byday->nr; i++) |
1564 | 0 | { |
1565 | 0 | if(_trp->freq==FREQ_YEARLY) |
1566 | 0 | { |
1567 | | #ifdef EXTRA_DEBUG |
1568 | | LM_DBG("%d==%d && %d==%d\n", _atp->t.tm_wday, |
1569 | | _trp->byday->xxx[i], _atp->ywday, |
1570 | | (_trp->byday->req[i]+_amp->ywday)%_amp->ywday); |
1571 | | #endif |
1572 | 0 | if(_atp->t.tm_wday == _trp->byday->xxx[i] && |
1573 | 0 | _atp->ywday == (_trp->byday->req[i]+_amp->ywday)% |
1574 | 0 | _amp->ywday) |
1575 | 0 | break; |
1576 | 0 | } |
1577 | 0 | else |
1578 | 0 | { |
1579 | 0 | if(_trp->freq==FREQ_MONTHLY) |
1580 | 0 | { |
1581 | | #ifdef EXTRA_DEBUG |
1582 | | LM_DBG("%d==%d && %d==%d [%d]\n", _atp->t.tm_wday, |
1583 | | _trp->byday->xxx[i], _atp->wom, |
1584 | | (_trp->byday->req[i]+_amp->mwday)%_amp->mwday, |
1585 | | _amp->mwday); |
1586 | | #endif |
1587 | 0 | if(_atp->t.tm_wday == _trp->byday->xxx[i] && |
1588 | 0 | _atp->wom==(_trp->byday->req[i]+ |
1589 | 0 | _amp->mwday)%_amp->mwday) |
1590 | 0 | break; |
1591 | 0 | } |
1592 | 0 | else |
1593 | 0 | { |
1594 | 0 | if(_atp->t.tm_wday == _trp->byday->xxx[i]) |
1595 | 0 | break; |
1596 | 0 | } |
1597 | 0 | } |
1598 | 0 | } |
1599 | 0 | if(i>=_trp->byday->nr) |
1600 | 0 | return REC_NOMATCH; |
1601 | 0 | } |
1602 | | |
1603 | 0 | return REC_MATCH; |
1604 | 0 | } |
1605 | | |
1606 | | |
1607 | | static inline int _tmrec_parse(const char *tr, tmrec_t *time_rec) |
1608 | 0 | { |
1609 | 0 | char *p, *s; |
1610 | 0 | osips_free_t free_f = (time_rec->flags & PKG_ALLOC ? |
1611 | 0 | osips_pkg_free : osips_shm_free); |
1612 | | |
1613 | | /* empty definition? */ |
1614 | 0 | if (!tr || *tr == '\0') |
1615 | 0 | return 0; |
1616 | | |
1617 | 0 | p = (char *)tr; |
1618 | |
|
1619 | 0 | load_TR_value(p, s, time_rec, tr_parse_tz, parse_error, done); |
1620 | | |
1621 | | /* Important: make sure to set the tz NOW, before more parsing... */ |
1622 | 0 | if (time_rec->tz) |
1623 | 0 | _tz_set(time_rec->tz); |
1624 | |
|
1625 | 0 | load_TR_value(p, s, time_rec, tr_parse_dtstart, parse_error, done); |
1626 | 0 | load_TR_value(p, s, time_rec, tr_parse_dtend, parse_error, done); |
1627 | 0 | load_TR_value(p, s, time_rec, tr_parse_duration, parse_error, done); |
1628 | 0 | load_TR_value(p, s, time_rec, tr_parse_freq, parse_error, done); |
1629 | 0 | load_TR_value(p, s, time_rec, tr_parse_until, parse_error, done); |
1630 | 0 | load_TR_value(p, s, time_rec, tr_parse_interval, parse_error, done); |
1631 | 0 | load_TR_value(p, s, time_rec, tr_parse_byday, parse_error, done); |
1632 | 0 | load_TR_value(p, s, time_rec, tr_parse_bymday, parse_error, done); |
1633 | 0 | load_TR_value(p, s, time_rec, tr_parse_byyday, parse_error, done); |
1634 | 0 | load_TR_value(p, s, time_rec, tr_parse_byweekno, parse_error, done); |
1635 | 0 | load_TR_value(p, s, time_rec, tr_parse_bymonth, parse_error, done); |
1636 | | |
1637 | 0 | done: |
1638 | 0 | if (time_rec->tz) |
1639 | 0 | tz_reset(); |
1640 | |
|
1641 | 0 | if (!_IS_SET(time_rec->dtstart)) |
1642 | 0 | time_rec->dtstart = 0; /* invalid; auto-fix to 19700101T000000 */ |
1643 | |
|
1644 | 0 | if (!_IS_SET(time_rec->duration)) { |
1645 | 0 | if (!_IS_SET(time_rec->dtend)) { |
1646 | | /* invalid; since we don't support mementos, we need a duration */ |
1647 | 0 | switch (get_min_interval(time_rec)) { |
1648 | 0 | case FREQ_DAILY: |
1649 | 0 | time_rec->dtend = time_rec->dtstart + SEC_DAILY - |
1650 | 0 | (time_rec->ts.tm_hour * 3600 + time_rec->ts.tm_min * 60 |
1651 | 0 | + time_rec->ts.tm_sec); /* until the end of the day */ |
1652 | 0 | break; |
1653 | 0 | case FREQ_WEEKLY: |
1654 | 0 | time_rec->dtend = time_rec->dtstart + SEC_WEEKLY - |
1655 | 0 | (time_rec->ts.tm_wday * SEC_DAILY |
1656 | 0 | + time_rec->ts.tm_hour * 3600 + time_rec->ts.tm_min * 60 |
1657 | 0 | + time_rec->ts.tm_sec); /* until the end of the week */ |
1658 | 0 | break; |
1659 | 0 | case FREQ_MONTHLY: |
1660 | 0 | time_rec->dtend = time_rec->dtstart + SEC_MONTHLY_MAX - |
1661 | 0 | (time_rec->ts.tm_mday * SEC_DAILY |
1662 | 0 | + time_rec->ts.tm_hour * 3600 + time_rec->ts.tm_min * 60 |
1663 | 0 | + time_rec->ts.tm_sec); /* until the end of the month */ |
1664 | 0 | break; |
1665 | 0 | case FREQ_YEARLY: |
1666 | 0 | time_rec->dtend = time_rec->dtstart + SEC_YEARLY_MAX - |
1667 | 0 | (time_rec->ts.tm_yday * SEC_DAILY |
1668 | 0 | + time_rec->ts.tm_hour * 3600 + time_rec->ts.tm_min * 60 |
1669 | 0 | + time_rec->ts.tm_sec); /* until the end of the year */ |
1670 | 0 | break; |
1671 | 0 | default: |
1672 | 0 | time_rec->dtend = 4294967295UL; /* auto-fix to +136 years */ |
1673 | 0 | } |
1674 | 0 | } |
1675 | | |
1676 | 0 | time_rec->duration = time_rec->dtend - time_rec->dtstart; |
1677 | 0 | } else { |
1678 | 0 | time_rec->dtend = time_rec->dtstart + time_rec->duration; |
1679 | 0 | } |
1680 | | |
1681 | 0 | if (!_IS_SET(time_rec->freq) && |
1682 | 0 | (_IS_SET(time_rec->until) || _IS_SET(time_rec->interval) |
1683 | 0 | || time_rec->flags & TR_BYXXX)) { |
1684 | 0 | LM_ERR("missing FREQ component in time rec: '%s'\n", tr); |
1685 | 0 | return -1; |
1686 | 0 | } |
1687 | | |
1688 | 0 | return 0; |
1689 | | |
1690 | 0 | parse_error: |
1691 | 0 | LM_ERR("parse error in <%s> around position %i\n", |
1692 | 0 | tr, (int)(long)(p-tr)); |
1693 | 0 | if (time_rec->tz) { |
1694 | 0 | free_f(time_rec->tz); |
1695 | 0 | tz_reset(); |
1696 | 0 | time_rec->tz = NULL; |
1697 | 0 | } |
1698 | |
|
1699 | 0 | return -1; |
1700 | 0 | } |
1701 | | |
1702 | | |
1703 | | tmrec *tmrec_parse(const char *tr, char alloc) |
1704 | 0 | { |
1705 | 0 | tmrec_p time_rec; |
1706 | |
|
1707 | 0 | time_rec = tmrec_new(alloc); |
1708 | 0 | if (!time_rec) { |
1709 | 0 | LM_ERR("oom\n"); |
1710 | 0 | return NULL; |
1711 | 0 | } |
1712 | | |
1713 | 0 | if (_tmrec_parse(tr, time_rec) < 0) { |
1714 | 0 | tmrec_free(time_rec); |
1715 | 0 | return NULL; |
1716 | 0 | } |
1717 | | |
1718 | 0 | return (tmrec *)time_rec; |
1719 | 0 | } |
1720 | | |
1721 | | |
1722 | | int _tmrec_check(const tmrec *_tr, time_t time) |
1723 | 0 | { |
1724 | 0 | tmrec_t *tr = (tmrec_p)_tr; |
1725 | 0 | ac_tm_t att; |
1726 | 0 | int rc; |
1727 | | |
1728 | | /* shortcut: if there is no dstart, timerec is valid */ |
1729 | 0 | if (!_IS_SET(tr->dtstart)) |
1730 | 0 | return 1; |
1731 | | |
1732 | 0 | if (tr->tz) |
1733 | 0 | _tz_set(tr->tz); |
1734 | | |
1735 | | /* set current time */ |
1736 | 0 | ac_tm_set_time(&att, time); |
1737 | | |
1738 | | /* does the recv_time match the specified interval? */ |
1739 | 0 | rc = check_tmrec(tr, &att); |
1740 | |
|
1741 | 0 | if (tr->tz) |
1742 | 0 | tz_reset(); |
1743 | |
|
1744 | 0 | return rc == 0; |
1745 | 0 | } |
1746 | | |
1747 | | |
1748 | | int _tmrec_check_str(const char *tr, time_t check_time) |
1749 | 0 | { |
1750 | 0 | tmrec_t time_rec; |
1751 | 0 | int rc; |
1752 | |
|
1753 | 0 | LM_DBG("checking: '%s'\n", tr); |
1754 | 0 | tmrec_init(&time_rec); |
1755 | 0 | time_rec.flags = PKG_ALLOC; |
1756 | |
|
1757 | 0 | if (_tmrec_parse(tr, &time_rec) < 0) { |
1758 | 0 | LM_ERR("failed to parse time rec\n"); |
1759 | 0 | tmrec_free_members(&time_rec, time_rec.flags); |
1760 | 0 | return -2; |
1761 | 0 | } |
1762 | | |
1763 | 0 | rc = _tmrec_check(&time_rec, check_time) ? 1 : -1; |
1764 | |
|
1765 | 0 | tmrec_free_members(&time_rec, time_rec.flags); |
1766 | |
|
1767 | 0 | return rc; |
1768 | 0 | } |
1769 | | |
1770 | | |
1771 | | int _tmrec_expr_check_str(const char *trx, time_t check_time) |
1772 | 0 | { |
1773 | 0 | char *p, *q, bkp, tmp = 77, need_close, invert_next = 0, op = 0; |
1774 | 0 | str aux; |
1775 | 0 | enum { |
1776 | 0 | NEED_OPERAND, |
1777 | 0 | NEED_OPERATOR, |
1778 | 0 | } state = NEED_OPERAND; |
1779 | |
|
1780 | 0 | int rc = 0, _rc; |
1781 | 0 | char is_valid; |
1782 | |
|
1783 | 0 | LM_DBG("checking: %s\n", trx); |
1784 | | |
1785 | | /* NULL input -> nothing to match against -> no match! */ |
1786 | 0 | if (!trx) |
1787 | 0 | return -1; |
1788 | | |
1789 | 0 | for (p = (char *)trx; *p != '\0'; p++) { |
1790 | 0 | if (is_ws(*p)) |
1791 | 0 | continue; |
1792 | | |
1793 | 0 | switch (state) { |
1794 | 0 | case NEED_OPERAND: |
1795 | 0 | switch (*p) { |
1796 | 0 | case ')': |
1797 | 0 | case '&': |
1798 | 0 | case '/': |
1799 | 0 | LM_ERR("failed to parse time rec (unexpected '%c')\n", *p); |
1800 | 0 | goto parse_err; |
1801 | | |
1802 | 0 | case '!': |
1803 | 0 | invert_next = !invert_next; |
1804 | 0 | continue; |
1805 | | |
1806 | 0 | case '(': |
1807 | 0 | for (need_close = 1, q = p + 1; *q != '\0'; q++) { |
1808 | 0 | switch (*q) { |
1809 | 0 | case '(': |
1810 | 0 | need_close++; |
1811 | 0 | break; |
1812 | | |
1813 | 0 | case ')': |
1814 | 0 | need_close--; |
1815 | 0 | break; |
1816 | | |
1817 | 0 | default: |
1818 | 0 | continue; |
1819 | 0 | } |
1820 | | |
1821 | 0 | if (!need_close) |
1822 | 0 | break; |
1823 | 0 | } |
1824 | | |
1825 | 0 | if (need_close) { |
1826 | 0 | LM_ERR("failed to parse time rec (bad parentheses)\n"); |
1827 | 0 | goto parse_err; |
1828 | 0 | } |
1829 | | |
1830 | 0 | aux.s = p + 1; |
1831 | 0 | aux.len = q - aux.s; |
1832 | 0 | trim(&aux); |
1833 | |
|
1834 | 0 | bkp = aux.s[aux.len]; |
1835 | 0 | aux.s[aux.len] = '\0'; |
1836 | 0 | _rc = _tmrec_expr_check_str(aux.s, check_time) + 1; |
1837 | 0 | aux.s[aux.len] = bkp; |
1838 | |
|
1839 | 0 | if (_rc < 0) |
1840 | 0 | goto parse_err; |
1841 | | |
1842 | 0 | p = q; |
1843 | |
|
1844 | 0 | if (invert_next) { |
1845 | 0 | invert_next = 0; |
1846 | 0 | _rc = (_rc + 2) % 4; |
1847 | 0 | } |
1848 | |
|
1849 | 0 | if (op == 1) |
1850 | 0 | rc &= _rc; |
1851 | 0 | else if (op == 2) |
1852 | 0 | rc |= _rc; |
1853 | 0 | else |
1854 | 0 | rc = tmp = _rc; |
1855 | |
|
1856 | 0 | state = NEED_OPERATOR; |
1857 | 0 | break; |
1858 | | |
1859 | 0 | default: |
1860 | 0 | for (is_valid = 0, q = p + 1; *q != '\0'; q++) { |
1861 | 0 | if (*q == '!' || *q == '(' || *q == ')') { |
1862 | 0 | LM_ERR("failed to parse multi time rec at '%c' " |
1863 | 0 | "(unexpected character)\n", *q); |
1864 | 0 | goto parse_err; |
1865 | 0 | } else if (*q == TR_SEPARATOR) { |
1866 | 0 | is_valid = 1; |
1867 | 0 | } |
1868 | | |
1869 | 0 | if (is_ws(*q)) { |
1870 | 0 | state = NEED_OPERATOR; |
1871 | 0 | break; |
1872 | 0 | } else if (*q == '&' || (*q == '/' && is_valid)) { |
1873 | 0 | break; |
1874 | 0 | } |
1875 | 0 | } |
1876 | | |
1877 | 0 | aux.s = p; |
1878 | 0 | aux.len = q - aux.s; |
1879 | 0 | trim(&aux); |
1880 | |
|
1881 | 0 | bkp = aux.s[aux.len]; |
1882 | 0 | aux.s[aux.len] = '\0'; |
1883 | 0 | _rc = _tmrec_check_str(aux.s, check_time) + 1; |
1884 | 0 | aux.s[aux.len] = bkp; |
1885 | |
|
1886 | 0 | if (_rc < 0) { |
1887 | 0 | LM_ERR("failed to parse single time rec: '%.*s'\n", |
1888 | 0 | aux.len, aux.s); |
1889 | 0 | return _rc - 1; |
1890 | 0 | } |
1891 | | |
1892 | 0 | if (invert_next) { |
1893 | 0 | invert_next = 0; |
1894 | 0 | _rc = (_rc + 2) % 4; |
1895 | 0 | } |
1896 | |
|
1897 | 0 | if (*q == '&') { |
1898 | 0 | if (op == 2) { |
1899 | 0 | LM_ERR("failed to parse rec at '&' (only 1 operator " |
1900 | 0 | "type is allowed within an expression)\n"); |
1901 | 0 | goto parse_err; |
1902 | 0 | } |
1903 | | |
1904 | 0 | if (op == 0) |
1905 | 0 | rc = _rc; |
1906 | 0 | op = 1; |
1907 | 0 | } else if (*q == '/') { |
1908 | 0 | if (op == 1) { |
1909 | 0 | LM_ERR("failed to parse rec at '/' (only 1 operator " |
1910 | 0 | "type is allowed within an expression)\n"); |
1911 | 0 | goto parse_err; |
1912 | 0 | } |
1913 | | |
1914 | 0 | op = 2; |
1915 | 0 | } |
1916 | | |
1917 | 0 | if (op == 1) |
1918 | 0 | rc &= _rc; |
1919 | 0 | else if (op == 2) |
1920 | 0 | rc |= _rc; |
1921 | 0 | else |
1922 | 0 | rc = tmp = _rc; |
1923 | |
|
1924 | 0 | if (*q == '\0') |
1925 | 0 | return rc - 1; |
1926 | | |
1927 | 0 | p = q; |
1928 | 0 | } |
1929 | 0 | break; |
1930 | | |
1931 | 0 | case NEED_OPERATOR: |
1932 | 0 | switch (*p) { |
1933 | 0 | case '&': |
1934 | 0 | if (op == 2) { |
1935 | 0 | LM_ERR("failed to parse rec at '&' (only 1 operator " |
1936 | 0 | "type is allowed within an expression)\n"); |
1937 | 0 | goto parse_err; |
1938 | 0 | } else if (op == 0) { |
1939 | 0 | rc = tmp; |
1940 | 0 | } |
1941 | | |
1942 | 0 | op = 1; |
1943 | 0 | state = NEED_OPERAND; |
1944 | 0 | break; |
1945 | | |
1946 | 0 | case '/': |
1947 | 0 | if (op == 1) { |
1948 | 0 | LM_ERR("failed to parse rec at '/' (only 1 operator " |
1949 | 0 | "type is allowed within an expression)\n"); |
1950 | 0 | goto parse_err; |
1951 | 0 | } |
1952 | | |
1953 | 0 | op = 2; |
1954 | 0 | state = NEED_OPERAND; |
1955 | 0 | break; |
1956 | | |
1957 | 0 | default: |
1958 | 0 | LM_ERR("failed to parse the rec string (bad char: '%c', " |
1959 | 0 | "expected operator)\n", *p); |
1960 | 0 | goto parse_err; |
1961 | 0 | } |
1962 | 0 | } |
1963 | 0 | } |
1964 | | |
1965 | 0 | if (state == NEED_OPERAND && op != 0) { |
1966 | 0 | LM_ERR("failed to parse the rec string (missing operand)\n"); |
1967 | 0 | LM_ERR("input given: '%s'\n", trx); |
1968 | 0 | return -2; |
1969 | 0 | } |
1970 | | |
1971 | 0 | if (invert_next) |
1972 | 0 | return (rc + 2) % 4 - 1; |
1973 | 0 | else |
1974 | 0 | return rc - 1; |
1975 | | |
1976 | 0 | return rc; |
1977 | | |
1978 | 0 | parse_err: |
1979 | 0 | LM_ERR("input given: '%s'\n", trx); |
1980 | 0 | return -2; |
1981 | 0 | } |
1982 | | |
1983 | | |
1984 | | tmrec_expr *tmrec_expr_parse(const char *trx, char alloc_type) |
1985 | 0 | { |
1986 | 0 | enum { |
1987 | 0 | NEED_OPERAND, |
1988 | 0 | NEED_OPERATOR, |
1989 | 0 | } state = NEED_OPERAND; |
1990 | |
|
1991 | 0 | tmrec_expr_t *exp, *e; |
1992 | 0 | osips_malloc_t malloc_f; |
1993 | 0 | char *p, *q, bkp, need_close, invert_next = 0, is_valid; |
1994 | 0 | str aux; |
1995 | 0 | int rc; |
1996 | |
|
1997 | 0 | if (!trx) |
1998 | 0 | return NULL; |
1999 | | |
2000 | 0 | LM_DBG("checking: %s\n", trx); |
2001 | |
|
2002 | 0 | malloc_f = (alloc_type & PKG_ALLOC ? |
2003 | 0 | osips_pkg_malloc : osips_shm_malloc); |
2004 | 0 | exp = malloc_f(sizeof *exp); |
2005 | 0 | if (!exp) { |
2006 | 0 | LM_ERR("oom\n"); |
2007 | 0 | return NULL; |
2008 | 0 | } |
2009 | | |
2010 | 0 | tmrec_expr_init(exp); |
2011 | 0 | exp->flags = alloc_type; |
2012 | |
|
2013 | 0 | for (p = (char *)trx; *p != '\0'; p++) { |
2014 | 0 | if (is_ws(*p)) |
2015 | 0 | continue; |
2016 | | |
2017 | 0 | switch (state) { |
2018 | 0 | case NEED_OPERAND: |
2019 | 0 | switch (*p) { |
2020 | 0 | case ')': |
2021 | 0 | case '&': |
2022 | 0 | case '/': |
2023 | 0 | LM_ERR("failed to parse time rec (unexpected '%c')\n", *p); |
2024 | 0 | goto parse_err; |
2025 | | |
2026 | 0 | case '!': |
2027 | 0 | invert_next = !invert_next; |
2028 | 0 | continue; |
2029 | | |
2030 | 0 | case '(': |
2031 | 0 | for (need_close = 1, q = p + 1; *q != '\0'; q++) { |
2032 | 0 | switch (*q) { |
2033 | 0 | case '(': |
2034 | 0 | need_close++; |
2035 | 0 | break; |
2036 | | |
2037 | 0 | case ')': |
2038 | 0 | need_close--; |
2039 | 0 | break; |
2040 | | |
2041 | 0 | default: |
2042 | 0 | continue; |
2043 | 0 | } |
2044 | | |
2045 | 0 | if (!need_close) |
2046 | 0 | break; |
2047 | 0 | } |
2048 | | |
2049 | 0 | if (need_close) { |
2050 | 0 | LM_ERR("failed to parse time rec (bad parentheses)\n"); |
2051 | 0 | goto parse_err; |
2052 | 0 | } |
2053 | | |
2054 | 0 | aux.s = p + 1; |
2055 | 0 | aux.len = q - aux.s; |
2056 | 0 | trim(&aux); |
2057 | |
|
2058 | 0 | bkp = aux.s[aux.len]; |
2059 | 0 | aux.s[aux.len] = '\0'; |
2060 | 0 | e = tmrec_expr_parse(aux.s, alloc_type); |
2061 | 0 | aux.s[aux.len] = bkp; |
2062 | |
|
2063 | 0 | if (!e) |
2064 | 0 | goto parse_err; |
2065 | | |
2066 | 0 | if (invert_next) { |
2067 | 0 | invert_next = 0; |
2068 | 0 | e->inverted = 1; |
2069 | 0 | } |
2070 | |
|
2071 | 0 | list_add_tail(&e->list, &exp->operands); |
2072 | 0 | p = q; |
2073 | 0 | state = NEED_OPERATOR; |
2074 | 0 | break; |
2075 | | |
2076 | 0 | default: |
2077 | 0 | for (is_valid = 0, q = p + 1; *q != '\0'; q++) { |
2078 | 0 | if (*q == '!' || *q == '(' || *q == ')') { |
2079 | 0 | LM_ERR("failed to parse multi time rec at '%c' " |
2080 | 0 | "(unexpected character)\n", *q); |
2081 | 0 | goto parse_err; |
2082 | 0 | } else if (*q == TR_SEPARATOR) { |
2083 | 0 | is_valid = 1; |
2084 | 0 | } |
2085 | | |
2086 | 0 | if (is_ws(*q)) { |
2087 | 0 | state = NEED_OPERATOR; |
2088 | 0 | break; |
2089 | 0 | } else if (*q == '&' || (*q == '/' && is_valid)) { |
2090 | 0 | break; |
2091 | 0 | } |
2092 | 0 | } |
2093 | | |
2094 | 0 | e = malloc_f(sizeof *e); |
2095 | 0 | if (!e) { |
2096 | 0 | LM_ERR("oom\n"); |
2097 | 0 | goto parse_err; |
2098 | 0 | } |
2099 | | |
2100 | 0 | tmrec_expr_init(e); |
2101 | 0 | e->flags = e->tr.flags = alloc_type; |
2102 | 0 | e->is_leaf = 1; |
2103 | |
|
2104 | 0 | list_add_tail(&e->list, &exp->operands); |
2105 | |
|
2106 | 0 | aux.s = p; |
2107 | 0 | aux.len = q - aux.s; |
2108 | 0 | trim(&aux); |
2109 | |
|
2110 | 0 | bkp = aux.s[aux.len]; |
2111 | 0 | aux.s[aux.len] = '\0'; |
2112 | 0 | rc = _tmrec_parse(aux.s, &e->tr); |
2113 | 0 | aux.s[aux.len] = bkp; |
2114 | |
|
2115 | 0 | if (rc < 0) |
2116 | 0 | goto parse_err; |
2117 | | |
2118 | 0 | if (invert_next) { |
2119 | 0 | invert_next = 0; |
2120 | 0 | e->inverted = 1; |
2121 | 0 | } |
2122 | |
|
2123 | 0 | if (*q == '&') { |
2124 | 0 | if (exp->op == TR_OP_OR) { |
2125 | 0 | LM_ERR("failed to parse rec at '&' (only 1 operator " |
2126 | 0 | "type is allowed within an expression)\n"); |
2127 | 0 | goto parse_err; |
2128 | 0 | } |
2129 | | |
2130 | 0 | exp->op = TR_OP_AND; |
2131 | 0 | } else if (*q == '/') { |
2132 | 0 | if (exp->op == TR_OP_AND) { |
2133 | 0 | LM_ERR("failed to parse rec at '/' (only 1 operator " |
2134 | 0 | "type is allowed within an expression)\n"); |
2135 | 0 | goto parse_err; |
2136 | 0 | } |
2137 | | |
2138 | 0 | exp->op = TR_OP_OR; |
2139 | 0 | } |
2140 | | |
2141 | 0 | if (*q == '\0') |
2142 | 0 | return exp; |
2143 | | |
2144 | 0 | p = q; |
2145 | 0 | } |
2146 | 0 | break; |
2147 | | |
2148 | 0 | case NEED_OPERATOR: |
2149 | 0 | switch (*p) { |
2150 | 0 | case '&': |
2151 | 0 | if (exp->op == TR_OP_OR) { |
2152 | 0 | LM_ERR("failed to parse rec at '&' (only 1 operator " |
2153 | 0 | "type is allowed within an expression)\n"); |
2154 | 0 | goto parse_err; |
2155 | 0 | } |
2156 | | |
2157 | 0 | exp->op = TR_OP_AND; |
2158 | 0 | state = NEED_OPERAND; |
2159 | 0 | break; |
2160 | | |
2161 | 0 | case '/': |
2162 | 0 | if (exp->op == TR_OP_AND) { |
2163 | 0 | LM_ERR("failed to parse rec at '/' (only 1 operator " |
2164 | 0 | "type is allowed within an expression)\n"); |
2165 | 0 | goto parse_err; |
2166 | 0 | } |
2167 | | |
2168 | 0 | exp->op = TR_OP_OR; |
2169 | 0 | state = NEED_OPERAND; |
2170 | 0 | break; |
2171 | | |
2172 | 0 | default: |
2173 | 0 | LM_ERR("failed to parse the rec string (bad char: '%c', " |
2174 | 0 | "expected operator)\n", *p); |
2175 | 0 | goto parse_err; |
2176 | 0 | } |
2177 | 0 | } |
2178 | 0 | } |
2179 | | |
2180 | 0 | if (state == NEED_OPERAND && exp->op != TR_OP_NUL) { |
2181 | 0 | LM_ERR("failed to parse the rec string (missing operand)\n"); |
2182 | 0 | goto parse_err; |
2183 | 0 | } |
2184 | | |
2185 | 0 | if (invert_next) |
2186 | 0 | exp->inverted = 1; |
2187 | |
|
2188 | 0 | return exp; |
2189 | | |
2190 | 0 | parse_err: |
2191 | 0 | tmrec_expr_free(exp); |
2192 | 0 | LM_ERR("parsing failed, input given: '%s'\n", trx); |
2193 | 0 | return NULL; |
2194 | 0 | } |
2195 | | |
2196 | | |
2197 | | int _tmrec_expr_check(const tmrec_expr *_trx, time_t check_time) |
2198 | 0 | { |
2199 | 0 | struct list_head *el; |
2200 | 0 | const tmrec_expr_t *exp, *trx = (const tmrec_expr_t *)_trx; |
2201 | 0 | int rc = 0; |
2202 | |
|
2203 | 0 | if (!trx) |
2204 | 0 | return -1; |
2205 | | |
2206 | 0 | if (trx->is_leaf) { |
2207 | 0 | rc = _tmrec_check(&trx->tr, check_time) ? 2 : 0; |
2208 | 0 | goto out; |
2209 | 0 | } |
2210 | | |
2211 | 0 | if (list_empty(&trx->operands)) |
2212 | 0 | goto out; |
2213 | | |
2214 | 0 | rc = (trx->op == TR_OP_AND ? 2 : 0); |
2215 | |
|
2216 | 0 | list_for_each (el, &trx->operands) { |
2217 | 0 | exp = list_entry(el, tmrec_expr_t, list); |
2218 | |
|
2219 | 0 | if (trx->op == TR_OP_AND) |
2220 | 0 | rc = rc & (_tmrec_expr_check(exp, check_time) + 1); |
2221 | 0 | else |
2222 | 0 | rc = rc | (_tmrec_expr_check(exp, check_time) + 1); |
2223 | 0 | } |
2224 | |
|
2225 | 0 | out: |
2226 | 0 | if (trx->inverted) { |
2227 | 0 | LM_DEV("result: %d\n", (rc + 2) % 4 - 1); |
2228 | 0 | return (rc + 2) % 4 - 1; |
2229 | 0 | } |
2230 | | |
2231 | 0 | LM_DEV("result: %d\n", rc - 1); |
2232 | 0 | return rc - 1; |
2233 | 0 | } |
2234 | | |
2235 | | |
2236 | | void tmrec_expr_free(tmrec_expr *_trx) |
2237 | 0 | { |
2238 | 0 | struct list_head *el, *next; |
2239 | 0 | tmrec_expr_t *exp, *trx = (tmrec_expr_t *)_trx; |
2240 | 0 | osips_free_t free_f; |
2241 | |
|
2242 | 0 | if (!trx) |
2243 | 0 | return; |
2244 | | |
2245 | 0 | free_f = (trx->flags & PKG_ALLOC ? |
2246 | 0 | osips_pkg_free : osips_shm_free); |
2247 | |
|
2248 | 0 | list_for_each_safe (el, next, &trx->operands) { |
2249 | 0 | exp = list_entry(el, tmrec_expr_t, list); |
2250 | 0 | tmrec_expr_free(exp); |
2251 | 0 | } |
2252 | |
|
2253 | 0 | tmrec_free_members(&trx->tr, trx->flags); |
2254 | 0 | free_f(trx); |
2255 | 0 | } |
2256 | | |
2257 | | |
2258 | | int _tz_offset(const char *tz, time_t t) |
2259 | 0 | { |
2260 | 0 | struct tm lt = {0}; |
2261 | |
|
2262 | 0 | _tz_set(tz); |
2263 | 0 | localtime_r(&t, <); |
2264 | 0 | tz_reset(); |
2265 | |
|
2266 | 0 | return lt.tm_gmtoff; |
2267 | 0 | } |