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