Replaced polling loop for LCR and chan_lcr with select based event loop.
[lcr.git] / interface.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** LCR                                                                       **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** reading interface.conf file and filling structure                         **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 struct interface *interface_first = NULL; /* first interface is current list */
15 struct interface *interface_newlist = NULL; /* first interface in new list */
16
17
18 /* set default out_channel */
19 void default_out_channel(struct interface_port *ifport)
20 {
21         struct select_channel *selchannel, **selchannelp;
22
23         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
24         memuse++;
25         
26         if (ifport->mISDNport->ntmode)
27                 selchannel->channel = CHANNEL_FREE;
28         else
29                 selchannel->channel = CHANNEL_ANY;
30         
31         ifport->out_channel = selchannel;
32
33         /* additional channel selection for multipoint NT ports */
34         if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode) {
35                 selchannelp = &(selchannel->next);
36                 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
37                 memuse++;
38                 selchannel->channel = CHANNEL_NO; // call waiting
39                 *selchannelp = selchannel;
40         }
41 }
42
43
44 /* set default in_channel */
45 void default_in_channel(struct interface_port *ifport)
46 {
47         struct select_channel *selchannel;
48
49         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
50         memuse++;
51         
52         selchannel->channel = CHANNEL_FREE;
53         
54         ifport->in_channel = selchannel;
55 }
56
57
58 /* parse string for a positive number */
59 static int get_number(char *value)
60 {
61         int val = 0;
62         char text[10];
63
64         val = atoi(value);
65         
66         SPRINT(text, "%d", val);
67
68         if (!strcmp(value, text))
69                 return(val);
70
71         return(-1);
72 }
73
74
75 /* remove element from buffer
76  * and return pointer to next element in buffer */
77 static char *get_seperated(char *buffer)
78 {
79         while(*buffer) {
80                 if (*buffer==',' || *buffer<=32) { /* seperate */
81                         *buffer++ = '\0';
82                         while((*buffer>'\0' && *buffer<=32) || *buffer==',')
83                                 buffer++;
84                         return(buffer);
85                 }
86                 buffer++;
87         }
88         return(buffer);
89 }
90
91 /*
92  * parameter processing
93  */
94 static int inter_block(struct interface *interface, char *filename, int line, char *parameter, char *value)
95 {
96         struct interface_port *ifport;
97
98         /* port in chain ? */
99         if (!interface->ifport) {
100                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
101                 return(-1);
102         }
103         /* goto end of chain */
104         ifport = interface->ifport;
105         while(ifport->next)
106                 ifport = ifport->next;
107         /* add value */
108         if (value[0]) {
109                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
110                 return(-1);
111         }
112         ifport->block = 1;
113         return(0);
114 }
115 static int inter_extension(struct interface *interface, char *filename, int line, char *parameter, char *value)
116 {
117         if (interface->external) {
118                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is external interface.\n", filename, line, parameter);
119                 return(-1);
120         }
121         if (value[0]) {
122                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
123                 return(-1);
124         }
125         interface->extension = 1;
126         return(0);
127 }
128 static int inter_extern(struct interface *interface, char *filename, int line, char *parameter, char *value)
129 {
130         if (interface->extension) {
131                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is an extension.\n", filename, line, parameter);
132                 return(-1);
133         }
134         if (value[0]) {
135                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
136                 return(-1);
137         }
138         interface->external = 1;
139         return(0);
140 }
141 static int inter_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
142 {
143         struct interface_port *ifport;
144
145         /* port in chain ? */
146         if (!interface->ifport) {
147                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
148                 return(-1);
149         }
150         if (interface->ifport->ptmp) {
151                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptmp was given.\n", filename, line, parameter);
152                 return(-1);
153         }
154         /* goto end of chain */
155         ifport = interface->ifport;
156         while(ifport->next)
157                 ifport = ifport->next;
158         /* add value */
159         if (value[0]) {
160                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
161                 return(-1);
162         }
163         ifport->ptp = 1;
164         return(0);
165 }
166 #if 0
167 static int inter_ptmp(struct interface *interface, char *filename, int line, char *parameter, char *value)
168 {
169         struct interface_port *ifport;
170
171         /* port in chain ? */
172         if (!interface->ifport) {
173                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
174                 return(-1);
175         }
176         if (interface->ifport->ptp) {
177                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptp was given.\n", filename, line, parameter);
178                 return(-1);
179         }
180         /* goto end of chain */
181         ifport = interface->ifport;
182         while(ifport->next)
183                 ifport = ifport->next;
184         /* add value */
185         if (value[0]) {
186                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
187                 return(-1);
188         }
189         ifport->ptmp = 1;
190         return(0);
191 }
192 #endif
193 static int inter_nt(struct interface *interface, char *filename, int line, char *parameter, char *value)
194 {
195         struct interface_port *ifport;
196
197         /* port in chain ? */
198         if (!interface->ifport) {
199                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
200                 return(-1);
201         }
202         /* goto end of chain */
203         ifport = interface->ifport;
204         while(ifport->next)
205                 ifport = ifport->next;
206         /* add value */
207         if (value[0]) {
208                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
209                 return(-1);
210         }
211         ifport->nt = 1;
212         return(0);
213 }
214 static int inter_tespecial(struct interface *interface, char *filename, int line, char *parameter, char *value)
215 {
216         struct interface_port *ifport;
217
218         /* port in chain ? */
219         if (!interface->ifport) {
220                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
221                 return(-1);
222         }
223         /* goto end of chain */
224         ifport = interface->ifport;
225         while(ifport->next)
226                 ifport = ifport->next;
227         /* add value */
228         if (value[0]) {
229                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
230                 return(-1);
231         }
232         ifport->tespecial = 1;
233         return(0);
234 }
235 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
236 {
237         if (!strcasecmp(value, "yes")) {
238                 interface->is_tones = IS_YES;
239         } else
240         if (!strcasecmp(value, "no")) {
241                 interface->is_tones = IS_NO;
242         } else {
243                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
244                 return(-1);
245         }
246         return(0);
247 }
248 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
249 {
250         if (!strcasecmp(value, "yes")) {
251                 interface->is_earlyb = IS_YES;
252         } else
253         if (!strcasecmp(value, "no")) {
254                 interface->is_earlyb = IS_NO;
255         } else {
256                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
257                 return(-1);
258         }
259         return(0);
260 }
261 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
262 {
263         if (!strcasecmp(value, "linear")) {
264                 interface->hunt = HUNT_LINEAR;
265         } else
266         if (!strcasecmp(value, "roundrobin")) {
267                 interface->hunt = HUNT_ROUNDROBIN;
268         } else {
269                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
270                 return(-1);
271         }
272         return(0);
273 }
274 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
275 {
276         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' is outdated.\nPlease use 'portnum' and decrease port number by 1! Ports are counted from 0 now.\n", filename, line, parameter);
277         return(-1);
278 }
279 static int inter_portnum(struct interface *interface, char *filename, int line, char *parameter, char *value)
280 {
281         struct interface_port *ifport, **ifportp;
282         struct interface *searchif;
283         int val;
284
285         val = get_number(value);
286         if (val == -1) {
287                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
288                 return(-1);
289         }
290         /* check for port already assigned */
291         searchif = interface_newlist;
292         while(searchif) {
293                 ifport = searchif->ifport;
294                 while(ifport) {
295                         if (ifport->portnum == val) {
296                                 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
297                                 return(-1);
298                         }
299                         ifport = ifport->next;
300                 }
301                 searchif = searchif->next;
302         }
303         /* alloc port substructure */
304         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
305         memuse++;
306         ifport->interface = interface;
307         /* set value */
308         ifport->portnum = val;
309         /* tail port */
310         ifportp = &interface->ifport;
311         while(*ifportp)
312                 ifportp = &((*ifportp)->next);
313         *ifportp = ifport;
314         return(0);
315 }
316 static int inter_portname(struct interface *interface, char *filename, int line, char *parameter, char *value)
317 {
318         struct interface_port *ifport, **ifportp;
319         struct interface *searchif;
320
321         /* check for port already assigned */
322         searchif = interface_newlist;
323         while(searchif) {
324                 ifport = searchif->ifport;
325                 while(ifport) {
326                         if (!strcasecmp(ifport->portname, value)) {
327                                 SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
328                                 return(-1);
329                         }
330 //                      /* check for use as GSM */
331 //                      if (ifport->gsm) {
332 //                              SPRINT(interface_error, "Error in %s (line %d): Interface already used for GSM.\n", filename, line);
333 //                              return(-1);
334 //                      }
335                         ifport = ifport->next;
336                 }
337                 searchif = searchif->next;
338         }
339         /* alloc port substructure */
340         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
341         memuse++;
342         ifport->interface = interface;
343         /* set value */
344         ifport->portnum = -1; // disable until resolved
345         SCPY(ifport->portname, value);
346         /* tail port */
347         ifportp = &interface->ifport;
348         while(*ifportp)
349                 ifportp = &((*ifportp)->next);
350         *ifportp = ifport;
351         return(0);
352 }
353 static int inter_l1hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
354 {
355         struct interface_port *ifport;
356
357         /* port in chain ? */
358         if (!interface->ifport) {
359                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
360                 return(-1);
361         }
362         /* goto end of chain */
363         ifport = interface->ifport;
364         while(ifport->next)
365                 ifport = ifport->next;
366         if (!strcmp(value, "yes")) {
367                 ifport->l1hold = 1;
368         } else
369         if (!strcmp(value, "no")) {
370                 ifport->l1hold = 0;
371         } else {
372                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
373                 return(-1);
374         }
375         return(0);
376 }
377 static int inter_l2hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
378 {
379         struct interface_port *ifport;
380
381         /* port in chain ? */
382         if (!interface->ifport) {
383                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
384                 return(-1);
385         }
386         /* goto end of chain */
387         ifport = interface->ifport;
388         while(ifport->next)
389                 ifport = ifport->next;
390         if (!strcmp(value, "yes")) {
391                 ifport->l2hold = 1;
392         } else
393         if (!strcmp(value, "no")) {
394                 ifport->l2hold = -1;
395         } else {
396                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
397                 return(-1);
398         }
399         return(0);
400 }
401 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
402 {
403         struct interface_port *ifport;
404         struct select_channel *selchannel, **selchannelp;
405         int val;
406         char *p, *el;
407
408         /* port in chain ? */
409         if (!interface->ifport) {
410                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
411                 return(-1);
412         }
413         /* goto end of chain */
414         ifport = interface->ifport;
415         while(ifport->next)
416                 ifport = ifport->next;
417         p = value;
418         while(*p) {
419                 el = p;
420                 p = get_seperated(p);
421                 if (!strcasecmp(el, "force")) {
422                         ifport->channel_force = 1;
423                         if (ifport->out_channel) {
424                                 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
425                                 return(-1);
426                         }
427                 } else
428                 if (!strcasecmp(el, "any")) {
429                         val = CHANNEL_ANY;
430                         goto selchannel;
431                 } else
432                 if (!strcasecmp(el, "free")) {
433                         val = CHANNEL_FREE;
434                         goto selchannel;
435                 } else
436                 if (!strcasecmp(el, "no")) {
437                         val = CHANNEL_NO;
438                         goto selchannel;
439                 } else {
440                         val = get_number(el);
441                         if (val == -1) {
442                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of 'force', 'any', 'free', 'no' and any channel number.\n", filename, line, parameter);
443                                 return(-1);
444                         }
445
446                         if (val<1 || val==16 || val>126) {
447                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
448                                 return(-1);
449                         }
450                         selchannel:
451                         /* add to select-channel list */
452                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
453                         memuse++;
454                         /* set value */
455                         selchannel->channel = val;
456                         /* tail port */
457                         selchannelp = &ifport->out_channel;
458                         while(*selchannelp)
459                                 selchannelp = &((*selchannelp)->next);
460                         *selchannelp = selchannel;
461                 }
462         }
463         return(0);
464 }
465 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
466 {
467         struct interface_port *ifport;
468         struct select_channel *selchannel, **selchannelp;
469         int val;
470         char *p, *el;
471
472         /* port in chain ? */
473         if (!interface->ifport) {
474                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
475                 return(-1);
476         }
477         /* goto end of chain */
478         ifport = interface->ifport;
479         while(ifport->next)
480                 ifport = ifport->next;
481         p = value;
482         while(*p) {
483                 el = p;
484                 p = get_seperated(p);
485                 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE) {
486                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
487                                 return(-1);
488                 }
489                 if (!strcasecmp(el, "free")) {
490                         val = CHANNEL_FREE;
491                         goto selchannel;
492                 } else {
493                         val = get_number(el);
494                         if (val == -1) {
495                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
496                                 return(-1);
497                         }
498
499                         if (val<1 || val==16 || val>126) {
500                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
501                                 return(-1);
502                         }
503                         selchannel:
504                         /* add to select-channel list */
505                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
506                         memuse++;
507                         /* set value */
508                         selchannel->channel = val;
509                         /* tail port */
510                         selchannelp = &ifport->in_channel;
511                         while(*selchannelp)
512                                 selchannelp = &((*selchannelp)->next);
513                         *selchannelp = selchannel;
514                 }
515         }
516         return(0);
517 }
518 static int inter_timeouts(struct interface *interface, char *filename, int line, char *parameter, char *value)
519 {
520         struct interface_port *ifport;
521 //      struct select_channel *selchannel, **selchannelp;
522 //      int val;
523         char *p, *el;
524
525         /* port in chain ? */
526         if (!interface->ifport) {
527                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
528                 return(-1);
529         }
530         /* goto end of chain */
531         ifport = interface->ifport;
532         while(ifport->next)
533                 ifport = ifport->next;
534         p = value;
535         if (!*p) {
536                 nofive:
537                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects five timeout values.\n", filename, line, parameter);
538                 return(-1);
539         }
540         el = p;
541         p = get_seperated(p);
542         ifport->tout_setup = atoi(el);
543         if (!*p)
544                 goto nofive;
545         el = p;
546         p = get_seperated(p);
547         ifport->tout_dialing = atoi(el);
548         if (!*p)
549                 goto nofive;
550         el = p;
551         p = get_seperated(p);
552         ifport->tout_proceeding = atoi(el);
553         if (!*p)
554                 goto nofive;
555         el = p;
556         p = get_seperated(p);
557         ifport->tout_alerting = atoi(el);
558         if (!*p)
559                 goto nofive;
560         el = p;
561         p = get_seperated(p);
562         ifport->tout_disconnect = atoi(el);
563         return(0);
564 }
565 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
566 {
567         struct interface_msn *ifmsn, **ifmsnp;
568         char *p, *el;
569
570         if (!value[0]) {
571                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
572                 return(-1);
573         }
574         if (interface->ifscreen_in) {
575                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
576                 return(-1);
577         }
578
579         /* process list */
580         p = value;
581         while(*p) {
582                 el = p;
583                 p = get_seperated(p);
584                 /* add MSN to list */
585                 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
586                 memuse++;
587                 /* set value */
588                 SCPY(ifmsn->msn, el);
589                 /* tail port */
590                 ifmsnp = &interface->ifmsn;
591                 while(*ifmsnp)
592                         ifmsnp = &((*ifmsnp)->next);
593                 *ifmsnp = ifmsn;
594         }
595         return(0);
596 }
597 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
598 {
599         struct interface_screen *ifscreen;
600         char *p, *el;
601
602         if (!value[0]) {
603                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
604                 return(-1);
605         }
606         /* add screen entry to list*/
607         ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
608         memuse++;
609         ifscreen->match_type = -1; /* unchecked */
610         ifscreen->match_present = -1; /* unchecked */
611         ifscreen->result_type = -1; /* unchanged */
612         ifscreen->result_present = -1; /* unchanged */
613         /* tail port */
614         while(*ifscreenp)
615                 ifscreenp = &((*ifscreenp)->next);
616         *ifscreenp = ifscreen;
617 //      printf("interface=%s\n", interface->name);
618         /* get match */
619         p = value;
620         while(*p) {
621                 el = p;
622                 p = get_seperated(p);
623                 if (!strcasecmp(el, "unknown")) {
624                         if (ifscreen->match_type != -1) {
625                                 typeerror:
626                                 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
627                                 return(-1);
628                         }
629                         ifscreen->match_type = INFO_NTYPE_UNKNOWN;
630                 } else
631                 if (!strcasecmp(el, "subscriber")) {
632                         if (ifscreen->match_type != -1)
633                                 goto typeerror;
634                         ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
635                 } else
636                 if (!strcasecmp(el, "national")) {
637                         if (ifscreen->match_type != -1)
638                                 goto typeerror;
639                         ifscreen->match_type = INFO_NTYPE_NATIONAL;
640                 } else
641                 if (!strcasecmp(el, "international")) {
642                         if (ifscreen->match_type != -1)
643                                 goto typeerror;
644                         ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
645                 } else
646                 if (!strcasecmp(el, "allowed")) {
647                         if (ifscreen->match_present != -1) {
648                                 presenterror:
649                                 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
650                                 return(-1);
651                         }
652                         ifscreen->match_present = INFO_PRESENT_ALLOWED;
653                 } else
654                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted")) {
655                         if (ifscreen->match_present != -1)
656                                 goto presenterror;
657                         ifscreen->match_present = INFO_PRESENT_RESTRICTED;
658                 } else {
659                         SCPY(ifscreen->match, el);
660                         /* check for % at the end */
661                         if (strchr(el, '%')) {
662                                 if (strchr(el, '%') != el+strlen(el)-1) {
663                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
664                                         return(-1);
665                                 }
666                         }
667                         break;
668                 }
669         }
670         if (ifscreen->match[0] == '\0') {
671                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
672                 return(-1);
673         }
674         /* get result */
675         while(*p) {
676                 el = p;
677                 p = get_seperated(p);
678                 if (!strcasecmp(el, "unknown")) {
679                         if (ifscreen->result_type != -1)
680                                 goto typeerror;
681                         ifscreen->result_type = INFO_NTYPE_UNKNOWN;
682                 } else
683                 if (!strcasecmp(el, "subscriber")) {
684                         if (ifscreen->result_type != -1)
685                                 goto typeerror;
686                         ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
687                 } else
688                 if (!strcasecmp(el, "national")) {
689                         if (ifscreen->result_type != -1)
690                                 goto typeerror;
691                         ifscreen->result_type = INFO_NTYPE_NATIONAL;
692                 } else
693                 if (!strcasecmp(el, "international")) {
694                         if (ifscreen->result_type != -1)
695                                 goto typeerror;
696                         ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
697                 } else
698                 if (!strcasecmp(el, "present") || !strcasecmp(el, "presented") || !strcasecmp(el, "allowed") || !strcasecmp(el, "allow")) {
699                         if (ifscreen->result_present != -1)
700                                 goto presenterror;
701                         ifscreen->result_present = INFO_PRESENT_ALLOWED;
702                 } else
703                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted") || !strcasecmp(el, "deny") || !strcasecmp(el, "denied")) {
704                         if (ifscreen->result_present != -1)
705                                 goto presenterror;
706                         ifscreen->result_present = INFO_PRESENT_RESTRICTED;
707                 } else {
708                         SCPY(ifscreen->result, el);
709                         /* check for % at the end */
710                         if (strchr(el, '%')) {
711                                 if (strchr(el, '%') != el+strlen(el)-1) {
712                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
713                                         return(-1);
714                                 }
715                         }
716                         break;
717                 }
718         }
719         if (ifscreen->result[0] == '\0') {
720                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
721                 return(-1);
722         }
723         return(0);
724 }
725 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
726 {
727         if (interface->ifmsn) {
728                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
729                 return(-1);
730         }
731
732         return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
733 }
734 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
735 {
736         return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
737 }
738 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
739 {
740         struct interface_port *ifport;
741
742         /* port in chain ? */
743         if (!interface->ifport) {
744                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
745                 return(-1);
746         }
747         /* goto end of chain */
748         ifport = interface->ifport;
749         while(ifport->next)
750                 ifport = ifport->next;
751         ifport->nodtmf = 1;
752         return(0);
753 }
754 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
755 {
756         char *p, *q;
757
758         /* seperate parameter from filter */
759         p = value;
760         while(*p > 32)
761                 p++;
762         if (*p) {
763                 *p++ = 0;
764                 while(*p > 0 && *p <= 32)
765                         p++;
766         }
767
768         if (!strcasecmp(value, "gain")) {
769                 q = p;
770                 while(*q > 32)
771                         q++;
772                 if (*q) {
773                         *q++ = 0;
774                         while(*q > 0 && *q <= 32)
775                                 q++;
776                 }
777                 if (*p == 0 || *q == 0) {
778                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects two gain values.\n", filename, line, parameter, value);
779                         return(-1);
780                 }
781                 if (atoi(p)<-8 || atoi(p)>8 || atoi(q)<-8 || atoi(q)>8) {
782                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' gain values not in range. (-8...8)\n", filename, line, parameter, value);
783                         return(-1);
784                 }
785                 interface->tx_gain = atoi(p);
786                 interface->rx_gain = atoi(q);
787         } else
788         if (!strcasecmp(value, "pipeline")) {
789                 if (*p == 0) {
790                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects pipeline string.\n", filename, line, parameter, value);
791                         return(-1);
792                 }
793                 SCPY(interface->pipeline, p);
794         } else
795         if (!strcasecmp(value, "blowfish")) {
796                 unsigned char key[56];
797                 int l;
798                 
799                 if (!!strncmp(p, "0x", 2)) {
800                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects blowfish key starting with '0x'.\n", filename, line, parameter, value);
801                         return(-1);
802                 }
803                 p += 2;
804                 l = 0; 
805                 while(*p) {
806                         if (l == 56) {
807                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key too long.\n", filename, line, parameter, value);
808                                 return(-1);
809                         }
810                         if (*p >= '0' && *p <= '9')
811                                 key[l] = (*p-'0')<<4;
812                         else if (*p >= 'a' && *p <= 'f')
813                                 key[l] = (*p-'a'+10)<<4;
814                         else if (*p >= 'A' && *p <= 'F')
815                                 key[l] = (*p-'A'+10)<<4;
816                         else {
817                                 digout:
818                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key has digits out of range. (0...9, a...f)\n", filename, line, parameter, value);
819                                 return(-1);
820                         }
821                         p++;
822                         if (*p == 0) {
823                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key must end on an 8 bit boundary (two character boundary).\n", filename, line, parameter, value);
824                                 return(-1);
825                         }
826                         if (*p >= '0' && *p <= '9')
827                                 key[l] = (*p-'0')<<4;
828                         else if (*p >= 'a' && *p <= 'f')
829                                 key[l] = (*p-'a'+10)<<4;
830                         else if (*p >= 'A' && *p <= 'F')
831                                 key[l] = (*p-'A'+10)<<4;
832                         else
833                                 goto digout;
834                         p++;
835                         l++;
836                 }
837                 if (l < 4) {
838                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key must be at least 4 bytes (8 characters).\n", filename, line, parameter, value);
839                         return(-1);
840                 }
841                 memcpy(interface->bf_key, key, l);
842                 interface->bf_len = l;
843         } else {
844                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has unknown filter '%s'.\n", filename, line, parameter, value);
845                 return(-1);
846         }
847         return(0);
848 }
849 static int inter_dialmax(struct interface *interface, char *filename, int line, char *parameter, char *value)
850 {
851         struct interface_port *ifport;
852
853         /* port in chain ? */
854         if (!interface->ifport) {
855                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
856                 return(-1);
857         }
858         /* goto end of chain */
859         ifport = interface->ifport;
860         while(ifport->next)
861                 ifport = ifport->next;
862         ifport->dialmax = atoi(value);
863         return(0);
864 }
865 static int inter_tones_dir(struct interface *interface, char *filename, int line, char *parameter, char *value)
866 {
867         struct interface_port *ifport;
868
869         /* port in chain ? */
870         if (!interface->ifport) {
871                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
872                 return(-1);
873         }
874         /* goto end of chain */
875         ifport = interface->ifport;
876         while(ifport->next)
877                 ifport = ifport->next;
878         SCPY(ifport->tones_dir, value);
879         return(0);
880 }
881 static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
882 {
883 #ifndef WITH_GSM
884         SPRINT(interface_error, "Error in %s (line %d): GSM not compiled in.\n", filename, line);
885         return(-1);
886 #else
887         struct interface_port *ifport;
888         struct interface *searchif;
889
890         /* check gsm */
891         if (!gsm) {
892                 SPRINT(interface_error, "Error in %s (line %d): GSM is not activated.\n", filename, line);
893                 return(-1);
894         }
895         searchif = interface_newlist;
896         while(searchif) {
897                 ifport = searchif->ifport;
898                 while(ifport) {
899                         if (ifport->gsm) {
900                                 SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm\n", filename, line, value);
901                                 return(-1);
902                         }
903                         ifport = ifport->next;
904                 }
905                 searchif = searchif->next;
906         }
907
908         /* set portname */
909         if (inter_portname(interface, filename, line, (char *)"portname", gsm->conf.interface_lcr))
910                 return(-1);
911         /* goto end of chain again to set gsmflag*/
912         ifport = interface->ifport;
913         while(ifport->next)
914                 ifport = ifport->next;
915         ifport->gsm = 1;
916         return(0);
917 #endif
918 }
919 static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value)
920 {
921         struct interface_port *ifport;
922
923         /* port in chain ? */
924         if (!interface->ifport) {
925                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
926                 return(-1);
927         }
928         /* goto end of chain */
929         ifport = interface->ifport;
930         while(ifport->next)
931                 ifport = ifport->next;
932         ifport->nonotify = 1;
933         return(0);
934 }
935 #ifdef WITH_SS5
936 static int inter_ss5(struct interface *interface, char *filename, int line, char *parameter, char *value)
937 {
938         struct interface_port *ifport;
939         char *element;
940
941         /* port in chain ? */
942         if (!interface->ifport) {
943                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
944                 return(-1);
945         }
946         /* goto end of chain */
947         ifport = interface->ifport;
948         while(ifport->next)
949                 ifport = ifport->next;
950         ifport->ss5 |= SS5_ENABLE;
951         while((element = strsep(&value, " "))) {
952                 if (element[0] == '\0')
953                         continue;
954                 if (!strcasecmp(element, "connect"))
955                         ifport->ss5 |= SS5_FEATURE_CONNECT;
956                 else
957                 if (!strcasecmp(element, "nodisconnect"))
958                         ifport->ss5 |= SS5_FEATURE_NODISCONNECT;
959                 else
960                 if (!strcasecmp(element, "releaseguardtimer"))
961                         ifport->ss5 |= SS5_FEATURE_RELEASEGUARDTIMER;
962                 else
963                 if (!strcasecmp(element, "bell"))
964                         ifport->ss5 |= SS5_FEATURE_BELL;
965                 else
966                 if (!strcasecmp(element, "pulsedialing"))
967                         ifport->ss5 |= SS5_FEATURE_PULSEDIALING;
968                 else
969                 if (!strcasecmp(element, "delay"))
970                         ifport->ss5 |= SS5_FEATURE_DELAY;
971                 else
972                 if (!strcasecmp(element, "starrelease"))
973                         ifport->ss5 |= SS5_FEATURE_STAR_RELEASE;
974                 else
975                 if (!strcasecmp(element, "suppress"))
976                         ifport->ss5 |= SS5_FEATURE_SUPPRESS;
977                 else {
978                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' does not allow value element '%s'.\n", filename, line, parameter, element);
979                         return(-1);
980                 }
981         }
982         return(0);
983 }
984 #endif
985
986
987 /*
988  * structure of parameters
989  */
990 struct interface_param interface_param[] = {
991         { "extension", &inter_extension, "",
992         "If keyword is given, calls to interface are handled as internal extensions."},
993
994         { "extern", &inter_extern, "",
995         "If keyword is given, this interface will be used for external calls.\n"
996         "Calls require an external interface, if the routing action 'extern' is used\nwithout specific interface given.\n"
997         "Calls forwarded by extension's 'settings' also require an external interface."},
998
999         {"tones", &inter_tones, "yes | no",
1000         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
1001
1002         {"earlyb", &inter_earlyb, "yes | no",
1003         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
1004
1005         {"hunt", &inter_hunt, "linear | roundrobin",
1006         "Select the algorithm for selecting port with free channel."},
1007
1008         {"port", &inter_port, "<number>",
1009         ""},
1010         {"portnum", &inter_portnum, "<number>",
1011         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
1012         {"portname", &inter_portname, "<name>",
1013         "Same as 'portnum', but the name is given instead.\nUse 'isdninfo' to list all available ports and names."},
1014
1015         {"block", &inter_block, "",
1016         "If keyword is given, calls on this interface are blocked.\n"
1017         "This parameter must follow a 'port' parameter."},
1018
1019         {"ptp", &inter_ptp, "",
1020         "The given port above is opened as point-to-point.\n"
1021         "This is required on NT-mode ports that are multipoint by default.\n"
1022         "This parameter must follow a 'port' parameter."},
1023
1024 #if 0
1025         {"ptmp", &inter_ptmp, "",
1026         "The given port above is opened as point-to-multipoint.\n"
1027         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
1028         "This parameter must follow a 'port' parameter."},
1029 #endif
1030
1031         {"nt", &inter_nt, "",
1032         "The given port above is opened in NT-mode.\n"
1033         "This is required on interfaces that support both NT-mode and TE-mode.\n"
1034         "This parameter must follow a 'port' parameter."},
1035
1036         {"te-special", &inter_tespecial, "",
1037         "The given port uses a modified TE-mode.\n"
1038         "All information elements that are allowed Network->User will then be\n"
1039         "transmitted User->Network also. This is usefull to pass all informations\n"
1040         "between two interconnected LCRs, like 'redirected number' or 'display'.\n"
1041         "Note that this is not compliant with ISDN protocol.\n"
1042         "This parameter must follow a 'port' parameter."},
1043
1044         {"layer1hold", &inter_l1hold, "yes | no",
1045         "The given port will not release layer 1 after layer 2 is down.\n"
1046         "It is required to keep layer 1 of telephones up, to solve activation problems.\n"
1047         "This parameter must follow a 'port' parameter."},
1048
1049         {"layer2hold", &inter_l2hold, "yes | no",
1050         "The given port will continuously try to establish layer 2 link and hold it.\n"
1051         "It is required for PTP links in most cases, therefore it is default.\n"
1052         "This parameter must follow a 'port' parameter."},
1053
1054         {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
1055         "Channel selection list for all outgoing calls to the interface.\n"
1056         "A free channels is searched in order of appearance.\n"
1057         "This parameter must follow a 'port' parameter.\n"
1058         " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
1059         " <number>[,...] - List of channels to search.\n"
1060         " free - Select any free channel\n"
1061         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
1062         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
1063
1064         {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
1065         "Channel selection list for all incoming calls from the interface.\n"
1066         "A free channels is accepted if in the list.\n"
1067         "If any channel was requested, the first free channel found is selected.\n"
1068         "This parameter must follow a 'port' parameter.\n"
1069         " <number>[,...] - List of channels to accept.\n"
1070         " free - Accept any free channel"},
1071
1072         {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
1073         "Timeout values for call states. They are both for incoming and outgoing states.\n"
1074         "The default is 120 seconds for all states. Use 0 to disable.\n"
1075         "This parameter must follow a 'port' parameter.\n"},
1076
1077         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
1078         "Incoming caller ID is checked against given MSN numbers.\n"
1079         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
1080
1081         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1082         "Adds an entry for incoming calls to the caller ID screen list.\n"
1083         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
1084         "If '%' is given after old caller ID, it matches even if caller ID has\n"
1085         "additional digits.\n"
1086         "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
1087         "are added.\n"
1088         "Options can be:\n"
1089         " unknown | subsciber | national | international - Change caller ID type.\n"
1090         " present | restrict - Change presentation of caller ID."},
1091                 
1092         {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1093         "Adds an entry for outgoing calls to the caller ID screen list.\n"
1094         "See 'screen-in' for help."},
1095
1096         {"nodtmf", &inter_nodtmf, "",
1097         "Disables DTMF detection for this interface.\n"
1098         "This parameter must follow a 'port' parameter."},
1099
1100         {"filter", &inter_filter, "<filter> <parameters>",
1101         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
1102         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
1103         "pipeline <string> - Sets echo cancelation pipeline.\n"
1104         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
1105
1106         {"dialmax", &inter_dialmax, "<digits>",
1107         "Limits the number of digits in setup/information message."},
1108
1109         {"tones_dir", &inter_tones_dir, "<path>",
1110         "Overrides the given tone_dir in options.conf.\n"
1111         "To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
1112
1113         {"gsm", &inter_gsm, "",
1114         "Sets up GSM interface for using OpenBSC.\n"
1115         "This interface must be a loopback interface. The second loopback interface\n"
1116         "must be assigned to OpenBSC."},
1117
1118         {"nonotify", &inter_nonotify, "",
1119         "Prevents sending notify messages to this interface. A call placed on hold will\n"
1120         "Not affect the remote end (phone or telcom switch).\n"
1121         "This parameter must follow a 'port' parameter."},
1122
1123 #ifdef WITH_SS5
1124         {"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
1125         "Interface uses CCITT No. 5 inband signalling rather than D-channel.\n"
1126         "This feature causes CPU load to rise and has no practical intend.\n"
1127         "If you don't know what it is, you don't need it.\n"
1128         "Features apply to protocol behaviour and blueboxing specials, they are:\n"
1129         " connect - Connect incomming call to throughconnect audio, if required.\n"
1130         " nodisconnect - Don't disconnect if incomming exchange disconnects.\n"
1131         " releaseguardtimer - Tries to prevent Blueboxing by a longer release-guard.\n"
1132         " bell - Allow releasing and pulse-dialing via 2600 Hz like old Bell systems.\n"
1133         " pulsedialing - Use pulse dialing on outgoing exchange. (takes long!)\n"
1134         " delay - Use on incomming exchange, to make you feel a delay when blueboxing.\n"
1135         " starrelease - Pulse dialing a star (11 pulses per digit) clears current call.\n"
1136         " suppress - Suppress received tones, as they will be recognized."},
1137 #endif
1138
1139         {NULL, NULL, NULL, NULL}
1140 };
1141
1142 /* read interfaces
1143  *
1144  * read settings from interface.conf
1145  */
1146 char interface_error[256];
1147 struct interface *read_interfaces(void)
1148 {
1149         FILE                    *fp = NULL;
1150         char                    filename[128];
1151         char                    *p;
1152         unsigned int            line, i;
1153         char                    buffer[256];
1154         struct interface        *interface = NULL, /* in case no interface */
1155                                 **interfacep = &interface_newlist;
1156         char                    parameter[128];
1157         char                    value[256];
1158         int                     expecting = 1; /* expecting new interface */
1159         struct interface_param  *ifparam;
1160
1161         if (interface_newlist != NULL)
1162                 FATAL("list is not empty.\n");
1163         interface_error[0] = '\0';
1164         SPRINT(filename, "%s/interface.conf", CONFIG_DATA);
1165
1166         if (!(fp = fopen(filename,"r"))) {
1167                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
1168                 goto error;
1169         }
1170
1171         line=0;
1172         while((GETLINE(buffer, fp))) {
1173                 p=buffer;
1174                 line++;
1175
1176                 while(*p <= 32) { /* skip spaces */
1177                         if (*p == 0)
1178                                 break;
1179                         p++;
1180                 }
1181                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1182                         continue;
1183
1184                 parameter[0]=0;
1185                 value[0]=0;
1186                 i=0; /* read parameter */
1187                 while(*p > 32) {
1188                         if (i+1 >= sizeof(parameter)) {
1189                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
1190                                 goto error;
1191                         }
1192                         parameter[i+1] = '\0';
1193                         parameter[i++] = *p++;
1194                 }
1195
1196                 while(*p <= 32) { /* skip spaces */
1197                         if (*p == 0)
1198                                 break;
1199                         p++;
1200                 }
1201
1202                 if (*p!=0 && *p!='#') { /* missing name */
1203                         i=0; /* read until end */
1204                         while(*p!=0 && *p!='#') {
1205                                 if (i+1 >= sizeof(value)) {
1206                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
1207                                         goto error;
1208                                 }
1209                                 value[i+1] = '\0';
1210                                 value[i++] = *p++;
1211                         }
1212
1213                         /* remove trailing spaces from value */
1214                         while(i) {
1215                                 if (value[i-1]==0 || value[i-1]>32)
1216                                         break;
1217                                 value[i-1] = '\0';
1218                                 i--;
1219                         }
1220                 }
1221
1222                 /* check for interface name as first statement */
1223                 if (expecting && parameter[0]!='[') {
1224                         SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1225                         goto error;
1226                 }
1227                 expecting = 0;
1228
1229                 /* check for new interface */
1230                 if (parameter[0] == '[') {
1231                         if (parameter[strlen(parameter)-1] != ']') {
1232                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1233                                 goto error;
1234                         }
1235                         parameter[strlen(parameter)-1] = '\0';
1236
1237                         /* check if interface name already exists */
1238                         interface = interface_newlist;
1239                         while(interface) {
1240                                 if (!strcasecmp(interface->name, parameter+1)) {
1241                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
1242                                         goto error;
1243                                 }
1244                                 interface = interface->next;
1245                         }
1246
1247                         /* append interface to new list */
1248                         interface = (struct interface *)MALLOC(sizeof(struct interface));
1249                         memuse++;
1250
1251                         /* name interface */
1252                         SCPY(interface->name, parameter+1);
1253
1254                         /* attach */
1255                         *interfacep = interface;
1256                         interfacep = &interface->next;
1257
1258                         continue;
1259                 }
1260
1261                 ifparam = interface_param;
1262                 while(ifparam->name) {
1263                         if (!strcasecmp(parameter, ifparam->name)) {
1264                                 if (ifparam->func(interface, filename, line, parameter, value))
1265                                         goto error;
1266                                 break;
1267                         }
1268                         ifparam++;
1269                 }
1270                 if (ifparam->name)
1271                         continue;
1272
1273                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1274                 goto error;
1275         }
1276
1277         if (fp) fclose(fp);
1278         return(interface_newlist);
1279 error:
1280         PERROR_RUNTIME("%s", interface_error);
1281         if (fp) fclose(fp);
1282         free_interfaces(interface_newlist);
1283         interface_newlist = NULL;
1284         return(NULL);
1285 }
1286
1287
1288 /*
1289  * freeing chain of interfaces
1290  */
1291 void free_interfaces(struct interface *interface)
1292 {
1293         void *temp;
1294         struct interface_port *ifport;
1295         struct select_channel *selchannel;
1296         struct interface_msn *ifmsn;
1297         struct interface_screen *ifscreen;
1298
1299         while(interface) {
1300                 ifport = interface->ifport;
1301                 while(ifport) {
1302                         selchannel = ifport->in_channel;
1303                         while(selchannel) {
1304                                 temp = selchannel;
1305                                 selchannel = selchannel->next;
1306                                 FREE(temp, sizeof(struct select_channel));
1307                                 memuse--;
1308                         }
1309                         selchannel = ifport->out_channel;
1310                         while(selchannel) {
1311                                 temp = selchannel;
1312                                 selchannel = selchannel->next;
1313                                 FREE(temp, sizeof(struct select_channel));
1314                                 memuse--;
1315                         }
1316                         temp = ifport;
1317                         ifport = ifport->next;
1318                         FREE(temp, sizeof(struct interface_port));
1319                         memuse--;
1320                 }
1321                 ifmsn = interface->ifmsn;
1322                 while(ifmsn) {
1323                         temp = ifmsn;
1324                         ifmsn = ifmsn->next;
1325                         FREE(temp, sizeof(struct interface_msn));
1326                         memuse--;
1327                 }
1328                 ifscreen = interface->ifscreen_in;
1329                 while(ifscreen) {
1330                         temp = ifscreen;
1331                         ifscreen = ifscreen->next;
1332                         FREE(temp, sizeof(struct interface_screen));
1333                         memuse--;
1334                 }
1335                 ifscreen = interface->ifscreen_out;
1336                 while(ifscreen) {
1337                         temp = ifscreen;
1338                         ifscreen = ifscreen->next;
1339                         FREE(temp, sizeof(struct interface_screen));
1340                         memuse--;
1341                 }
1342                 temp = interface;
1343                 interface = interface->next;
1344                 FREE(temp, sizeof(struct interface));
1345                 memuse--;
1346         }
1347 }
1348
1349 /*
1350  * defaults of ports if not specified by config
1351  */
1352 static void set_defaults(struct interface_port *ifport)
1353 {
1354         /* default channel selection list */
1355         if (!ifport->out_channel)
1356                 default_out_channel(ifport);
1357         if (!ifport->in_channel)
1358                 default_in_channel(ifport);
1359         /* default is_tones */
1360         if (ifport->interface->is_tones)
1361                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1362         else
1363                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode || ifport->mISDNport->ss5)?1:0;
1364         /* default is_earlyb */
1365         if (ifport->interface->is_earlyb)
1366                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1367         else
1368                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode && !ifport->mISDNport->ss5)?0:1;
1369         /* set locally flag */
1370         if (ifport->interface->extension)
1371                 ifport->mISDNport->locally = 1;
1372         else
1373                 ifport->mISDNport->locally = 0;
1374 }
1375
1376
1377 /*
1378  * all links between mISDNport and interface are made
1379  * unused mISDNports are closed, new mISDNports are opened
1380  * also set default select_channel lists
1381  */
1382 void relink_interfaces(void)
1383 {
1384         struct mISDNport *mISDNport;
1385         struct interface *interface;
1386         struct interface_port *ifport;
1387
1388         /* unlink all mISDNports */
1389         mISDNport = mISDNport_first;
1390         while(mISDNport) {
1391                 mISDNport->ifport = NULL;
1392                 mISDNport = mISDNport->next;
1393         }
1394
1395         /* relink existing mISDNports */
1396         interface = interface_newlist;
1397         while(interface) {
1398                 ifport = interface->ifport;
1399                 while(ifport) {
1400                         mISDNport = mISDNport_first;
1401                         while(mISDNport) {
1402                                 if (!strcmp(mISDNport->name, ifport->portname))
1403                                         ifport->portnum = mISDNport->portnum; /* same name, so we use same number */
1404                                 if (mISDNport->portnum == ifport->portnum) {
1405                                         PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", ifport->portnum, ifport->portname);
1406                                         ifport->mISDNport = mISDNport;
1407                                         mISDNport->ifport = ifport;
1408                                         set_defaults(ifport);
1409                                 }
1410                                 mISDNport = mISDNport->next;
1411                         }
1412                         ifport = ifport->next;
1413                 }
1414                 interface = interface->next;
1415         }
1416
1417         /* close unused mISDNports */
1418         closeagain:
1419         mISDNport = mISDNport_first;
1420         while(mISDNport) {
1421                 if (mISDNport->ifport == NULL) {
1422                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1423                         /* remove all port objects and destroy port */
1424                         mISDNport_close(mISDNport);
1425                         goto closeagain;
1426                 }
1427                 mISDNport = mISDNport->next;
1428         }
1429
1430         /* open and link new mISDNports */
1431         interface = interface_newlist;
1432         while(interface) {
1433                 ifport = interface->ifport;
1434                 while(ifport) {
1435                         if (!ifport->mISDNport) {
1436                                 load_port(ifport);
1437                         }
1438                         ifport = ifport->next;
1439                 }
1440                 interface = interface->next;
1441         }
1442
1443 }
1444
1445
1446 /*
1447  * load port
1448  */
1449 void load_port(struct interface_port *ifport)
1450 {
1451         struct mISDNport *mISDNport;
1452
1453         /* open new port */
1454         mISDNport = mISDNport_open(ifport);
1455         if (mISDNport) {
1456                 /* link port */
1457                 ifport->mISDNport = mISDNport;
1458                 mISDNport->ifport = ifport;
1459                 /* set number and name */
1460                 ifport->portnum = mISDNport->portnum;
1461                 SCPY(ifport->portname, mISDNport->name);
1462                 /* set defaults */
1463                 set_defaults(ifport);
1464                 /* load static port instances */
1465                 mISDNport_static(mISDNport);
1466         } else {
1467                 ifport->block = 2; /* not available */
1468         }
1469 }
1470
1471 /*
1472  * give summary of interface syntax
1473  */
1474 void doc_interface(void)
1475 {
1476         struct interface_param *ifparam;
1477         
1478         printf("Syntax overview\n");
1479         printf("---------------\n\n");
1480
1481         printf("[<name>]\n");
1482         ifparam = interface_param;
1483         while(ifparam->name) {
1484                 if (ifparam->name[0])
1485                         printf("%s %s\n", ifparam->name, ifparam->usage);
1486                 ifparam++;
1487         }
1488
1489         ifparam = interface_param;
1490         while(ifparam->name) {
1491                 if (ifparam->name[0]) {
1492                         printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1493                         printf("%s\n", ifparam->help);
1494                 }
1495                 ifparam++;
1496         }
1497 }
1498
1499
1500 /* screen caller id
1501  * out==0: incoming caller id, out==1: outgoing caller id
1502  */
1503 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1504 {
1505         char                    *msn1;
1506         struct interface_msn    *ifmsn;
1507         struct interface_screen *ifscreen;
1508         char suffix[64];
1509
1510         /* screen incoming caller id */
1511         if (!out) {
1512                 /* check for MSN numbers, use first MSN if no match */
1513                 msn1 = NULL;
1514                 ifmsn = interface->ifmsn;
1515                 while(ifmsn) {
1516                         if (!msn1)
1517                                 msn1 = ifmsn->msn;
1518                         if (!strcmp(ifmsn->msn, id)) {
1519                                 break;
1520                         }
1521                         ifmsn = ifmsn->next;
1522                 }
1523                 if (ifmsn) {
1524                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (found in MSN list)");
1525                         add_trace("msn", NULL, "%s", id);
1526                         end_trace();
1527                 }
1528                 if (!ifmsn && msn1) { // not in list, first msn given
1529                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (not found in MSN list)");
1530                         add_trace("msn", "given", "%s", id);
1531                         add_trace("msn", "used", "%s", msn1);
1532                         end_trace();
1533                         UNCPY(id, msn1, idsize);
1534                         id[idsize-1] = '\0';
1535                 }
1536         }
1537
1538         /* check screen list */
1539         if (out)
1540                 ifscreen = interface->ifscreen_out;
1541         else
1542                 ifscreen = interface->ifscreen_in;
1543         while (ifscreen) {
1544                 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1545                 if (ifscreen->match_present==-1 || ifscreen->match_present==*present) {
1546                         if (strchr(ifscreen->match,'%')) {
1547                                 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1548                                         break;
1549                         } else {
1550                                 if (!strcmp(ifscreen->match, id))
1551                                         break;
1552                         }
1553                 }
1554                 ifscreen = ifscreen->next;
1555         }
1556         if (ifscreen) { // match
1557                 start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, out?DIRECTION_OUT:DIRECTION_IN, 0, 0, "SCREEN (found in screen list)");
1558                 switch(*type) {
1559                         case INFO_NTYPE_UNKNOWN:
1560                         add_trace("given", "type", "unknown");
1561                         break;
1562                         case INFO_NTYPE_SUBSCRIBER:
1563                         add_trace("given", "type", "subscriber");
1564                         break;
1565                         case INFO_NTYPE_NATIONAL:
1566                         add_trace("given", "type", "national");
1567                         break;
1568                         case INFO_NTYPE_INTERNATIONAL:
1569                         add_trace("given", "type", "international");
1570                         break;
1571                 }
1572                 switch(*present) {
1573                         case INFO_PRESENT_ALLOWED:
1574                         add_trace("given", "present", "allowed");
1575                         break;
1576                         case INFO_PRESENT_RESTRICTED:
1577                         add_trace("given", "present", "restricted");
1578                         break;
1579                         case INFO_PRESENT_NOTAVAIL:
1580                         add_trace("given", "present", "not available");
1581                         break;
1582                 }
1583                 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1584                 if (ifscreen->result_type != -1) {
1585                         *type = ifscreen->result_type;
1586                         switch(*type) {
1587                                 case INFO_NTYPE_UNKNOWN:
1588                                 add_trace("used", "type", "unknown");
1589                                 break;
1590                                 case INFO_NTYPE_SUBSCRIBER:
1591                                 add_trace("used", "type", "subscriber");
1592                                 break;
1593                                 case INFO_NTYPE_NATIONAL:
1594                                 add_trace("used", "type", "national");
1595                                 break;
1596                                 case INFO_NTYPE_INTERNATIONAL:
1597                                 add_trace("used", "type", "international");
1598                                 break;
1599                         }
1600                 }
1601                 if (ifscreen->result_present != -1) {
1602                         *present = ifscreen->result_present;
1603                         switch(*present) {
1604                                 case INFO_PRESENT_ALLOWED:
1605                                 add_trace("used", "present", "allowed");
1606                                 break;
1607                                 case INFO_PRESENT_RESTRICTED:
1608                                 add_trace("used", "present", "restricted");
1609                                 break;
1610                                 case INFO_PRESENT_NOTAVAIL:
1611                                 add_trace("used", "present", "not available");
1612                                 break;
1613                         }
1614                 }
1615                 if (strchr(ifscreen->match,'%')) {
1616                         SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1617                         UNCPY(id, ifscreen->result, idsize);
1618                         id[idsize-1] = '\0';
1619                         if (strchr(id,'%')) {
1620                                 *strchr(id,'%') = '\0';
1621                                 UNCAT(id, suffix, idsize);
1622                                 id[idsize-1] = '\0';
1623                         }
1624                 } else {
1625                         UNCPY(id, ifscreen->result, idsize);
1626                         id[idsize-1] = '\0';
1627                 }
1628                 add_trace("used", "id", "%s", id[0]?id:"<empty>");
1629                 end_trace();
1630         }
1631 }
1632