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