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