1/*
2 *   Copyright (c) 1997 Gary Jennejohn. All rights reserved.
3 *
4 *   Copyright (c) 1997, 1999 Hellmuth Michaelis. All rights reserved.
5 *
6 *   Redistribution and use in source and binary forms, with or without
7 *   modification, are permitted provided that the following conditions
8 *   are met:
9 *
10 *   1. Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *   2. Redistributions in binary form must reproduce the above copyright
13 *      notice, this list of conditions and the following disclaimer in the
14 *      documentation and/or other materials provided with the distribution.
15 *   3. Neither the name of the author nor the names of any co-contributors
16 *      may be used to endorse or promote products derived from this software
17 *      without specific prior written permission.
18 *   4. Altered versions must be plainly marked as such, and must not be
19 *      misrepresented as being the original software and/or documentation.
20 *
21 *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 *   SUCH DAMAGE.
32 *
33 *---------------------------------------------------------------------------
34 *
35 *	i4b daemon - charging rates description file handling
36 *	-----------------------------------------------------
37 *
38 *	$Id: rates.c,v 1.6 2004/10/30 08:19:30 dsl Exp $
39 *
40 * $FreeBSD$
41 *
42 *      last edit-date: [Mon Dec 13 21:48:31 1999]
43 *
44 *---------------------------------------------------------------------------*/
45
46static char error[256];
47
48static int getrate(int rate_type);
49
50#ifdef PARSE_DEBUG_MAIN
51
52#include <stdio.h>
53
54#define MAIN
55
56#define ERROR (-1)
57
58extern int got_rate;
59
60int main( int argc, char **argv )
61{
62	int ret;
63	ret = readrates("/etc/isdn/isdnd.rates");
64	if (ret == ERROR)
65		fprintf(stderr, "readrates returns [%d], [%s]\n", ret, error);
66	else
67		{
68		int type = 0;
69
70		got_rate = 1;
71
72		fprintf(stderr, "readrates returns [%d]\n", ret);
73
74		for (type = 0; type < 4; type++)
75			{
76			int unit = getrate( type );
77			fprintf(stderr, "getrate(%d) => %d\n", type, unit );
78			}
79		}
80
81	return(ret);
82}
83
84#endif
85
86#include "isdnd.h"
87
88/*---------------------------------------------------------------------------*
89 *	parse rates file
90 *---------------------------------------------------------------------------*/
91int
92readrates(char *filename)
93{
94	char buffer[MAXPATHLEN];
95	register char *bp;
96	struct rates *rt, *ort;
97	int rateindx;
98	int indx;
99	int line = 0;
100	FILE *fp;
101	int first;
102#if DEBUG
103	int i, j;
104#endif
105
106	indx = 0;
107	rt = ort = NULL;
108
109	if ((fp = fopen(filename, "r")) == NULL)
110	{
111		snprintf(error, sizeof(error), "error open %s: %s", filename, sys_errlist[errno]);
112		rate_error = error;
113		return(WARNING);
114	}
115
116	while((fgets(buffer, MAXPATHLEN, fp)) != NULL)
117	{
118		line++;
119
120/* comments */
121		if (buffer[0] == '#'  || buffer[0] == ' ' ||
122		   buffer[0] == '\t' || buffer[0] == '\n')
123		{
124			continue;
125		}
126
127		bp = &buffer[0];
128
129		/* rate type */
130
131		if (*bp == 'r' && *(bp+1) == 'a' && isdigit((unsigned char)*(bp+2)))
132		{
133				rateindx = *(bp+2) - '0';
134				bp += 3;
135
136				/* eat space delimiter */
137
138				while(isspace((unsigned char)*bp))
139					bp++;
140		}
141		else
142		{
143			snprintf(error, sizeof(error), "rates: invalid rate type %c%c%c in line %d", *bp, *(bp+1), *(bp+2), line);
144			goto rate_error;
145		}
146		if (rateindx >= NRATES)
147		{
148			snprintf(error, sizeof(error), "rates: invalid rate index %d in line %d", rateindx, line);
149			goto rate_error;
150		}
151
152		/* day */
153
154		if (isdigit((unsigned char)*bp) && *bp >= '0' && *bp <= '6')
155		{
156			indx = *bp - '0';
157
158			DBGL(DL_RATES, (logit(LL_DBG, "rates: index = %d", indx)));
159		}
160		else
161		{
162			snprintf(error, sizeof(error), "rates: invalid day digit %c in line %d", *bp, line);
163			goto rate_error;
164		}
165
166		if (rates[rateindx][indx] == NULL)
167		{
168			rt = (struct rates *)malloc(sizeof (struct rates));
169			if (rt == NULL)
170			{
171				snprintf(error, sizeof(error), "rates: cannot malloc space for rate structure");
172				goto rate_error;
173		  	}
174			rt->next = NULL;
175		  	rates[rateindx][indx] = rt;
176		}
177
178		bp++;
179
180		/* eat space delimiter */
181
182		while(isspace((unsigned char)*bp))
183			bp++;
184
185		/* now loop to get the rates entries */
186
187		first = 1;
188
189		while(*bp && isdigit((unsigned char)*bp))
190		{
191			int hour = 0;
192			int min = 0;
193
194			if (first)
195			{
196				first = 0;
197			}
198			else
199			{
200				ort = rt;
201
202				rt = (struct rates *)malloc(sizeof (struct rates));
203				if (rt == NULL)
204				{
205					snprintf(error, sizeof(error), "rates: cannot malloc space2 for rate structure");
206					goto rate_error;
207			  	}
208				ort->next = rt;
209				rt->next = NULL;
210			}
211
212			/* start hour */
213
214			if (isdigit((unsigned char)*bp) && isdigit((unsigned char)*(bp+1)))
215			{
216				hour = atoi(bp);
217				bp += 2;
218			}
219		  	else
220			{
221				snprintf(error, sizeof(error), "rates: start_hr error in line %d", line);
222				goto rate_error;
223		  	}
224
225			/* point */
226
227		  	if (*bp == '.')
228		  	{
229		  		bp++;
230		  	}
231		  	else
232		  	{
233				snprintf(error, sizeof(error), "rates: no '.' after start_hr in line %d", line);
234				goto rate_error;
235			}
236
237			/* start minute */
238
239			if (isdigit((unsigned char)*bp) && isdigit((unsigned char)*(bp+1)))
240			{
241				min = atoi(bp);
242				bp += 2;
243			}
244		  	else
245			{
246				snprintf(error, sizeof(error), "rates: start_min error in line %d", line);
247				goto rate_error;
248		  	}
249
250			rt->start_time = hour*60 + min;
251
252			/* minus */
253
254		  	if (*bp == '-')
255		  	{
256		  		bp++;
257		  	}
258		  	else
259		  	{
260				snprintf(error, sizeof(error), "rates: no '-' after start_min in line %d", line);
261				goto rate_error;
262			}
263
264			/* end hour */
265
266			if (isdigit((unsigned char)*bp) && isdigit((unsigned char)*(bp+1)))
267			{
268				hour = atoi(bp);
269				bp += 2;
270			}
271		  	else
272			{
273				snprintf(error, sizeof(error), "rates: end_hr error in line %d", line);
274				goto rate_error;
275		  	}
276
277			/* point */
278
279		  	if (*bp == '.')
280		  	{
281		  		bp++;
282		  	}
283		  	else
284		  	{
285				snprintf(error, sizeof(error), "rates: no '.' after end_hr in line %d", line);
286				goto rate_error;
287			}
288
289			/* end minute */
290
291			if (isdigit((unsigned char)*bp) && isdigit((unsigned char)*(bp+1)))
292			{
293				min = atoi(bp);
294				bp += 2;
295			}
296		  	else
297			{
298				snprintf(error, sizeof(error), "rates: end_min error in line %d", line);
299				goto rate_error;
300		  	}
301
302			/* if hour is 0 assume it means midnight */
303			if ( hour == 0 )
304				hour = 24;
305			rt->end_time = hour * 60 + min;
306
307			if ( rt->end_time <= rt->start_time )
308				{
309				snprintf(error, sizeof(error), "rates: end_time must be greater than start_time %d", line);
310				goto rate_error;
311				}
312
313			/* colon */
314
315		  	if (*bp == ':')
316		  	{
317		  		bp++;
318		  	}
319		  	else
320		  	{
321				snprintf(error, sizeof(error), "rates: no ':' after end_min in line %d", line);
322				goto rate_error;
323			}
324
325			/* time */
326
327			if (isdigit((unsigned char)*bp))
328			{
329				rt->rate = atoi(bp);
330				while(!isspace((unsigned char)*bp))
331					bp++;
332			}
333		  	else
334			{
335				snprintf(error, sizeof(error), "rates: first rate digit error in line %d", line);
336				goto rate_error;
337		  	}
338
339			/* eat space delimiter */
340
341			while(isspace((unsigned char)*bp))
342				bp++;
343		}
344	}
345
346#if DEBUG
347	if (debug_flags & DL_RATES)
348	{
349		for (j = 0; j < NRATES; j++)
350		{
351			for (i = 0; i < NDAYS; i++)
352			{
353				if (rates [j][i] != NULL)
354				{
355					rt = rates [j][i];
356					for (; rt; rt = rt->next)
357					{
358						logit(LL_DBG, "rates: index %d day %d = %d.%2.2d-%d.%2.2d:%d",
359							j, i, rt->start_time/60, rt->start_time%60,
360							rt->end_time/60,rt->end_time%60,rt->rate);
361					}
362				}
363				else
364				{
365					logit(LL_DBG, "rates: NO entry for day %d !!\n", i);
366				}
367			}
368		}
369	}
370#endif
371	fclose(fp);
372	return(GOOD);
373
374rate_error:
375	fclose(fp);
376	rate_error = error;
377	return(ERROR);
378}
379
380#ifndef PARSE_DEBUG_MAIN
381
382/*---------------------------------------------------------------------------*
383 *	get unit length time from configured source
384 *---------------------------------------------------------------------------*/
385int
386get_current_rate(struct cfg_entry *cep, int dolog)
387{
388	int rt;
389
390	switch (cep->unitlengthsrc)
391	{
392	case ULSRC_CMDL:	/* specified on commandline     */
393		if (dolog)
394			logit(LL_CHD, "%05d %s rate %d sec/unit (cmdl)",
395				cep->cdid, cep->name, unit_length);
396		return(unit_length);
397		break;
398
399	case ULSRC_CONF:	/* get it from config file      */
400		if (dolog)
401			logit(LL_CHD, "%05d %s rate %d sec/unit (conf)",
402				cep->cdid, cep->name, cep->unitlength);
403		return(cep->unitlength);
404
405	case ULSRC_RATE:	/* get it dynamic from ratesfile*/
406		if (!got_rate)	/* got valid rates struct ?? */
407		{
408			if (dolog)
409				logit(LL_CHD, "%05d %s rate %d sec/unit (no ratefile)",
410					cep->cdid, cep->name, UNITLENGTH_DEFAULT);
411			return(UNITLENGTH_DEFAULT);
412		}
413		if ((cep->ratetype >= NRATES) ||
414		   (cep->ratetype == INVALID_RATE))
415		{
416			if (dolog)
417				logit(LL_CHD, "%05d %s rate %d sec/unit (rate out of range)",
418					cep->cdid, cep->name, UNITLENGTH_DEFAULT);
419			return(UNITLENGTH_DEFAULT);
420		}
421
422		if ((rt = getrate(cep->ratetype)) != -1)
423		{
424			if (dolog)
425				logit(LL_CHD, "%05d %s rate %d sec/unit (rate)",
426					cep->cdid, cep->name, rt);
427			return(rt);
428		}
429
430		if (dolog)
431			logit(LL_CHD, "%05d %s rate %d sec/unit (ratescan fail)",
432				cep->cdid, cep->name, UNITLENGTH_DEFAULT);
433
434		return(UNITLENGTH_DEFAULT);
435		break;
436
437	case ULSRC_DYN:	/* dynamically calculated from AOC */
438		if ((rt = getrate(cep->ratetype)) != -1)
439		{
440			if (dolog)
441				logit(LL_CHD, "%05d %s rate %d sec/unit (aocd, rate)",
442					cep->cdid, cep->name, rt);
443			return(rt);
444		}
445		if (dolog)
446			logit(LL_CHD, "%05d %s rate %d sec/unit (aocd, default)",
447				cep->cdid, cep->name, UNITLENGTH_DEFAULT);
448
449		return(UNITLENGTH_DEFAULT);
450		break;
451
452	default:
453		if (dolog)
454			logit(LL_CHD, "%05d %s rate %d sec/unit (unitlen unknown)",
455				cep->cdid, cep->name, UNITLENGTH_DEFAULT);
456
457		return(UNITLENGTH_DEFAULT);
458		break;
459	}
460}
461#endif /* PARSE_DEBUG_MAIN */
462
463
464/*---------------------------------------------------------------------------*
465 *	get the currently active rate
466 *---------------------------------------------------------------------------*/
467static int
468getrate(int rate_type )
469{
470	struct tm *ptr;
471	time_t now;
472	register struct rates *hd;
473	int time_now;
474
475	if ((!got_rate) ||
476	   (rate_type >= NRATES) ||
477	   (rate_type == INVALID_RATE))
478	{
479		return -1;
480	}
481
482	time(&now);			/* get current time */
483
484	ptr = localtime(&now);
485
486	time_now = ptr->tm_hour*60 + ptr->tm_min;
487
488	/* walk thru the rates for weekday until rate for current time found */
489
490	for (hd = rates[rate_type][ptr->tm_wday]; hd; hd = hd->next)
491	{
492		/* current time within window ? */
493		if ((time_now >= hd->start_time ) &&
494		    (time_now < hd->end_time ))
495		{
496			DBGL(DL_RATES, (logit(LL_DBG, "rate=%d sec/unit (day=%d, beg=%d:%2.2d, end=%d:2.2d, current=%d:%2.2d)",
497				hd->rate,
498				ptr->tm_wday,
499				hd->start_time/60, hd->start_time%60,
500				hd->end_time/60, hd->end_time%60,
501				time_now/60, time_now%60)));
502
503			return hd->rate;
504		}
505	}
506	return -1;
507}
508
509/* EOF */
510