Initial import from FreeBSD RELENG_4:
[games.git] / usr.sbin / i4b / isdnd / rates.c
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.11 2000/10/09 12:53:29 hm Exp $ 
39  *
40  * $FreeBSD: src/usr.sbin/i4b/isdnd/rates.c,v 1.6.2.2 2001/08/01 17:45:03 obrien Exp $
41  *
42  *      last edit-date: [Mon Dec 13 21:48:31 1999]
43  *
44  *---------------------------------------------------------------------------*/
45
46 static char error[256];
47
48 static 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
58 extern int got_rate;
59
60 int 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  *---------------------------------------------------------------------------*/
91 int
92 readrates(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(*(bp+2)))
132                 {
133                                 rateindx = *(bp+2) - '0';
134                                 bp += 3;
135
136                                 /* eat space delimiter */
137
138                                 while(isspace(*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(*bp) && *bp >= '0' && *bp <= '6')
155                 {
156                         indx = *bp - '0';
157
158                         DBGL(DL_RATES, (log(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(*bp))
183                         bp++;
184
185                 /* now loop to get the rates entries */
186
187                 first = 1;
188                 
189                 while(*bp && isdigit(*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(*bp) && isdigit(*(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(*bp) && isdigit(*(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(*bp) && isdigit(*(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(*bp) && isdigit(*(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 then 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(*bp))
328                         {
329                                 rt->rate = atoi(bp);
330                                 while(!isspace(*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(*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                                                 log(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                                         log(LL_DBG, "rates: NO entry for day %d !!\n", i);
366                                 }
367                         }
368                 }
369         }
370 #endif
371         fclose(fp);
372         return(GOOD);
373
374 rate_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  *---------------------------------------------------------------------------*/
385 int
386 get_current_rate(cfg_entry_t *cep, int logit)
387 {
388         int rt;
389         
390         switch(cep->unitlengthsrc)
391         {
392                 case ULSRC_CMDL:        /* specified on commandline     */
393                         if(logit)
394                                 log(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(logit)
401                                 log(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(logit)
409                                         log(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(logit)
417                                         log(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(logit)
425                                         log(LL_CHD, "%05d %s rate %d sec/unit (rate)",
426                                                 cep->cdid, cep->name, rt);
427                                 return(rt);
428                         }
429
430                         if(logit)                       
431                                 log(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(logit)
441                                         log(LL_CHD, "%05d %s rate %d sec/unit (aocd, rate)",
442                                                 cep->cdid, cep->name, rt);
443                                 return(rt);
444                         }
445                         if(logit)
446                                 log(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(logit)
454                                 log(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  *---------------------------------------------------------------------------*/
467 static int
468 getrate(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, (log(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 */