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