Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / usr.sbin / i4b / isdnd / rc_config.c
1 /*
2  * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  *---------------------------------------------------------------------------
26  *
27  *      i4b daemon - config file processing
28  *      -----------------------------------
29  *
30  * $FreeBSD: src/usr.sbin/i4b/isdnd/rc_config.c,v 1.6.2.3 2002/04/24 18:50:07 joerg Exp $
31  * $DragonFly: src/usr.sbin/i4b/isdnd/rc_config.c,v 1.5 2008/04/20 13:44:26 swildner Exp $
32  *
33  *      last edit-date: [Fri Jul 20 19:16:27 2001]
34  *
35  *---------------------------------------------------------------------------*/
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41
42 #include <sys/ioctl.h>
43
44 #include <net/if.h>
45
46 #include "isdnd.h"
47 #include "y.tab.h"
48
49 #include "monitor.h"
50
51 extern int entrycount;
52 extern int controllercount;
53 extern int lineno;
54 extern char *yytext;
55
56 extern FILE *yyin;
57 extern int yyparse();
58
59 static void set_config_defaults(void);
60 static void check_config(void);
61 static void print_config(void);
62 static void parse_valid(int entrycount, char *dt);
63
64 static int nregexpr = 0;
65 static int nregprog = 0;
66
67 /*---------------------------------------------------------------------------*
68  *      called from main to read and process config file
69  *---------------------------------------------------------------------------*/
70 void
71 configure(char *filename, int reread)
72 {
73         extern void reset_scanner(FILE *inputfile);
74         
75         set_config_defaults();
76
77         yyin = fopen(filename, "r");
78
79         if(yyin == NULL)
80         {
81                 dolog(LL_ERR, "cannot fopen file [%s]", filename);
82                 exit(1);
83         }
84
85         if(reread)
86         {
87                 reset_scanner(yyin);
88         }
89         
90         yyparse();
91         
92         monitor_fixup_rights();
93
94         check_config();         /* validation and consistency check */
95
96         fclose(yyin);
97
98         if(do_print)
99         {
100                 if(config_error_flag)
101                 {
102                         dolog(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
103                         exit(1);
104                 }
105                 print_config();
106                 do_exit(0);
107         }
108 }
109
110 /*---------------------------------------------------------------------------*
111  *      yacc error routine
112  *---------------------------------------------------------------------------*/
113 void
114 yyerror(const char *msg)
115 {
116         dolog(LL_ERR, "configuration error: %s at line %d, token \"%s\"", msg, lineno+1, yytext);
117         config_error_flag++;
118 }
119
120 /*---------------------------------------------------------------------------*
121  *      fill all config entries with default values
122  *---------------------------------------------------------------------------*/
123 static void
124 set_config_defaults(void)
125 {
126         cfg_entry_t *cep = &cfg_entry_tab[0];   /* ptr to config entry */
127         int i;
128
129         /* system section cleanup */
130         
131         nregprog = nregexpr = 0;
132
133         rt_prio = RTPRIO_NOTUSED;
134
135         mailer[0] = '\0';
136         mailto[0] = '\0';       
137         
138         /* clean regular expression table */
139         
140         for(i=0; i < MAX_RE; i++)
141         {
142                 if(rarr[i].re_expr)
143                         free(rarr[i].re_expr);
144                 rarr[i].re_expr = NULL;
145                 
146                 if(rarr[i].re_prog)
147                         free(rarr[i].re_prog);
148                 rarr[i].re_prog = NULL;
149
150                 rarr[i].re_flg = 0;
151         }
152
153         strcpy(rotatesuffix, "");
154         
155         /*
156          * controller table cleanup, beware: has already
157          * been setup in main, init_controller() !
158          */
159         
160         for(i=0; i < ncontroller; i++)
161         {
162                 isdn_ctrl_tab[i].protocol = PROTOCOL_DSS1;
163                 isdn_ctrl_tab[i].firmware = NULL;
164         }
165
166         /* entry section cleanup */
167         
168         for(i=0; i < CFG_ENTRY_MAX; i++, cep++)
169         {
170                 bzero(cep, sizeof(cfg_entry_t));
171
172                 /* ====== filled in at startup configuration, then static */
173
174                 sprintf(cep->name, "ENTRY%d", i);       
175
176                 cep->isdncontroller = INVALID;
177                 cep->isdnchannel = CHAN_ANY;
178
179                 cep->usrdevicename = INVALID;
180                 cep->usrdeviceunit = INVALID;
181                 
182                 cep->remote_numbers_handling = RNH_LAST;
183
184                 cep->dialin_reaction = REACT_IGNORE;
185
186                 cep->b1protocol = BPROT_NONE;
187
188                 cep->unitlength = UNITLENGTH_DEFAULT;
189
190                 cep->earlyhangup = EARLYHANGUP_DEFAULT;
191                 
192                 cep->ratetype = INVALID_RATE;
193                 
194                 cep->unitlengthsrc = ULSRC_NONE;
195
196                 cep->answerprog = ANSWERPROG_DEF;               
197
198                 cep->callbackwait = CALLBACKWAIT_MIN;
199
200                 cep->calledbackwait = CALLEDBACKWAIT_MIN;               
201
202                 cep->dialretries = DIALRETRIES_DEF;
203
204                 cep->recoverytime = RECOVERYTIME_MIN;
205         
206                 cep->dialouttype = DIALOUT_NORMAL;
207                 
208                 cep->inout = DIR_INOUT;
209                 
210                 cep->ppp_expect_auth = AUTH_UNDEF;
211                 
212                 cep->ppp_send_auth = AUTH_UNDEF;
213                 
214                 cep->ppp_auth_flags = AUTH_RECHALLENGE | AUTH_REQUIRED;
215                 
216                 /* ======== filled in after start, then dynamic */
217
218                 cep->cdid = CDID_UNUSED;
219
220                 cep->state = ST_IDLE;
221
222                 cep->aoc_valid = AOC_INVALID;
223         }
224 }
225
226 /*---------------------------------------------------------------------------*
227  *      internaly set values for ommitted controler sectin
228  *---------------------------------------------------------------------------*/
229 void
230 cfg_set_controller_default(void)
231 {
232         controllercount = 0;
233         DBGL(DL_RCCF, (dolog(LL_DBG, "[defaults, no controller section] controller %d: protocol = dss1", controllercount)));
234         isdn_ctrl_tab[controllercount].protocol = PROTOCOL_DSS1;
235 }
236
237 #define PPP_PAP         0xc023
238 #define PPP_CHAP        0xc223
239
240 static void
241 set_isppp_auth(int entry)
242 {
243         cfg_entry_t *cep = &cfg_entry_tab[entry];       /* ptr to config entry */
244
245         struct ifreq ifr;
246         struct spppreq spr;
247         int s;
248         int doioctl = 0;
249
250         if(cep->usrdevicename != BDRV_ISPPP)
251                 return;
252
253         if(cep->ppp_expect_auth == AUTH_UNDEF 
254            && cep->ppp_send_auth == AUTH_UNDEF)
255                 return;
256
257         if(cep->ppp_expect_auth == AUTH_NONE 
258            || cep->ppp_send_auth == AUTH_NONE)
259                 doioctl = 1;
260
261         if ((cep->ppp_expect_auth == AUTH_CHAP 
262              || cep->ppp_expect_auth == AUTH_PAP)
263             && cep->ppp_expect_name[0] != 0
264             && cep->ppp_expect_password[0] != 0)
265                 doioctl = 1;
266
267         if ((cep->ppp_send_auth == AUTH_CHAP || cep->ppp_send_auth == AUTH_PAP)
268                         && cep->ppp_send_name[0] != 0
269                         && cep->ppp_send_password[0] != 0)
270                 doioctl = 1;
271
272         if(!doioctl)
273                 return;
274
275         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "isp%d", cep->usrdeviceunit);
276
277         /* use a random AF to create the socket */
278         if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
279                 dolog(LL_ERR, "ERROR opening control socket at line %d!", lineno);
280                 config_error_flag++;
281                 return;
282         }
283         spr.cmd = (int)SPPPIOGDEFS;
284         ifr.ifr_data = (caddr_t)&spr;
285
286         if (ioctl(s, SIOCGIFGENERIC, &ifr) == -1) {
287                 dolog(LL_ERR, "ERROR fetching active PPP authentication info for %s at line %d!", ifr.ifr_name, lineno);
288                 close(s);
289                 config_error_flag++;
290                 return;
291         }
292         if (cep->ppp_expect_auth != AUTH_UNDEF)
293         {
294                 if(cep->ppp_expect_auth == AUTH_NONE)
295                 {
296                         spr.defs.hisauth.proto = 0;
297                 }
298                 else if ((cep->ppp_expect_auth == AUTH_CHAP 
299                           || cep->ppp_expect_auth == AUTH_PAP)
300                          && cep->ppp_expect_name[0] != 0
301                          && cep->ppp_expect_password[0] != 0)
302                 {
303                         spr.defs.hisauth.proto = cep->ppp_expect_auth == AUTH_PAP ? PPP_PAP : PPP_CHAP;
304                         strncpy(spr.defs.hisauth.name, cep->ppp_expect_name, AUTHNAMELEN);
305                         strncpy(spr.defs.hisauth.secret, cep->ppp_expect_password, AUTHKEYLEN);
306                 }
307         }
308         if (cep->ppp_send_auth != AUTH_UNDEF)
309         {
310                 if(cep->ppp_send_auth == AUTH_NONE)
311                 {
312                         spr.defs.myauth.proto = 0;
313                 }
314                 else if ((cep->ppp_send_auth == AUTH_CHAP 
315                           || cep->ppp_send_auth == AUTH_PAP)
316                          && cep->ppp_send_name[0] != 0
317                          && cep->ppp_send_password[0] != 0)
318                 {
319                         spr.defs.myauth.proto = cep->ppp_send_auth == AUTH_PAP ? PPP_PAP : PPP_CHAP;
320                         strncpy(spr.defs.myauth.name, cep->ppp_send_name, AUTHNAMELEN);
321                         strncpy(spr.defs.myauth.secret, cep->ppp_send_password, AUTHKEYLEN);
322
323                         if(cep->ppp_auth_flags & AUTH_REQUIRED)
324                                 spr.defs.hisauth.flags &= ~AUTHFLAG_NOCALLOUT;
325                         else
326                                 spr.defs.hisauth.flags |= AUTHFLAG_NOCALLOUT;
327
328                         if(cep->ppp_auth_flags & AUTH_RECHALLENGE)
329                                 spr.defs.hisauth.flags &= ~AUTHFLAG_NORECHALLENGE;
330                         else
331                                 spr.defs.hisauth.flags |= AUTHFLAG_NORECHALLENGE;
332                 }
333         }
334
335         spr.cmd = (int)SPPPIOSDEFS;
336
337         if (ioctl(s, SIOCSIFGENERIC, &ifr) == -1) {
338                 dolog(LL_ERR, "ERROR setting new PPP authentication parameters for %s at line %d!", ifr.ifr_name, lineno);
339                 config_error_flag++;
340         }
341         close(s);
342 }
343
344 /*---------------------------------------------------------------------------*
345  *      extract values from config and fill table
346  *---------------------------------------------------------------------------*/
347 void
348 cfg_setval(int keyword)
349 {
350         int i;
351         
352         switch(keyword)
353         {
354                 case ACCTALL:
355                         acct_all = yylval.booln;
356                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: acctall = %d", yylval.booln)));
357                         break;
358                         
359                 case ACCTFILE:
360                         strcpy(acctfile, yylval.str);
361                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: acctfile = %s", yylval.str)));
362                         break;
363
364                 case ALERT:
365                         if(yylval.num < MINALERT)
366                         {
367                                 yylval.num = MINALERT;
368                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: alert < %d, min = %d", entrycount, MINALERT, yylval.num)));
369                         }
370                         else if(yylval.num > MAXALERT)
371                         {
372                                 yylval.num = MAXALERT;
373                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: alert > %d, min = %d", entrycount, MAXALERT, yylval.num)));
374                         }
375                                 
376                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: alert = %d", entrycount, yylval.num)));
377                         cfg_entry_tab[entrycount].alert = yylval.num;
378                         break;
379
380                 case ALIASING:
381                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: aliasing = %d", yylval.booln)));
382                         aliasing = yylval.booln;
383                         break;
384
385                 case ALIASFNAME:
386                         strcpy(aliasfile, yylval.str);
387                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: aliasfile = %s", yylval.str)));
388                         break;
389
390                 case ANSWERPROG:
391                         if((cfg_entry_tab[entrycount].answerprog = malloc(strlen(yylval.str)+1)) == NULL)
392                         {
393                                 dolog(LL_ERR, "entry %d: answerstring, malloc failed!", entrycount);
394                                 do_exit(1);
395                         }
396                         strcpy(cfg_entry_tab[entrycount].answerprog, yylval.str);
397                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: answerprog = %s", entrycount, yylval.str)));
398                         break;
399                         
400                 case B1PROTOCOL:
401                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: b1protocol = %s", entrycount, yylval.str)));
402                         if(!(strcmp(yylval.str, "raw")))
403                                 cfg_entry_tab[entrycount].b1protocol = BPROT_NONE;
404                         else if(!(strcmp(yylval.str, "hdlc")))
405                                 cfg_entry_tab[entrycount].b1protocol = BPROT_RHDLC;
406                         else
407                         {
408                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"b1protocol\" at line %d!", lineno);
409                                 config_error_flag++;
410                         }
411                         break;
412
413                 case BEEPCONNECT:
414                         do_bell = yylval.booln;
415                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: beepconnect = %d", yylval.booln)));
416                         break;
417
418                 case BUDGETCALLBACKPERIOD:
419                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-callbackperiod = %d", entrycount, yylval.num)));
420                         cfg_entry_tab[entrycount].budget_callbackperiod = yylval.num;
421                         break;
422
423                 case BUDGETCALLBACKNCALLS:
424                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-callbackncalls = %d", entrycount, yylval.num)));
425                         cfg_entry_tab[entrycount].budget_callbackncalls = yylval.num;
426                         break;
427                         
428                 case BUDGETCALLOUTPERIOD:
429                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-calloutperiod = %d", entrycount, yylval.num)));
430                         cfg_entry_tab[entrycount].budget_calloutperiod = yylval.num;
431                         break;
432
433                 case BUDGETCALLOUTNCALLS:
434                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-calloutncalls = %d", entrycount, yylval.num)));
435                         cfg_entry_tab[entrycount].budget_calloutncalls = yylval.num;
436                         break;
437
438                 case BUDGETCALLBACKSFILEROTATE:
439                         cfg_entry_tab[entrycount].budget_callbacksfile_rotate = yylval.booln;
440                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-callbacksfile-rotate = %d", entrycount, yylval.booln)));
441                         break;
442                         
443                 case BUDGETCALLBACKSFILE:
444                         {
445                                 FILE *fp;
446                                 int s, l;
447                                 int n;
448                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-callbacksfile = %s", entrycount, yylval.str)));
449                                 fp = fopen(yylval.str, "r");
450                                 if(fp != NULL)
451                                 {
452                                         if((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3)
453                                         {
454                                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: initializing budget-callbacksfile %s", entrycount, yylval.str)));
455                                                 fclose(fp);
456                                                 fp = fopen(yylval.str, "w");
457                                                 if(fp != NULL)
458                                                 {
459                                                         fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
460                                                         fclose(fp);
461                                                 }
462                                         }
463                                 }
464                                 else
465                                 {
466                                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: creating budget-callbacksfile %s", entrycount, yylval.str)));
467                                         fp = fopen(yylval.str, "w");
468                                         if(fp != NULL)
469                                         {
470                                                 fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
471                                                 fclose(fp);
472                                         }
473                                 }
474
475                                 fp = fopen(yylval.str, "r");
476                                 if(fp != NULL)
477                                 {
478                                         if((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3)
479                                         {
480                                                 if((cfg_entry_tab[entrycount].budget_callbacks_file = malloc(strlen(yylval.str)+1)) == NULL)
481                                                 {
482                                                         dolog(LL_ERR, "entry %d: budget-callbacksfile, malloc failed!", entrycount);
483                                                         do_exit(1);
484                                                 }
485                                                 strcpy(cfg_entry_tab[entrycount].budget_callbacks_file, yylval.str);
486                                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: using callbacksfile %s", entrycount, yylval.str)));
487                                         }
488                                         fclose(fp);
489                                 }
490                         }
491                         break;
492
493                 case BUDGETCALLOUTSFILEROTATE:
494                         cfg_entry_tab[entrycount].budget_calloutsfile_rotate = yylval.booln;
495                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-calloutsfile-rotate = %d", entrycount, yylval.booln)));
496                         break;
497
498                 case BUDGETCALLOUTSFILE:
499                         {
500                                 FILE *fp;
501                                 int s, l;
502                                 int n;
503                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: budget-calloutsfile = %s", entrycount, yylval.str)));
504                                 fp = fopen(yylval.str, "r");
505                                 if(fp != NULL)
506                                 {
507                                         if((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) != 3)
508                                         {
509                                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: initializing budget-calloutsfile %s", entrycount, yylval.str)));
510                                                 fclose(fp);
511                                                 fp = fopen(yylval.str, "w");
512                                                 if(fp != NULL)
513                                                 {
514                                                         fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
515                                                         fclose(fp);
516                                                 }
517                                         }
518                                 }
519                                 else
520                                 {
521                                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: creating budget-calloutsfile %s", entrycount, yylval.str)));
522                                         fp = fopen(yylval.str, "w");
523                                         if(fp != NULL)
524                                         {
525                                                 fprintf(fp, "%d %d %d", (int)time(NULL), (int)time(NULL), 0);
526                                                 fclose(fp);
527                                         }
528                                 }
529
530                                 fp = fopen(yylval.str, "r");
531                                 if(fp != NULL)
532                                 {
533                                         if((fscanf(fp, "%d %d %d", (int *)&s, (int *)&l, &n)) == 3)
534                                         {
535                                                 if((cfg_entry_tab[entrycount].budget_callouts_file = malloc(strlen(yylval.str)+1)) == NULL)
536                                                 {
537                                                         dolog(LL_ERR, "entry %d: budget-calloutsfile, malloc failed!", entrycount);
538                                                         do_exit(1);
539                                                 }
540                                                 strcpy(cfg_entry_tab[entrycount].budget_callouts_file, yylval.str);
541                                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: using calloutsfile %s", entrycount, yylval.str)));
542                                         }
543                                         fclose(fp);
544                                 }
545                         }
546                         break;
547                 
548                 case CALLBACKWAIT:
549                         if(yylval.num < CALLBACKWAIT_MIN)
550                         {
551                                 yylval.num = CALLBACKWAIT_MIN;
552                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: callbackwait < %d, min = %d", entrycount, CALLBACKWAIT_MIN, yylval.num)));
553                         }
554
555                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: callbackwait = %d", entrycount, yylval.num)));
556                         cfg_entry_tab[entrycount].callbackwait = yylval.num;
557                         break;
558                         
559                 case CALLEDBACKWAIT:
560                         if(yylval.num < CALLEDBACKWAIT_MIN)
561                         {
562                                 yylval.num = CALLEDBACKWAIT_MIN;
563                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: calledbackwait < %d, min = %d", entrycount, CALLEDBACKWAIT_MIN, yylval.num)));
564                         }
565
566                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: calledbackwait = %d", entrycount, yylval.num)));
567                         cfg_entry_tab[entrycount].calledbackwait = yylval.num;
568                         break;
569
570                 case CLONE:
571                     /*
572                      *  clone = <entryname>
573                      *      Loads the entry from the named, existing one.
574                      *      Fields such as name and usrdeviceunit should
575                      *      always be specified after clone as they must be
576                      *      unique.
577                      *
578                      *  NOTE: all malloc()'d fields must be dup()'d here,
579                      *  we can't have multiple references to same storage.
580                      */
581                     for (i = 0; i < entrycount; i++)
582                         if (!strcmp(cfg_entry_tab[i].name, yylval.str))
583                             break;
584                     if (i == entrycount) {
585                         dolog(LL_ERR, "entry %d: clone, unknown entry %s!", entrycount, yylval.str);
586                         do_exit(1);
587                     }
588                     
589                     DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: clone = %s", entrycount, yylval.str)));
590
591                     memcpy(&cfg_entry_tab[entrycount], &cfg_entry_tab[i],
592                            sizeof(cfg_entry_tab[0]));
593
594                     if (cfg_entry_tab[entrycount].answerprog)
595                         cfg_entry_tab[entrycount].answerprog = strdup(cfg_entry_tab[entrycount].answerprog);
596                     if (cfg_entry_tab[entrycount].budget_callbacks_file)
597                         cfg_entry_tab[entrycount].budget_callbacks_file = strdup(cfg_entry_tab[entrycount].budget_callbacks_file);
598                     if (cfg_entry_tab[entrycount].budget_callouts_file)
599                         cfg_entry_tab[entrycount].budget_callouts_file = strdup(cfg_entry_tab[entrycount].budget_callouts_file);
600                     if (cfg_entry_tab[entrycount].connectprog)
601                         cfg_entry_tab[entrycount].connectprog = strdup(cfg_entry_tab[entrycount].connectprog);
602                     if (cfg_entry_tab[entrycount].disconnectprog)
603                         cfg_entry_tab[entrycount].disconnectprog = strdup(cfg_entry_tab[entrycount].disconnectprog);
604                     break;
605
606                 case CONNECTPROG:
607                         if((cfg_entry_tab[entrycount].connectprog = malloc(strlen(yylval.str)+1)) == NULL)
608                         {
609                                 dolog(LL_ERR, "entry %d: connectprog, malloc failed!", entrycount);
610                                 do_exit(1);
611                         }
612                         strcpy(cfg_entry_tab[entrycount].connectprog, yylval.str);
613                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: connectprog = %s", entrycount, yylval.str)));
614                         break;
615                         
616                 case DIALOUTTYPE:
617                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: dialouttype = %s", entrycount, yylval.str)));
618                         if(!(strcmp(yylval.str, "normal")))
619                                 cfg_entry_tab[entrycount].dialouttype = DIALOUT_NORMAL;
620                         else if(!(strcmp(yylval.str, "calledback")))
621                                 cfg_entry_tab[entrycount].dialouttype = DIALOUT_CALLEDBACK;
622                         else
623                         {
624                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialout-type\" at line %d!", lineno);
625                                 config_error_flag++;
626                         }
627                         break;
628
629                 case DIALRETRIES:
630                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: dialretries = %d", entrycount, yylval.num)));
631                         cfg_entry_tab[entrycount].dialretries = yylval.num;
632                         break;
633
634                 case DIALRANDINCR:
635                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: dialrandincr = %d", entrycount, yylval.booln)));
636                         cfg_entry_tab[entrycount].dialrandincr = yylval.booln;
637                         break;
638
639                 case DIRECTION:
640                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: direction = %s", entrycount, yylval.str)));
641
642                         if(!(strcmp(yylval.str, "inout")))
643                                 cfg_entry_tab[entrycount].inout = DIR_INOUT;
644                         else if(!(strcmp(yylval.str, "in")))
645                                 cfg_entry_tab[entrycount].inout = DIR_INONLY;
646                         else if(!(strcmp(yylval.str, "out")))
647                                 cfg_entry_tab[entrycount].inout = DIR_OUTONLY;
648                         else
649                         {
650                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"direction\" at line %d!", lineno);
651                                 config_error_flag++;
652                         }
653                         break;
654
655                 case DISCONNECTPROG:
656                         if((cfg_entry_tab[entrycount].disconnectprog = malloc(strlen(yylval.str)+1)) == NULL)
657                         {
658                                 dolog(LL_ERR, "entry %d: disconnectprog, malloc failed!", entrycount);
659                                 do_exit(1);
660                         }
661                         strcpy(cfg_entry_tab[entrycount].disconnectprog, yylval.str);
662                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: disconnectprog = %s", entrycount, yylval.str)));
663                         break;
664
665                 case DOWNTRIES:
666                         if(yylval.num > DOWN_TRIES_MAX)
667                                 yylval.num = DOWN_TRIES_MAX;
668                         else if(yylval.num < DOWN_TRIES_MIN)
669                                 yylval.num = DOWN_TRIES_MIN;
670                 
671                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: downtries = %d", entrycount, yylval.num)));
672                         cfg_entry_tab[entrycount].downtries = yylval.num;
673                         break;
674
675                 case DOWNTIME:
676                         if(yylval.num > DOWN_TIME_MAX)
677                                 yylval.num = DOWN_TIME_MAX;
678                         else if(yylval.num < DOWN_TIME_MIN)
679                                 yylval.num = DOWN_TIME_MIN;
680                 
681                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: downtime = %d", entrycount, yylval.num)));
682                         cfg_entry_tab[entrycount].downtime = yylval.num;
683                         break;
684
685                 case EARLYHANGUP:
686                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: earlyhangup = %d", entrycount, yylval.num)));
687                         cfg_entry_tab[entrycount].earlyhangup = yylval.num;
688                         break;
689
690                 case EXTCALLATTR:
691                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: extcallattr = %d", yylval.booln)));
692                         extcallattr = yylval.booln;
693                         break;
694
695                 case FIRMWARE:
696                         DBGL(DL_RCCF, (dolog(LL_DBG, "controller %d: firmware = %s", controllercount, yylval.str)));
697                         isdn_ctrl_tab[controllercount].firmware = strdup(yylval.str);
698                         break;
699
700                 case HOLIDAYFILE:
701                         strcpy(holidayfile, yylval.str);
702                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: holidayfile = %s", yylval.str)));
703                         break;
704
705                 case IDLE_ALG_OUT:
706                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: idle-algorithm-outgoing = %s", entrycount, yylval.str)));
707
708                         if(!(strcmp(yylval.str, "fix-unit-size")))
709                         {
710                                 cfg_entry_tab[entrycount].shorthold_algorithm = SHA_FIXU;
711                         }
712                         else if(!(strcmp(yylval.str, "var-unit-size")))
713                         {
714                                 cfg_entry_tab[entrycount].shorthold_algorithm = SHA_VARU;
715                         }
716                         else
717                         {
718                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"idle-algorithm-outgoing\" at line %d!", lineno);
719                                 config_error_flag++;
720                         }
721                         break;
722
723                 case IDLETIME_IN:
724                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: idle_time_in = %d", entrycount, yylval.num)));
725                         cfg_entry_tab[entrycount].idle_time_in = yylval.num;
726                         break;
727                         
728                 case IDLETIME_OUT:
729                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: idle_time_out = %d", entrycount, yylval.num)));
730                         cfg_entry_tab[entrycount].idle_time_out = yylval.num;
731                         break;
732
733                 case ISDNCONTROLLER:
734                         cfg_entry_tab[entrycount].isdncontroller = yylval.num;
735                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: isdncontroller = %d", entrycount, yylval.num)));
736                         break;
737
738                 case ISDNCHANNEL:
739                         if (yylval.num == 0 || yylval.num == -1)
740                         {
741                                         cfg_entry_tab[entrycount].isdnchannel = CHAN_ANY;
742                                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: isdnchannel = any", entrycount)));
743                         }
744                         else if (yylval.num > MAX_BCHAN)
745                         {
746                                         dolog(LL_DBG, "entry %d: isdnchannel value out of range", entrycount);
747                                         config_error_flag++;
748                         }
749                         else
750                         {
751                             cfg_entry_tab[entrycount].isdnchannel = yylval.num-1;
752                             DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: isdnchannel = B%d", entrycount, yylval.num)));
753                         }
754                         break;
755
756                 case ISDNTIME:
757                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: isdntime = %d", yylval.booln)));
758                         isdntime = yylval.booln;
759                         break;
760
761                 case ISDNTXDELIN:
762                         cfg_entry_tab[entrycount].isdntxdelin = yylval.num;
763                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: isdntxdel-incoming = %d", entrycount, yylval.num)));
764                         break;
765
766                 case ISDNTXDELOUT:
767                         cfg_entry_tab[entrycount].isdntxdelout = yylval.num;
768                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: isdntxdel-outgoing = %d", entrycount, yylval.num)));
769                         break;
770
771                 case LOCAL_PHONE_DIALOUT:
772                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: local_phone_dialout = %s", entrycount, yylval.str)));
773                         strcpy(cfg_entry_tab[entrycount].local_phone_dialout, yylval.str);
774                         break;
775
776                 case LOCAL_PHONE_INCOMING:
777                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: local_phone_incoming = %s", entrycount, yylval.str)));
778                         strcpy(cfg_entry_tab[entrycount].local_phone_incoming, yylval.str);
779                         break;
780
781                 case MAILER:
782                         strcpy(mailer, yylval.str);
783                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: mailer = %s", yylval.str)));
784                         break;
785
786                 case MAILTO:
787                         strcpy(mailto, yylval.str);
788                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: mailto = %s", yylval.str)));
789                         break;
790
791                 case MAXCONNECTTIME:
792                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: maxconnecttime = %d", entrycount, yylval.num)));
793                         cfg_entry_tab[entrycount].maxconnecttime = yylval.num;
794                         break;
795
796                 case MONITORPORT:
797                         monitorport = yylval.num;
798                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: monitorport = %d", yylval.num)));
799                         break;
800
801                 case MONITORSW:
802                         if (yylval.booln && inhibit_monitor)
803                         {
804                                 do_monitor = 0;
805                                 DBGL(DL_RCCF, (dolog(LL_DBG, "system: monitor-enable overridden by command line flag")));
806                         }
807                         else
808                         {
809                                 do_monitor = yylval.booln;
810                                 DBGL(DL_RCCF, (dolog(LL_DBG, "system: monitor-enable = %d", yylval.booln)));
811                         }
812                         break;
813
814                 case NAME:
815                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: name = %s", entrycount, yylval.str)));
816                         strcpy(cfg_entry_tab[entrycount].name, yylval.str);
817                         break;
818
819                 case PPP_AUTH_RECHALLENGE:
820                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-auth-rechallenge = %d", entrycount, yylval.booln)));
821                         if(yylval.booln)
822                                 cfg_entry_tab[entrycount].ppp_auth_flags |= AUTH_RECHALLENGE;
823                         else
824                                 cfg_entry_tab[entrycount].ppp_auth_flags &= ~AUTH_RECHALLENGE;
825                         set_isppp_auth(entrycount);
826                         break;
827
828                 case PPP_AUTH_PARANOID:
829                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-auth-paranoid = %d", entrycount, yylval.booln)));
830                         if(yylval.booln)
831                                 cfg_entry_tab[entrycount].ppp_auth_flags |= AUTH_REQUIRED;
832                         else
833                                 cfg_entry_tab[entrycount].ppp_auth_flags &= ~AUTH_REQUIRED;
834                         set_isppp_auth(entrycount);
835                         break;
836
837                 case PPP_EXPECT_AUTH:
838                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-expect-auth = %s", entrycount, yylval.str)));
839                         if(!(strcmp(yylval.str, "none")))
840                                 cfg_entry_tab[entrycount].ppp_expect_auth = AUTH_NONE;
841                         else if(!(strcmp(yylval.str, "pap")))
842                                 cfg_entry_tab[entrycount].ppp_expect_auth = AUTH_PAP;
843                         else if(!(strcmp(yylval.str, "chap")))
844                                 cfg_entry_tab[entrycount].ppp_expect_auth = AUTH_CHAP;
845                         else
846                         {
847                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"ppp-expect-auth\" at line %d!", lineno);
848                                 config_error_flag++;
849                                 break;
850                         }
851                         set_isppp_auth(entrycount);
852                         break;
853
854                 case PPP_EXPECT_NAME:
855                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-expect-name = %s", entrycount, yylval.str)));
856                         strncpy(cfg_entry_tab[entrycount].ppp_expect_name, yylval.str, sizeof(cfg_entry_tab[entrycount].ppp_expect_name) -1);
857                         set_isppp_auth(entrycount);
858                         break;
859
860                 case PPP_EXPECT_PASSWORD:
861                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-expect-password = %s", entrycount, yylval.str)));
862                         strncpy(cfg_entry_tab[entrycount].ppp_expect_password, yylval.str, sizeof(cfg_entry_tab[entrycount].ppp_expect_password) -1);
863                         set_isppp_auth(entrycount);
864                         break;
865
866                 case PPP_SEND_AUTH:
867                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-send-auth = %s", entrycount, yylval.str)));
868                         if(!(strcmp(yylval.str, "none")))
869                                 cfg_entry_tab[entrycount].ppp_send_auth = AUTH_NONE;
870                         else if(!(strcmp(yylval.str, "pap")))
871                                 cfg_entry_tab[entrycount].ppp_send_auth = AUTH_PAP;
872                         else if(!(strcmp(yylval.str, "chap")))
873                                 cfg_entry_tab[entrycount].ppp_send_auth = AUTH_CHAP;
874                         else
875                         {
876                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"ppp-send-auth\" at line %d!", lineno);
877                                 config_error_flag++;
878                                 break;
879                         }
880                         set_isppp_auth(entrycount);
881                         break;
882
883                 case PPP_SEND_NAME:
884                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-send-name = %s", entrycount, yylval.str)));
885                         strncpy(cfg_entry_tab[entrycount].ppp_send_name, yylval.str, sizeof(cfg_entry_tab[entrycount].ppp_send_name) -1);
886                         set_isppp_auth(entrycount);
887                         break;
888
889                 case PPP_SEND_PASSWORD:
890                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ppp-send-password = %s", entrycount, yylval.str)));
891                         strncpy(cfg_entry_tab[entrycount].ppp_send_password, yylval.str, sizeof(cfg_entry_tab[entrycount].ppp_send_password) -1);
892                         set_isppp_auth(entrycount);
893                         break;
894
895                 case PROTOCOL:
896                         DBGL(DL_RCCF, (dolog(LL_DBG, "controller %d: protocol = %s", controllercount, yylval.str)));
897                         if(!(strcmp(yylval.str, "dss1")))
898                                 isdn_ctrl_tab[controllercount].protocol = PROTOCOL_DSS1;
899                         else if(!(strcmp(yylval.str, "d64s")))
900                                 isdn_ctrl_tab[controllercount].protocol = PROTOCOL_D64S;
901                         else
902                         {
903                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"protocol\" at line %d!", lineno);
904                                 config_error_flag++;
905                         }
906                         break;
907
908                 case REACTION:
909                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: dialin_reaction = %s", entrycount, yylval.str)));
910                         if(!(strcmp(yylval.str, "accept")))
911                                 cfg_entry_tab[entrycount].dialin_reaction = REACT_ACCEPT;
912                         else if(!(strcmp(yylval.str, "reject")))
913                                 cfg_entry_tab[entrycount].dialin_reaction = REACT_REJECT;
914                         else if(!(strcmp(yylval.str, "ignore")))
915                                 cfg_entry_tab[entrycount].dialin_reaction = REACT_IGNORE;
916                         else if(!(strcmp(yylval.str, "answer")))
917                                 cfg_entry_tab[entrycount].dialin_reaction = REACT_ANSWER;
918                         else if(!(strcmp(yylval.str, "callback")))
919                                 cfg_entry_tab[entrycount].dialin_reaction = REACT_CALLBACK;
920                         else
921                         {
922                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"dialin_reaction\" at line %d!", lineno);
923                                 config_error_flag++;
924                         }
925                         break;
926
927                 case REMOTE_PHONE_DIALOUT:
928                         if(cfg_entry_tab[entrycount].remote_numbers_count >= MAXRNUMBERS)
929                         {
930                                 dolog(LL_ERR, "ERROR parsing config file: too many remote numbers at line %d!", lineno);
931                                 config_error_flag++;
932                                 break;
933                         }                               
934                         
935                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: remote_phone_dialout #%d = %s",
936                                 entrycount, cfg_entry_tab[entrycount].remote_numbers_count, yylval.str)));
937
938                         strcpy(cfg_entry_tab[entrycount].remote_numbers[cfg_entry_tab[entrycount].remote_numbers_count].number, yylval.str);
939                         cfg_entry_tab[entrycount].remote_numbers[cfg_entry_tab[entrycount].remote_numbers_count].flag = 0;
940
941                         cfg_entry_tab[entrycount].remote_numbers_count++;
942                         
943                         break;
944
945                 case REMOTE_NUMBERS_HANDLING:                   
946                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: remdial_handling = %s", entrycount, yylval.str)));
947                         if(!(strcmp(yylval.str, "next")))
948                                 cfg_entry_tab[entrycount].remote_numbers_handling = RNH_NEXT;
949                         else if(!(strcmp(yylval.str, "last")))
950                                 cfg_entry_tab[entrycount].remote_numbers_handling = RNH_LAST;
951                         else if(!(strcmp(yylval.str, "first")))
952                                 cfg_entry_tab[entrycount].remote_numbers_handling = RNH_FIRST;
953                         else
954                         {
955                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"remdial_handling\" at line %d!", lineno);
956                                 config_error_flag++;
957                         }
958                         break;
959
960                 case REMOTE_PHONE_INCOMING:
961                         {
962                                 int n;
963                                 n = cfg_entry_tab[entrycount].incoming_numbers_count;
964                                 if (n >= MAX_INCOMING)
965                                 {
966                                         dolog(LL_ERR, "ERROR parsing config file: too many \"remote_phone_incoming\" entries at line %d!", lineno);
967                                         config_error_flag++;
968                                         break;
969                                 }
970                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: remote_phone_incoming #%d = %s", entrycount, n, yylval.str)));
971                                 strcpy(cfg_entry_tab[entrycount].remote_phone_incoming[n].number, yylval.str);
972                                 cfg_entry_tab[entrycount].incoming_numbers_count++;
973                         }
974                         break;
975
976                 case RATESFILE:
977                         strcpy(ratesfile, yylval.str);
978                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: ratesfile = %s", yylval.str)));
979                         break;
980
981                 case RATETYPE:
982                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: ratetype = %d", entrycount, yylval.num)));
983                         cfg_entry_tab[entrycount].ratetype = yylval.num;
984                         break;
985                 
986                 case RECOVERYTIME:
987                         if(yylval.num < RECOVERYTIME_MIN)
988                         {
989                                 yylval.num = RECOVERYTIME_MIN;
990                                 DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: recoverytime < %d, min = %d", entrycount, RECOVERYTIME_MIN, yylval.num)));
991                         }
992
993                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: recoverytime = %d", entrycount, yylval.num)));
994                         cfg_entry_tab[entrycount].recoverytime = yylval.num;
995                         break;
996                 
997                 case REGEXPR:
998                         if(nregexpr >= MAX_RE)
999                         {
1000                                 dolog(LL_ERR, "system: regexpr #%d >= MAX_RE", nregexpr);
1001                                 config_error_flag++;
1002                                 break;
1003                         }
1004
1005                         if((i = regcomp(&(rarr[nregexpr].re), yylval.str, REG_EXTENDED|REG_NOSUB)) != 0)
1006                         {
1007                                 char buf[256];
1008                                 regerror(i, &(rarr[nregexpr].re), buf, sizeof(buf));
1009                                 dolog(LL_ERR, "system: regcomp error for %s: [%s]", yylval.str, buf);
1010                                 config_error_flag++;
1011                                 break;
1012                         }
1013                         else
1014                         {
1015                                 if((rarr[nregexpr].re_expr = malloc(strlen(yylval.str)+1)) == NULL)
1016                                 {
1017                                         dolog(LL_ERR, "system: regexpr malloc error error for %s", yylval.str);
1018                                         config_error_flag++;
1019                                         break;
1020                                 }
1021                                 strcpy(rarr[nregexpr].re_expr, yylval.str);
1022
1023                                 DBGL(DL_RCCF, (dolog(LL_DBG, "system: regexpr %s stored into slot %d", yylval.str, nregexpr)));
1024                                 
1025                                 if(rarr[nregexpr].re_prog != NULL)
1026                                         rarr[nregexpr].re_flg = 1;
1027                                 
1028                                 nregexpr++;
1029                                 
1030                         }
1031                         break;
1032
1033                 case REGPROG:
1034                         if(nregprog >= MAX_RE)
1035                         {
1036                                 dolog(LL_ERR, "system: regprog #%d >= MAX_RE", nregprog);
1037                                 config_error_flag++;
1038                                 break;
1039                         }
1040                         if((rarr[nregprog].re_prog = malloc(strlen(yylval.str)+1)) == NULL)
1041                         {
1042                                 dolog(LL_ERR, "system: regprog malloc error error for %s", yylval.str);
1043                                 config_error_flag++;
1044                                 break;
1045                         }
1046                         strcpy(rarr[nregprog].re_prog, yylval.str);
1047
1048                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: regprog %s stored into slot %d", yylval.str, nregprog)));
1049                         
1050                         if(rarr[nregprog].re_expr != NULL)
1051                                 rarr[nregprog].re_flg = 1;
1052
1053                         nregprog++;
1054                         break;
1055
1056                 case ROTATESUFFIX:
1057                         strcpy(rotatesuffix, yylval.str);
1058                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: rotatesuffix = %s", yylval.str)));
1059                         break;
1060
1061                 case RTPRIO:
1062 #ifdef USE_RTPRIO
1063                         rt_prio = yylval.num;
1064                         if(rt_prio < RTP_PRIO_MIN || rt_prio > RTP_PRIO_MAX)
1065                         {
1066                                 config_error_flag++;
1067                                 dolog(LL_ERR, "system: error, rtprio (%d) out of range!", yylval.num);
1068                         }
1069                         else
1070                         {
1071                                 DBGL(DL_RCCF, (dolog(LL_DBG, "system: rtprio = %d", yylval.num)));
1072                         }
1073 #else
1074                         rt_prio = RTPRIO_NOTUSED;
1075 #endif
1076                         break;
1077
1078                 case TINAINITPROG:
1079                         strcpy(tinainitprog, yylval.str);
1080                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: tinainitprog = %s", yylval.str)));
1081                         break;
1082
1083                 case UNITLENGTH:
1084                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: unitlength = %d", entrycount, yylval.num)));
1085                         cfg_entry_tab[entrycount].unitlength = yylval.num;
1086                         break;
1087
1088                 case UNITLENGTHSRC:
1089                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: unitlengthsrc = %s", entrycount, yylval.str)));
1090                         if(!(strcmp(yylval.str, "none")))
1091                                 cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_NONE;
1092                         else if(!(strcmp(yylval.str, "cmdl")))
1093                                 cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_CMDL;
1094                         else if(!(strcmp(yylval.str, "conf")))
1095                                 cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_CONF;
1096                         else if(!(strcmp(yylval.str, "rate")))
1097                                 cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_RATE;
1098                         else if(!(strcmp(yylval.str, "aocd")))
1099                                 cfg_entry_tab[entrycount].unitlengthsrc = ULSRC_DYN;
1100                         else
1101                         {
1102                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"unitlengthsrc\" at line %d!", lineno);
1103                                 config_error_flag++;
1104                         }
1105                         break;
1106
1107                 case USRDEVICENAME:
1108                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: usrdevicename = %s", entrycount, yylval.str)));
1109                         if(!strcmp(yylval.str, "rbch"))
1110                                 cfg_entry_tab[entrycount].usrdevicename = BDRV_RBCH;
1111                         else if(!strcmp(yylval.str, "tel"))
1112                                 cfg_entry_tab[entrycount].usrdevicename = BDRV_TEL;
1113                         else if(!strcmp(yylval.str, "ipr"))
1114                                 cfg_entry_tab[entrycount].usrdevicename = BDRV_IPR;
1115                         else if(!strcmp(yylval.str, "isp"))
1116                                 cfg_entry_tab[entrycount].usrdevicename = BDRV_ISPPP;
1117 #ifdef __bsdi__
1118                         else if(!strcmp(yylval.str, "ibc"))
1119                                 cfg_entry_tab[entrycount].usrdevicename = BDRV_IBC;
1120 #endif
1121                         else if(!strcmp(yylval.str, "ing"))
1122                                 cfg_entry_tab[entrycount].usrdevicename = BDRV_ING;
1123                         else
1124                         {
1125                                 dolog(LL_ERR, "ERROR parsing config file: unknown parameter for keyword \"usrdevicename\" at line %d!", lineno);
1126                                 config_error_flag++;
1127                         }
1128                         break;
1129
1130                 case USRDEVICEUNIT:
1131                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: usrdeviceunit = %d", entrycount, yylval.num)));
1132                         cfg_entry_tab[entrycount].usrdeviceunit = yylval.num;
1133                         break;
1134
1135                 case USEACCTFILE:
1136                         useacctfile = yylval.booln;
1137                         DBGL(DL_RCCF, (dolog(LL_DBG, "system: useacctfile = %d", yylval.booln)));
1138                         break;
1139
1140                 case USEDOWN:
1141                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: usedown = %d", entrycount, yylval.booln)));
1142                         cfg_entry_tab[entrycount].usedown = yylval.booln;
1143                         break;
1144
1145                 case VALID:
1146                         DBGL(DL_RCCF, (dolog(LL_DBG, "entry %d: valid = %s", entrycount, yylval.str)));
1147                         parse_valid(entrycount, yylval.str);
1148                         break;
1149
1150                 default:
1151                         dolog(LL_ERR, "ERROR parsing config file: unknown keyword at line %d!", lineno);
1152                         config_error_flag++;
1153                         break;                  
1154         }
1155 }
1156
1157 /*---------------------------------------------------------------------------*
1158  *      parse a date/time range
1159  *---------------------------------------------------------------------------*/
1160 static void
1161 parse_valid(int entrycount, char *dt)
1162 {
1163         /* a valid string consists of some days of week separated by
1164          * commas, where 0=sunday, 1=monday .. 6=saturday and a special
1165          * value of 7 which is a holiday from the holiday file.
1166          * after the days comes an optional (!) time range in the form
1167          * aa:bb-cc:dd, this format is fixed to be parsable by sscanf.
1168          * Valid specifications looks like this:
1169          * 1,2,3,4,5,09:00-18:00        Monday-Friday 9-18h
1170          * 1,2,3,4,5,18:00-09:00        Monday-Friday 18-9h
1171          * 6                            Saturday (whole day)
1172          * 0,7                          Sunday and Holidays
1173          */
1174
1175         int day = 0;
1176         int fromhr = 0;
1177         int frommin = 0;
1178         int tohr = 0;
1179         int tomin = 0;
1180         int ret;
1181         
1182         for(;;)
1183         {
1184                 if( ( ((*dt >= '0') && (*dt <= '9')) && (*(dt+1) == ':') ) ||
1185                     ( ((*dt >= '0') && (*dt <= '2')) && ((*(dt+1) >= '0') && (*(dt+1) <= '9')) && (*(dt+2) == ':') ) )
1186                 {
1187                         /* dt points to time spec */
1188                         ret = sscanf(dt, "%d:%d-%d:%d", &fromhr, &frommin, &tohr, &tomin);
1189                         if(ret !=4)
1190                         {
1191                                 dolog(LL_ERR, "ERROR parsing config file: timespec [%s] error at line %d!", *dt, lineno);
1192                                 config_error_flag++;
1193                                 return;
1194                         }
1195
1196                         if(fromhr < 0 || fromhr > 24 || tohr < 0 || tohr > 24 ||
1197                            frommin < 0 || frommin > 59 || tomin < 0 || tomin > 59)
1198                         {
1199                                 dolog(LL_ERR, "ERROR parsing config file: invalid time [%s] at line %d!", *dt, lineno);
1200                                 config_error_flag++;
1201                                 return;
1202                         }
1203                         break;
1204                 }
1205                 else if ((*dt >= '0') && (*dt <= '7'))
1206                 {
1207                         /* dt points to day spec */
1208                         day |= 1 << (*dt - '0');
1209                         dt++;
1210                         continue;
1211                 }
1212                 else if (*dt == ',')
1213                 {
1214                         /* dt points to delimiter */
1215                         dt++;
1216                         continue;
1217                 }
1218                 else if (*dt == '\0')
1219                 {
1220                         /* dt points to end of string */
1221                         break;
1222                 }
1223                 else
1224                 {
1225                         /* dt points to illegal character */
1226                         dolog(LL_ERR, "ERROR parsing config file: illegal character [%c=0x%x] in date/time spec at line %d!", *dt, *dt, lineno);
1227                         config_error_flag++;
1228                         return;
1229                 }
1230         }
1231         cfg_entry_tab[entrycount].day = day;
1232         cfg_entry_tab[entrycount].fromhr = fromhr;
1233         cfg_entry_tab[entrycount].frommin = frommin;
1234         cfg_entry_tab[entrycount].tohr = tohr;
1235         cfg_entry_tab[entrycount].tomin = tomin;
1236 }
1237
1238 /*---------------------------------------------------------------------------*
1239  *      configuration validation and consistency check
1240  *---------------------------------------------------------------------------*/
1241 static void
1242 check_config(void)
1243 {
1244         cfg_entry_t *cep = &cfg_entry_tab[0];   /* ptr to config entry */
1245         int i;
1246         int error = 0;
1247
1248         /* regular expression table */
1249         
1250         for(i=0; i < MAX_RE; i++)
1251         {
1252                 if((rarr[i].re_expr != NULL) && (rarr[i].re_prog == NULL))
1253                 {
1254                         dolog(LL_ERR, "check_config: regular expression %d without program!", i);
1255                         error++;
1256                 }
1257                 if((rarr[i].re_prog != NULL) && (rarr[i].re_expr == NULL))
1258                 {
1259                         dolog(LL_ERR, "check_config: regular expression program %d without expression!", i);
1260                         error++;
1261                 }
1262         }
1263
1264         /* entry sections */
1265         
1266         for(i=0; i <= entrycount; i++, cep++)
1267         {
1268                 /* isdn controller number */
1269
1270                 if((cep->isdncontroller < -1) || (cep->isdncontroller > (ncontroller-1)))
1271                 {
1272                         dolog(LL_ERR, "check_config: WARNING, isdncontroller out of range in entry %d!", i);
1273                 }
1274
1275                 /* numbers used for dialout */
1276                 
1277                 if((cep->inout != DIR_INONLY) && (cep->dialin_reaction != REACT_ANSWER))
1278                 {
1279                         if(cep->remote_numbers_count == 0)
1280                         {
1281                                 dolog(LL_ERR, "check_config: remote-phone-dialout not set in entry %d!", i);
1282                                 error++;
1283                         }
1284                         if(strlen(cep->local_phone_dialout) == 0)
1285                         {
1286                                 dolog(LL_ERR, "check_config: local-phone-dialout not set in entry %d!", i);
1287                                 error++;
1288                         }
1289                 }
1290
1291                 /* numbers used for incoming calls */
1292                 
1293                 if(cep->inout != DIR_OUTONLY)
1294                 {
1295                         if(strlen(cep->local_phone_incoming) == 0)
1296                         {
1297                                 dolog(LL_ERR, "check_config: local-phone-incoming not set in entry %d!", i);
1298                                 error++;
1299                         }
1300                         if(cep->incoming_numbers_count == 0)
1301                         {
1302                                 dolog(LL_ERR, "check_config: remote-phone-incoming not set in entry %d!", i);
1303                                 error++;
1304                         }
1305                 }
1306
1307                 if((cep->dialin_reaction == REACT_ANSWER) && (cep->b1protocol != BPROT_NONE))
1308                 {
1309                         dolog(LL_ERR, "check_config: b1protocol not raw for telephony in entry %d!", i);
1310                         error++;
1311                 }
1312
1313                 if((cep->ppp_send_auth == AUTH_PAP) || (cep->ppp_send_auth == AUTH_CHAP))
1314                 {
1315                         if(cep->ppp_send_name[0] == 0)
1316                         {
1317                                 dolog(LL_ERR, "check_config: no remote authentification name in entry %d!", i);
1318                                 error++;
1319                         }
1320                         if(cep->ppp_send_password[0] == 0)
1321                         {
1322                                 dolog(LL_ERR, "check_config: no remote authentification password in entry %d!", i);
1323                                 error++;
1324                         }
1325                 }
1326                 if((cep->ppp_expect_auth == AUTH_PAP) || (cep->ppp_expect_auth == AUTH_CHAP))
1327                 {
1328                         if(cep->ppp_expect_name[0] == 0)
1329                         {
1330                                 dolog(LL_ERR, "check_config: no local authentification name in entry %d!", i);
1331                                 error++;
1332                         }
1333                         if(cep->ppp_expect_password[0] == 0)
1334                         {
1335                                 dolog(LL_ERR, "check_config: no local authentification secret in entry %d!", i);
1336                                 error++;
1337                         }
1338                 }
1339         }
1340         if(error)
1341         {
1342                 dolog(LL_ERR, "check_config: %d error(s) in configuration file, exit!", error);
1343                 do_exit(1);
1344         }
1345 }
1346
1347 /*---------------------------------------------------------------------------*
1348  *      print the configuration
1349  *---------------------------------------------------------------------------*/
1350 static void
1351 print_config(void)
1352 {
1353 #define PFILE stdout
1354
1355 #ifdef I4B_EXTERNAL_MONITOR
1356         extern struct monitor_rights * monitor_next_rights(const struct monitor_rights *r);
1357         struct monitor_rights *m_rights;
1358 #endif
1359         cfg_entry_t *cep = &cfg_entry_tab[0];   /* ptr to config entry */
1360         int i, j;
1361         time_t clock;
1362         char mytime[64];
1363
1364         time(&clock);
1365         strcpy(mytime, ctime(&clock));
1366         mytime[strlen(mytime)-1] = '\0';
1367
1368         fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1369         fprintf(PFILE, "# system section (generated %s)\n", mytime);
1370         fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1371         fprintf(PFILE, "system\n");
1372         fprintf(PFILE, "useacctfile     = %s\n", useacctfile ? "on\t\t\t\t# update accounting information file" : "off\t\t\t\t# don't update accounting information file");
1373         fprintf(PFILE, "acctall         = %s\n", acct_all ? "on\t\t\t\t# put all events into accounting file" : "off\t\t\t\t# put only charged events into accounting file");
1374         fprintf(PFILE, "acctfile        = %s\t\t# accounting information file\n", acctfile);
1375         fprintf(PFILE, "ratesfile       = %s\t\t# charging rates database file\n", ratesfile);
1376
1377 #ifdef USE_RTPRIO
1378         if(rt_prio == RTPRIO_NOTUSED)
1379                 fprintf(PFILE, "# rtprio is unused\n");
1380         else
1381                 fprintf(PFILE, "rtprio          = %d\t\t\t\t# isdnd runs at realtime priority\n", rt_prio);
1382 #endif
1383
1384         /* regular expression table */
1385         
1386         for(i=0; i < MAX_RE; i++)
1387         {
1388                 if(rarr[i].re_expr != NULL)
1389                 {
1390                         fprintf(PFILE, "regexpr         = \"%s\"\t\t# scan logfile for this expression\n", rarr[i].re_expr);
1391                 }
1392                 if(rarr[i].re_prog != NULL)
1393                 {
1394                         fprintf(PFILE, "regprog         = %s\t\t# program to run when expression is matched\n", rarr[i].re_prog);
1395                 }
1396         }
1397
1398 #ifdef I4B_EXTERNAL_MONITOR
1399
1400         fprintf(PFILE, "monitor-allowed = %s\n", do_monitor ? "on\t\t\t\t# remote isdnd monitoring allowed" : "off\t\t\t\t# remote isdnd monitoring disabled");
1401         fprintf(PFILE, "monitor-port    = %d\t\t\t\t# TCP/IP port number used for remote monitoring\n", monitorport);
1402
1403         m_rights = monitor_next_rights(NULL);
1404         if(m_rights != NULL)
1405         {
1406                 char *s = "error\n";
1407                 char b[512];
1408
1409                 for ( ; m_rights != NULL; m_rights = monitor_next_rights(m_rights))
1410                 {
1411                         if(m_rights->local)
1412                         {
1413                                 fprintf(PFILE, "monitor         = \"%s\"\t\t# local socket name for monitoring\n", m_rights->name);
1414                         }
1415                         else
1416                         {
1417                                 struct in_addr ia;
1418                                 ia.s_addr = ntohl(m_rights->net);
1419
1420                                 switch(m_rights->mask)
1421                                 {
1422                                         case 0xffffffff:
1423                                                 s = "32";
1424                                                 break;
1425                                         case 0xfffffffe:
1426                                                 s = "31";
1427                                                 break;
1428                                         case 0xfffffffc:
1429                                                 s = "30";
1430                                                 break;
1431                                         case 0xfffffff8:
1432                                                 s = "29";
1433                                                 break;
1434                                         case 0xfffffff0:
1435                                                 s = "28";
1436                                                 break;
1437                                         case 0xffffffe0:
1438                                                 s = "27";
1439                                                 break;
1440                                         case 0xffffffc0:
1441                                                 s = "26";
1442                                                 break;
1443                                         case 0xffffff80:
1444                                                 s = "25";
1445                                                 break;
1446                                         case 0xffffff00:
1447                                                 s = "24";
1448                                                 break;
1449                                         case 0xfffffe00:
1450                                                 s = "23";
1451                                                 break;
1452                                         case 0xfffffc00:
1453                                                 s = "22";
1454                                                 break;
1455                                         case 0xfffff800:
1456                                                 s = "21";
1457                                                 break;
1458                                         case 0xfffff000:
1459                                                 s = "20";
1460                                                 break;
1461                                         case 0xffffe000:
1462                                                 s = "19";
1463                                                 break;
1464                                         case 0xffffc000:
1465                                                 s = "18";
1466                                                 break;
1467                                         case 0xffff8000:
1468                                                 s = "17";
1469                                                 break;
1470                                         case 0xffff0000:
1471                                                 s = "16";
1472                                                 break;
1473                                         case 0xfffe0000:
1474                                                 s = "15";
1475                                                 break;
1476                                         case 0xfffc0000:
1477                                                 s = "14";
1478                                                 break;
1479                                         case 0xfff80000:
1480                                                 s = "13";
1481                                                 break;
1482                                         case 0xfff00000:
1483                                                 s = "12";
1484                                                 break;
1485                                         case 0xffe00000:
1486                                                 s = "11";
1487                                                 break;
1488                                         case 0xffc00000:
1489                                                 s = "10";
1490                                                 break;
1491                                         case 0xff800000:
1492                                                 s = "9";
1493                                                 break;
1494                                         case 0xff000000:
1495                                                 s = "8";
1496                                                 break;
1497                                         case 0xfe000000:
1498                                                 s = "7";
1499                                                 break;
1500                                         case 0xfc000000:
1501                                                 s = "6";
1502                                                 break;
1503                                         case 0xf8000000:
1504                                                 s = "5";
1505                                                 break;
1506                                         case 0xf0000000:
1507                                                 s = "4";
1508                                                 break;
1509                                         case 0xe0000000:
1510                                                 s = "3";
1511                                                 break;
1512                                         case 0xc0000000:
1513                                                 s = "2";
1514                                                 break;
1515                                         case 0x80000000:
1516                                                 s = "1";
1517                                                 break;
1518                                         case 0x00000000:
1519                                                 s = "0";
1520                                                 break;
1521                                 }
1522                                 fprintf(PFILE, "monitor         = \"%s/%s\"\t\t# host (net/mask) allowed to connect for monitoring\n", inet_ntoa(ia), s);
1523                         }
1524                         b[0] = '\0';
1525                         
1526                         if((m_rights->rights) & I4B_CA_COMMAND_FULL)
1527                                 strcat(b, "fullcmd,");
1528                         if((m_rights->rights) & I4B_CA_COMMAND_RESTRICTED)
1529                                 strcat(b, "restrictedcmd,");
1530                         if((m_rights->rights) & I4B_CA_EVNT_CHANSTATE)
1531                                 strcat(b, "channelstate,");
1532                         if((m_rights->rights) & I4B_CA_EVNT_CALLIN)
1533                                 strcat(b, "callin,");
1534                         if((m_rights->rights) & I4B_CA_EVNT_CALLOUT)
1535                                 strcat(b, "callout,");
1536                         if((m_rights->rights) & I4B_CA_EVNT_I4B)
1537                                 strcat(b, "logevents,");
1538
1539                         if(b[strlen(b)-1] == ',')
1540                                 b[strlen(b)-1] = '\0';
1541                                 
1542                         fprintf(PFILE, "monitor-access  = %s\t\t# monitor access rights\n", b);
1543                 }
1544         }
1545         
1546 #endif
1547         /* entry sections */
1548         
1549         for(i=0; i <= entrycount; i++, cep++)
1550         {
1551                 fprintf(PFILE, "\n");
1552                 fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1553                 fprintf(PFILE, "# entry section %d\n", i);
1554                 fprintf(PFILE, "#---------------------------------------------------------------------------\n");
1555                 fprintf(PFILE, "entry\n");
1556
1557                 fprintf(PFILE, "name                  = %s\t\t# name for this entry section\n", cep->name);
1558
1559                 fprintf(PFILE, "isdncontroller        = %d\t\t# ISDN card number used for this entry\n", cep->isdncontroller);
1560                 fprintf(PFILE, "isdnchannel           = ");
1561                 switch(cep->isdnchannel)
1562                 {
1563                                 case CHAN_ANY:
1564                                         fprintf(PFILE, "-1\t\t# any ISDN B-channel may be used\n");
1565                                         break;
1566                                 default:
1567                                         fprintf(PFILE, "%d\t\t# only ISDN B-channel %d may be used\n", cep->isdnchannel+1, cep->isdnchannel+1);
1568                                         break;
1569                 }
1570
1571                 fprintf(PFILE, "usrdevicename         = %s\t\t# name of userland ISDN B-channel device\n", bdrivername(cep->usrdevicename));
1572                 fprintf(PFILE, "usrdeviceunit         = %d\t\t# unit number of userland ISDN B-channel device\n", cep->usrdeviceunit);
1573
1574                 fprintf(PFILE, "b1protocol            = %s\n", cep->b1protocol ? "hdlc\t\t# B-channel layer 1 protocol is HDLC" : "raw\t\t# No B-channel layer 1 protocol used");
1575
1576                 if(!(cep->usrdevicename == BDRV_TEL))
1577                 {
1578                         fprintf(PFILE, "direction             = ");
1579                         switch(cep->inout)
1580                         {
1581                                 case DIR_INONLY:
1582                                         fprintf(PFILE, "in\t\t# only incoming connections allowed\n");
1583                                         break;
1584                                 case DIR_OUTONLY:
1585                                         fprintf(PFILE, "out\t\t# only outgoing connections allowed\n");
1586                                         break;
1587                                 case DIR_INOUT:
1588                                         fprintf(PFILE, "inout\t\t# incoming and outgoing connections allowed\n");
1589                                         break;
1590                         }
1591                 }
1592                 
1593                 if(!((cep->usrdevicename == BDRV_TEL) || (cep->inout == DIR_INONLY)))
1594                 {
1595                         if(cep->remote_numbers_count > 1)
1596                         {
1597                                 for(j=0; j<cep->remote_numbers_count; j++)
1598                                         fprintf(PFILE, "remote-phone-dialout  = %s\t\t# telephone number %d for dialing out to remote\n", cep->remote_numbers[j].number, j+1);
1599
1600                                 fprintf(PFILE, "remdial-handling      = ");
1601                 
1602                                 switch(cep->remote_numbers_handling)
1603                                 {
1604                                         case RNH_NEXT:
1605                                                 fprintf(PFILE, "next\t\t# use next number after last successful for new dial\n");
1606                                                 break;
1607                                         case RNH_LAST:
1608                                                 fprintf(PFILE, "last\t\t# use last successful number for new dial\n");
1609                                                 break;
1610                                         case RNH_FIRST:
1611                                                 fprintf(PFILE, "first\t\t# always start with first number for new dial\n");
1612                                                 break;
1613                                 }
1614                         }
1615                         else
1616                         {
1617                                 fprintf(PFILE, "remote-phone-dialout  = %s\t\t# telephone number for dialing out to remote\n", cep->remote_numbers[0].number);
1618                         }
1619
1620                         fprintf(PFILE, "local-phone-dialout   = %s\t\t# show this number to remote when dialling out\n", cep->local_phone_dialout);
1621                         fprintf(PFILE, "dialout-type          = %s\n", cep->dialouttype ? "calledback\t\t# i am called back by remote" : "normal\t\t# i am not called back by remote");
1622                 }
1623
1624                 if(!(cep->inout == DIR_OUTONLY))
1625                 {
1626                         int n;
1627                         
1628                         fprintf(PFILE, "local-phone-incoming  = %s\t\t# incoming calls must match this (mine) telephone number\n", cep->local_phone_incoming);
1629                         for (n = 0; n < cep->incoming_numbers_count; n++)
1630                                 fprintf(PFILE, "remote-phone-incoming = %s\t\t# this is a valid remote number to call me\n",
1631                                         cep->remote_phone_incoming[n].number);
1632
1633                         fprintf(PFILE, "dialin-reaction       = ");
1634                         switch(cep->dialin_reaction)
1635                         {
1636                                 case REACT_ACCEPT:
1637                                         fprintf(PFILE, "accept\t\t# i accept a call from remote and connect\n");
1638                                         break;
1639                                 case REACT_REJECT:
1640                                         fprintf(PFILE, "reject\t\t# i reject the call from remote\n");
1641                                         break;
1642                                 case REACT_IGNORE:
1643                                         fprintf(PFILE, "ignore\t\t# i ignore the call from remote\n");
1644                                         break;
1645                                 case REACT_ANSWER:
1646                                         fprintf(PFILE, "answer\t\t# i will start telephone answering when remote calls in\n");
1647                                         break;
1648                                 case REACT_CALLBACK:
1649                                         fprintf(PFILE, "callback\t\t# when remote calls in, i will hangup and call back\n");
1650                                         break;
1651                         }
1652                 }
1653
1654                 if(cep->usrdevicename == BDRV_ISPPP)
1655                 {
1656                         char *s;
1657                         switch(cep->ppp_expect_auth)
1658                         {
1659                                 case AUTH_NONE:
1660                                         s = "none";
1661                                         break;
1662                                 case AUTH_PAP:
1663                                         s = "pap";
1664                                         break;
1665                                 case AUTH_CHAP:
1666                                         s = "chap";
1667                                         break;
1668                                 default:
1669                                         s = NULL;
1670                                         break;
1671                         }
1672                         if(s != NULL)
1673                         {
1674                                 fprintf(PFILE, "ppp-expect-auth       = %s\t\t# the auth protocol we expect to receive on dial-in (none,pap,chap)\n", s);
1675                                 if(cep->ppp_expect_auth != AUTH_NONE)
1676                                 {
1677                                         fprintf(PFILE, "ppp-expect-name       = %s\t\t# the user name allowed in\n", cep->ppp_expect_name);
1678                                         fprintf(PFILE, "ppp-expect-password   = %s\t\t# the key expected from the other side\n", cep->ppp_expect_password);
1679                                         fprintf(PFILE, "ppp-auth-paranoid     = %s\t\t# do we require remote to authenticate even if we dial out\n", cep->ppp_auth_flags & AUTH_REQUIRED ? "yes" : "no");
1680                                 }
1681                         }
1682                         switch(cep->ppp_send_auth)
1683                         {
1684                                 case AUTH_NONE:
1685                                         s = "none";
1686                                         break;
1687                                 case AUTH_PAP:
1688                                         s = "pap";
1689                                         break;
1690                                 case AUTH_CHAP:
1691                                         s = "chap";
1692                                         break;
1693                                 default:
1694                                         s = NULL;
1695                                         break;
1696                         }
1697                         if(s != NULL)
1698                         {
1699                                 fprintf(PFILE, "ppp-send-auth         = %s\t\t# the auth protocol we use when dialing out (none,pap,chap)\n", s);
1700                                 if(cep->ppp_send_auth != AUTH_NONE)
1701                                 {
1702                                         fprintf(PFILE, "ppp-send-name         = %s\t\t# our PPP account used for dial-out\n", cep->ppp_send_name);
1703                                         fprintf(PFILE, "ppp-send-password     = %s\t\t# the key sent to the other side\n", cep->ppp_send_password);
1704                                 }
1705                         }
1706                         if(cep->ppp_send_auth == AUTH_CHAP ||
1707                            cep->ppp_expect_auth == AUTH_CHAP) {
1708                                 fprintf(PFILE, "ppp-auth-rechallenge   = %s\t\t# rechallenge CHAP connections once in a while\n", cep->ppp_auth_flags & AUTH_RECHALLENGE ? "yes" : "no");
1709                         }
1710                 }
1711
1712                 if(!((cep->inout == DIR_INONLY) || (cep->usrdevicename == BDRV_TEL)))
1713                 {
1714                         char *s;
1715                         fprintf(PFILE, "idletime-outgoing     = %d\t\t# outgoing call idle timeout\n", cep->idle_time_out);
1716
1717                         switch( cep->shorthold_algorithm )
1718                         {
1719                                 case SHA_FIXU:
1720                                         s = "fix-unit-size";
1721                                         break;
1722                                 case SHA_VARU:
1723                                         s = "var-unit-size";
1724                                         break;
1725                                 default:
1726                                         s = "error!!!";
1727                                         break;
1728                         }
1729
1730                         fprintf(PFILE, "idle-algorithm-outgoing     = %s\t\t# outgoing call idle algorithm\n", s);
1731                 }
1732
1733                 if(!(cep->inout == DIR_OUTONLY))
1734                         fprintf(PFILE, "idletime-incoming     = %d\t\t# incoming call idle timeout\n", cep->idle_time_in);
1735
1736                 if(!(cep->usrdevicename == BDRV_TEL))
1737                 {               
1738                         fprintf(PFILE, "unitlengthsrc         = ");
1739                         switch(cep->unitlengthsrc)
1740                         {
1741                                 case ULSRC_NONE:
1742                                         fprintf(PFILE, "none\t\t# no unit length specified, using default\n");
1743                                         break;
1744                                 case ULSRC_CMDL:
1745                                         fprintf(PFILE, "cmdl\t\t# using unit length specified on commandline\n");
1746                                         break;
1747                                 case ULSRC_CONF:
1748                                         fprintf(PFILE, "conf\t\t# using unitlength specified by unitlength-keyword\n");
1749                                         fprintf(PFILE, "unitlength            = %d\t\t# fixed unitlength\n", cep->unitlength);
1750                                         break;
1751                                 case ULSRC_RATE:
1752                                         fprintf(PFILE, "rate\t\t# using unitlength specified in rate database\n");
1753                                         fprintf(PFILE, "ratetype              = %d\t\t# type of rate from rate database\n", cep->ratetype);
1754                                         break;
1755                                 case ULSRC_DYN:
1756                                         fprintf(PFILE, "aocd\t\t# using dynamically calculated unitlength based on AOCD subscription\n");
1757                                         fprintf(PFILE, "ratetype              = %d\t\t# type of rate from rate database\n", cep->ratetype);
1758                                         break;
1759                         }
1760
1761                         fprintf(PFILE, "earlyhangup           = %d\t\t# early hangup safety time\n", cep->earlyhangup);
1762
1763                 }
1764                 
1765                 if(cep->usrdevicename == BDRV_TEL)
1766                 {
1767                         fprintf(PFILE, "answerprog            = %s\t\t# program used to answer incoming telephone calls\n", cep->answerprog);
1768                         fprintf(PFILE, "alert                 = %d\t\t# number of seconds to wait before accepting a call\n", cep->alert);
1769                 }
1770
1771                 if(!(cep->usrdevicename == BDRV_TEL))
1772                 {               
1773                         if(cep->dialin_reaction == REACT_CALLBACK)
1774                                 fprintf(PFILE, "callbackwait          = %d\t\t# i am waiting this time before calling back remote\n", cep->callbackwait);
1775         
1776                         if(cep->dialouttype == DIALOUT_CALLEDBACK)
1777                                 fprintf(PFILE, "calledbackwait        = %d\t\t# i am waiting this time for a call back from remote\n", cep->calledbackwait);
1778         
1779                         if(!(cep->inout == DIR_INONLY))
1780                         {
1781                                 fprintf(PFILE, "dialretries           = %d\t\t# number of dialing retries\n", cep->dialretries);
1782                                 fprintf(PFILE, "recoverytime          = %d\t\t# time to wait between dialling retries\n", cep->recoverytime);
1783                                 fprintf(PFILE, "dialrandincr          = %s\t\t# use random dialing time addon\n", cep->dialrandincr ? "on" : "off");
1784
1785                                 fprintf(PFILE, "usedown               = %s\n", cep->usedown ? "on\t\t# ISDN device switched off on excessive dial failures" : "off\t\t# no device switchoff on excessive dial failures");
1786                                 if(cep->usedown)
1787                                 {
1788                                         fprintf(PFILE, "downtries             = %d\t\t# number of dialretries failures before switching off\n", cep->downtries);
1789                                         fprintf(PFILE, "downtime              = %d\t\t# time device is switched off\n", cep->downtime);
1790                                 }
1791                         }
1792                 }               
1793         }
1794         fprintf(PFILE, "\n");   
1795 }
1796
1797 /* EOF */