1 /*
2 * binkleyforce -- unix FTN mailer project
3 *
4 * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
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 * $Id: u_time.c,v 1.1.1.1 2004/09/09 09:52:39 kstepanenkov Exp $
12 */
13
14 #include "includes.h"
15 #include "confread.h"
16 #include "logger.h"
17 #include "util.h"
18
19 static const char *months[] =
20 {
21 "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
22 };
23
time_settimer(time_t * timer,int value)24 int time_settimer(time_t *timer, int value)
25 {
26 *timer = time(NULL) + value;
27
28 return 0;
29 }
30
time_timerout(time_t timer)31 int time_timerout(time_t timer)
32 {
33 if( timer > 0 && time(NULL) >= timer )
34 return 1;
35
36 return 0;
37 }
38
time_timeleft(time_t timer)39 int time_timeleft(time_t timer)
40 {
41 if( timer > 0 )
42 return MAX(time(NULL) - timer, 0);
43
44 return 0;
45 }
46
time_elapsed(time_t since_time)47 int time_elapsed(time_t since_time)
48 {
49 if( since_time > 0 )
50 {
51 int yield = time(NULL) - since_time;
52 return ( yield > 0 ) ? yield : 0;
53 }
54
55 return 0;
56 }
57
58 /*****************************************************************************
59 * Put time string into buffer, according to the format
60 *
61 * Arguments:
62 * buffer pointer to the destination buffer
63 * buflen buffer size
64 * fmt format string (`man strftime' for more information)
65 * t seconds since 1970.. you know..
66 *
67 * Return value:
68 * Pointer to the resulting string
69 */
time_string_format(char * buffer,size_t buflen,const char * fmt,time_t t)70 char *time_string_format(char *buffer, size_t buflen, const char *fmt, time_t t)
71 {
72 struct tm *tm;
73
74 if( !t ) t = time(&t);
75
76 tm = localtime(&t);
77
78 if( strftime(buffer, buflen, fmt, tm) == 0 )
79 {
80 strnxcpy(buffer, "invalid format", buflen);
81 }
82
83 return buffer;
84 }
85
86 /*****************************************************************************
87 * Put time string into buffer (time format depends on the locale settings).
88 *
89 * Arguments:
90 * buffer pointer to the destination buffer
91 * buflen buffer size
92 * t seconds since 1970.. you know..
93 *
94 * Return value:
95 * Pointer to the resulting string
96 */
time_string_long(char * buffer,size_t buflen,time_t t)97 char *time_string_long(char *buffer, size_t buflen, time_t t)
98 {
99 char *sptr;
100
101 if( !t ) time(&t);
102
103 sptr = ctime(&t);
104 strnxcpy(buffer, sptr, buflen);
105
106 return string_chomp(buffer);
107 }
108
109 /*****************************************************************************
110 * Put time string into buffer (e.g. My birth day is "Aug 11 07:20:00").
111 *
112 * Arguments:
113 * buffer pointer to the destination buffer
114 * buflen buffer size
115 * t seconds since 1970.. you know..
116 *
117 * Return value:
118 * Pointer to the resulting string
119 */
time_string_bf_log(char * buffer,size_t buflen,time_t t)120 char *time_string_bf_log(char *buffer, size_t buflen, time_t t)
121 {
122 struct tm *ptm;
123
124 ASSERT(buflen > 16);
125
126 if( !t ) time(&t);
127
128 ptm = localtime(&t);
129 sprintf(buffer, "%3s %02d %02d:%02d:%02d",
130 months[ptm->tm_mon], ptm->tm_mday,
131 ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
132
133 return buffer;
134 }
135
136 /*****************************************************************************
137 * Put date+time string into buffer. Special format for netmail message
138 * headers.
139 *
140 * Arguments:
141 * buffer pointer to the destination buffer
142 * buflen buffer size
143 * t seconds since 1970.. you know..
144 *
145 * Return value:
146 * Pointer to the resulting string
147 */
time_string_msghdr(char * buffer,time_t t)148 char *time_string_msghdr(char *buffer, time_t t)
149 {
150 struct tm *ptm;
151
152 if( !t ) time(&t);
153
154 ptm = localtime(&t);
155 sprintf(buffer, "%02d %3s %02d %02d:%02d:%02d",
156 ptm->tm_mday, months[ptm->tm_mon],
157 (ptm->tm_year < 100) ? ptm->tm_year : ptm->tm_year % 100,
158 ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
159
160 return buffer;
161 }
162
163 /*****************************************************************************
164 * Get TimeZone for our location
165 *
166 * Arguments:
167 *
168 * Return value:
169 * Offset in minutes
170 */
time_gmtoffset(void)171 long time_gmtoffset(void)
172 {
173 time_t tt = time(NULL);
174 struct tm local = *localtime(&tt);
175 struct tm gmt = *gmtime(&tt);
176 long tz = gmt.tm_yday - local.tm_yday;
177
178 if( tz > 1 )
179 tz = -24;
180 else if( tz < -1 )
181 tz = 24;
182 else
183 tz *= 24;
184
185 tz += gmt.tm_hour - local.tm_hour;
186 tz *= 60;
187 tz += gmt.tm_min - local.tm_min;
188
189 return tz;
190 }
191
192 /*****************************************************************************
193 * Get TimeZone for our location as pointer to the null terminated string
194 *
195 * Arguments:
196 * buffer pointer to the destination buffer (must be at least 6 bytes)
197 *
198 * Return value:
199 * Pointer to the resulting string (e.g. "+0400")
200 */
time_string_gmtoffset(char * buffer)201 char *time_string_gmtoffset(char *buffer)
202 {
203 long tz = time_gmtoffset();
204 char sign = (tz > 0)?'+':'-';
205 int hour = tz/60;
206 int mint = tz%60;
207
208 sprintf(buffer, "%c%02d%02d", sign, hour, mint);
209
210 return buffer;
211 }
212
213 /*****************************************************************************
214 * Get time in native format from seconds counter (e.g. "1:30:10")
215 *
216 * Arguments:
217 * buffer pointer to the destination buffer (must be at least 9 bytes)
218 * timer number of seconds
219 *
220 * Return value:
221 * Pointer to the resulting string
222 */
time_string_timer(char * buffer,int timer)223 char *time_string_timer(char *buffer, int timer)
224 {
225 int hour, min, sec;
226
227 hour = (timer/3600);
228 min = (timer%3600)/60;
229 sec = (timer%60);
230
231 if( hour )
232 sprintf(buffer, "%02d:%02d:%02d", (hour < 100) ? hour : 99, min, sec);
233 else
234 sprintf(buffer, "%02d:%02d", min, sec);
235
236 return buffer;
237 }
238
239 /*****************************************************************************
240 * Get approximate interval in native format (e.g. "1 day", "3 hours")
241 *
242 * Arguments:
243 * buffer pointer to the destination buffer (must be large enough)
244 * seconds time interval in seconds
245 *
246 * Return value:
247 * Pointer to the resulting string
248 */
time_string_approx_interval(char * buffer,int seconds)249 char *time_string_approx_interval(char *buffer, int seconds)
250 {
251 if( seconds < 0 )
252 strcpy(buffer, "error");
253 else if( seconds == 0 )
254 strcpy(buffer, "up-to-date");
255 else if( seconds == 1 )
256 strcpy(buffer, "1 second");
257 else if( seconds < 60 )
258 sprintf(buffer, "%d seconds", seconds);
259 else if( seconds < 120 )
260 strcpy(buffer, "1 minute");
261 else if( seconds < 3600 )
262 sprintf(buffer, "%d minutes", seconds/60);
263 else if( seconds < 7200 )
264 strcpy(buffer, "1 hour");
265 else if( seconds < 86400 )
266 sprintf(buffer, "%d hours", seconds/3600);
267 else if( seconds < 172800 )
268 strcpy(buffer, "1 day");
269 else if( seconds < 999*86400 )
270 sprintf(buffer, "%d days", seconds/86400);
271 else
272 sprintf(buffer, "%d years", seconds/(366*86400));
273
274 return buffer;
275 }
276
277 /*****************************************************************************
278 * Check time for conforming to the time interval specified by string
279 *
280 * Arguments:
281 * str pointer to the time interval string
282 * now time to check (most often it is current time)
283 *
284 * Return value:
285 * Zero value if time conforms, 1 if not, and -1 if specified time interval
286 * string is incorrect
287 */
time_check(const char * str,struct tm * now)288 int time_check(const char *str, struct tm *now)
289 {
290 int h1, h2, m1, m2, beg, end, cur, day;
291 bool dayok = FALSE;
292 bool timeok = FALSE;
293
294 ASSERT(str != NULL && now != NULL);
295
296 if( *str == '\0' ) return 1;
297
298 if( strncasecmp(str, "Sun", 3) == 0 ) day = 0;
299 else if( strncasecmp(str, "Mon", 3) == 0 ) day = 1;
300 else if( strncasecmp(str, "Tue", 3) == 0 ) day = 2;
301 else if( strncasecmp(str, "Wed", 3) == 0 ) day = 3;
302 else if( strncasecmp(str, "Thu", 3) == 0 ) day = 4;
303 else if( strncasecmp(str, "Fri", 3) == 0 ) day = 5;
304 else if( strncasecmp(str, "Sat", 3) == 0 ) day = 6;
305 else if( strncasecmp(str, "Any", 3) == 0 ) day = -1;
306 else if( strncasecmp(str, "Wk", 2) == 0 ) day = -2;
307 else if( strncasecmp(str, "We", 2) == 0 ) day = -3;
308 else day = -4;
309
310 if( day >= 0 )
311 {
312 dayok = (now->tm_wday == day);
313 str += 3;
314 }
315 else
316 {
317 switch(day) {
318 case -3:
319 dayok = ( (now->tm_wday == 0) || (now->tm_wday == 6) );
320 str += 2;
321 break;
322 case -2:
323 dayok = ( (now->tm_wday != 0) && (now->tm_wday != 6) );
324 str += 2;
325 break;
326 case -1:
327 str += 3;
328 default:
329 dayok = TRUE;
330 }
331 }
332
333 if( !dayok ) return 1;
334
335 if( *str == '\0' )
336 return (day == -4) ? -1 : 0;
337
338 if( sscanf(str, "%02d:%02d-%02d:%02d", &h1, &m1, &h2, &m2) != 4 )
339 return -1;
340
341 cur = now->tm_hour*60 + now->tm_min;
342 beg = h1*60 + m1;
343 end = h2*60 + m2;
344
345 if( end > beg )
346 timeok = ( (cur >= beg) && (cur <= end) );
347 else
348 timeok = ( (cur >= beg) || (cur <= end) );
349
350 DEB((D_INFO, "checktime: is %02d:%02d between %02d:%02d and %02d:%02d? %s!",
351 now->tm_hour,now->tm_min, h1, m1, h2, m2, timeok ? "Yes" : "No"));
352
353 return !timeok;
354 }
355
356 /*****************************************************************************
357 * Check time for conforming to the time intervals
358 *
359 * Arguments:
360 * timestr pointer to the time intervals string
361 * tim time to check (most often it is current time)
362 *
363 * Return value:
364 * Zero value if time conforms, 1 if not, and -1 if specified time interval
365 * string is incorrect
366 */
time_checkintervals(const char * timestr,struct tm * now)367 int time_checkintervals(const char *timestr, struct tm *now)
368 {
369 char *str, *p;
370
371 ASSERT(timestr != NULL);
372
373 str = xstrcpy(timestr);
374
375 for( p = strtok(str, ","); p; p = strtok(NULL, ",") )
376 {
377 if( *p )
378 {
379 switch(time_check(p, now)) {
380 case 0:
381 return 0;
382 case -1:
383 return -1;
384 case 1:
385 break;
386 default:
387 ASSERT(0);
388 }
389 }
390 }
391
392 return 1;
393 }
394
timevec_add(s_timevec * dest,int day_beg,int day_end,long beg,long end)395 int timevec_add(s_timevec *dest, int day_beg, int day_end, long beg, long end)
396 {
397 int i;
398
399 /*
400 * Check for dupes. TODO: more complex checks
401 */
402 for( i = 0; i < dest->num; i++ )
403 {
404 if( dest->tvec[i].day_beg <= day_beg
405 && dest->tvec[i].day_end >= day_end
406 && dest->tvec[i].beg == beg
407 && dest->tvec[i].end == end )
408 return 0;
409 }
410
411 if( dest->num >= TIMEVEC_MAX_ELEMENTS )
412 return -1;
413
414 dest->tvec[dest->num].day_beg = day_beg;
415 dest->tvec[dest->num].day_end = day_end;
416 dest->tvec[dest->num].beg = beg;
417 dest->tvec[dest->num].end = end;
418 dest->num++;
419
420 return 0;
421 }
422
423 /*****************************************************************************
424 * Parse one time interval. Only uucico like time format is supported yet.
425 *
426 * Arguments:
427 * dest pointer to the destination time storage structure
428 * str time string to parse
429 *
430 * Return value:
431 * Zero value on success, and -1 for incorrect time strings
432 */
timevec_parse(s_timevec * dest,const char * str)433 int timevec_parse(s_timevec *dest, const char *str)
434 {
435 int beg_hour = 0;
436 int end_hour = 0;
437 int beg_min = 0;
438 int end_min = 0;
439 enum day beg_day;
440 enum day end_day;
441 int beg = 0;
442 int end = 0;
443
444 if( strncasecmp(str, "Sun", 3) == 0 )
445 beg_day = DAY_SUNDAY;
446 else if( strncasecmp(str, "Mon", 3) == 0 )
447 beg_day = DAY_MONDAY;
448 else if( strncasecmp(str, "Tue", 3) == 0 )
449 beg_day = DAY_TUESDAY;
450 else if( strncasecmp(str, "Wed", 3) == 0 )
451 beg_day = DAY_WEDNESDAY;
452 else if( strncasecmp(str, "Thu", 3) == 0 )
453 beg_day = DAY_THURSDAY;
454 else if( strncasecmp(str, "Fri", 3) == 0 )
455 beg_day = DAY_FRIDAY;
456 else if( strncasecmp(str, "Sat", 3) == 0 )
457 beg_day = DAY_SATURDAY;
458 else if( strncasecmp(str, "Any", 3) == 0 )
459 beg_day = DAY_ANY;
460 else if( strncasecmp(str, "Wk", 2) == 0 )
461 beg_day = DAY_WORKDAY;
462 else if( strncasecmp(str, "We", 2) == 0 )
463 beg_day = DAY_WEEKEND;
464 else
465 beg_day = DAY_UNDEF;
466
467 end_day = beg_day;
468
469 if( beg_day >= DAY_MONDAY && beg_day <= DAY_SUNDAY )
470 str += 3;
471 else if( beg_day == DAY_ANY )
472 str += 3;
473 else if( beg_day == DAY_WORKDAY || beg_day == DAY_WEEKEND )
474 str += 2;
475
476 if( sscanf(str, "%02d:%02d-%02d:%02d", &beg_hour, &beg_min, &end_hour, &end_min) != 4 )
477 return -1;
478
479 beg = beg_hour * 60 + beg_min;
480 end = end_hour * 60 + end_min;
481
482 if( beg == end )
483 return -1;
484
485 switch(beg_day) {
486 case DAY_MONDAY:
487 case DAY_TUESDAY:
488 case DAY_WEDNESDAY:
489 case DAY_THURSDAY:
490 case DAY_FRIDAY:
491 case DAY_SATURDAY:
492 case DAY_SUNDAY:
493 timevec_add(dest, beg_day, end_day, beg, end);
494 break;
495 case DAY_WORKDAY:
496 timevec_add(dest, DAY_MONDAY, DAY_FRIDAY, beg, end);
497 break;
498 case DAY_WEEKEND:
499 timevec_add(dest, DAY_SATURDAY, DAY_SUNDAY, beg, end);
500 break;
501 default:
502 timevec_add(dest, DAY_MONDAY, DAY_SUNDAY, beg, end);
503 break;
504 }
505
506 return 0;
507 }
508
timevec_parse_list(s_timevec * dest,const char * str)509 int timevec_parse_list(s_timevec *dest, const char *str)
510 {
511 char *p = NULL;
512 char *tmp = xstrcpy(str);
513 int rc = 0;
514
515 for( p = strtok(tmp, ","); p; p = strtok(NULL, ",") )
516 {
517 if( *p && timevec_parse(dest, p) == -1 )
518 rc = -1;
519 }
520
521 free(tmp);
522
523 return rc;
524 }
525
timevec_check(const s_timevec * tv,const struct tm * now)526 int timevec_check(const s_timevec *tv, const struct tm *now)
527 {
528 int i;
529 bool ok = FALSE;
530 int cur = now->tm_hour * 60 + now->tm_min;
531 int cur_day = DAY_UNDEF;
532
533 if( now->tm_wday == 0 )
534 cur_day = DAY_SUNDAY;
535 else if( now->tm_wday == 1 )
536 cur_day = DAY_MONDAY;
537 else if( now->tm_wday == 2 )
538 cur_day = DAY_TUESDAY;
539 else if( now->tm_wday == 3 )
540 cur_day = DAY_WEDNESDAY;
541 else if( now->tm_wday == 4 )
542 cur_day = DAY_THURSDAY;
543 else if( now->tm_wday == 5 )
544 cur_day = DAY_FRIDAY;
545 else if( now->tm_wday == 6 )
546 cur_day = DAY_SATURDAY;
547 else
548 {
549 bf_log("timevec_check: error 'tm->tm_wday' is out of range");
550 return -1;
551 }
552
553 for( i = 0; i < tv->num; i++ )
554 {
555 if( (cur_day >= tv->tvec[i].day_beg)
556 && (cur_day <= tv->tvec[i].day_end) )
557 {
558 int beg = tv->tvec[i].beg;
559 int end = tv->tvec[i].end;
560
561 if( end > beg )
562 ok = ( (cur >= beg) && (cur <= end) );
563 else
564 ok = ( (cur >= beg) || (cur <= end) );
565
566 if( ok ) break;
567 }
568 }
569
570 return ok ? 0 : 1;
571 }
572
timevec_string(char * buffer,const s_timevec * tv,size_t buflen)573 char *timevec_string(char *buffer, const s_timevec *tv, size_t buflen)
574 {
575 int i;
576 char *ptr = buffer;
577
578 *ptr = '\0';
579
580 for( i = 0; i < tv->num; i++ )
581 {
582 if( tv->tvec[i].day_beg == DAY_MONDAY
583 && tv->tvec[i].day_end == DAY_SUNDAY )
584 {
585 sprintf(ptr, "%02ld:%02ld-%02ld:%02ld,",
586 tv->tvec[i].beg / 60, tv->tvec[i].beg % 60,
587 tv->tvec[i].end / 60, tv->tvec[i].end % 60);
588 }
589 else if( tv->tvec[i].day_beg == tv->tvec[i].day_end )
590 {
591 sprintf(ptr, "%d.%02ld:%02ld-%02ld:%02ld,", tv->tvec[i].day_beg,
592 tv->tvec[i].beg / 60, tv->tvec[i].beg % 60,
593 tv->tvec[i].end / 60, tv->tvec[i].end % 60);
594 }
595 else
596 {
597 sprintf(ptr, "%d.%02ld:%02ld-%d.%02ld:%02ld,",
598 tv->tvec[i].day_beg, tv->tvec[i].beg / 60, tv->tvec[i].beg % 60,
599 tv->tvec[i].day_end, tv->tvec[i].end / 60, tv->tvec[i].end % 60);
600 }
601
602 ptr += strlen(ptr);
603 }
604
605 if( ptr > buffer )
606 *(ptr - 1) = '\0';
607
608 return buffer;
609 }
610
timevec_isdefined(const s_timevec * tv)611 bool timevec_isdefined(const s_timevec *tv)
612 {
613 return tv->num ? TRUE : FALSE;
614 }
615
timevec_isnow(const s_timevec * tv,const struct tm * now)616 bool timevec_isnow(const s_timevec *tv, const struct tm *now)
617 {
618 return ( timevec_check(tv, now) == 0 ) ? TRUE : FALSE;
619 }
620
621 /* end of u_time.c */
622