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