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