e7ab1710d94008ebba1cb368ecbf43be73424cb5
[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 (options.gsm && !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", options.loopback_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", options.loopback_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 static int inter_remote(struct interface *interface, char *filename, int line, char *parameter, char *value)
1058 {
1059         struct interface_port *ifport;
1060         struct interface *searchif;
1061
1062         if (!value[0]) {
1063                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects application name as value.\n", filename, line, parameter);
1064                 return(-1);
1065         }
1066         searchif = interface_newlist;
1067         while(searchif) {
1068                 ifport = searchif->ifport;
1069                 while(ifport) {
1070                         if (ifport->remote && !strcmp(ifport->remote_app, value)) {
1071                                 SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses remote application '%s'.\n", filename, line, ifport->portname, value);
1072                                 return(-1);
1073                         }
1074                         ifport = ifport->next;
1075                 }
1076                 searchif = searchif->next;
1077         }
1078
1079         /* set portname */
1080         if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
1081                 return(-1);
1082
1083         /* goto end of chain again to set application name */
1084         ifport = interface->ifport;
1085         while(ifport->next)
1086                 ifport = ifport->next;
1087         ifport->remote = 1;
1088         SCPY(ifport->remote_app, value);
1089
1090
1091         return(0);
1092 }
1093
1094
1095 /*
1096  * structure of parameters
1097  */
1098 struct interface_param interface_param[] = {
1099         { "extension", &inter_extension, "",
1100         "If keyword is given, calls to interface are handled as internal extensions."},
1101
1102         { "extern", &inter_extern, "",
1103         "If keyword is given, this interface will be used for external calls.\n"
1104         "Calls require an external interface, if the routing action 'extern' is used\nwithout specific interface given.\n"
1105         "Calls forwarded by extension's 'settings' also require an external interface."},
1106
1107         {"tones", &inter_tones, "yes | no",
1108         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
1109
1110         {"earlyb", &inter_earlyb, "yes | no",
1111         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
1112
1113         {"hunt", &inter_hunt, "linear | roundrobin",
1114         "Select the algorithm for selecting port with free channel."},
1115
1116         {"port", &inter_port, "<number>",
1117         ""},
1118         {"portnum", &inter_portnum, "<number>",
1119         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
1120         {"portname", &inter_portname, "<name>",
1121         "Same as 'portnum', but the name is given instead.\nUse 'isdninfo' to list all available ports and names."},
1122
1123         {"block", &inter_block, "",
1124         "If keyword is given, calls on this interface are blocked.\n"
1125         "This parameter must follow a 'port' parameter."},
1126
1127         {"ptp", &inter_ptp, "",
1128         "The given port above is opened as point-to-point.\n"
1129         "This is required on NT-mode ports that are multipoint by default.\n"
1130         "This parameter must follow a 'port' parameter."},
1131
1132 #if 0
1133         {"ptmp", &inter_ptmp, "",
1134         "The given port above is opened as point-to-multipoint.\n"
1135         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
1136         "This parameter must follow a 'port' parameter."},
1137 #endif
1138
1139         {"nt", &inter_nt, "",
1140         "The given port above is opened in NT-mode.\n"
1141         "This is required on interfaces that support both NT-mode and TE-mode.\n"
1142         "This parameter must follow a 'port' parameter."},
1143
1144         {"te-special", &inter_tespecial, "",
1145         "The given port uses a modified TE-mode.\n"
1146         "All information elements that are allowed Network->User will then be\n"
1147         "transmitted User->Network also. This is usefull to pass all informations\n"
1148         "between two interconnected LCRs, like 'redirected number' or 'display'.\n"
1149         "Note that this is not compliant with ISDN protocol.\n"
1150         "This parameter must follow a 'port' parameter."},
1151
1152         {"layer1hold", &inter_l1hold, "yes | no",
1153         "The given port will not release layer 1 after layer 2 is down.\n"
1154         "It is required to keep layer 1 of telephones up, to solve activation problems.\n"
1155         "This parameter must follow a 'port' parameter."},
1156
1157         {"layer2hold", &inter_l2hold, "yes | no",
1158         "The given port will continuously try to establish layer 2 link and hold it.\n"
1159         "It is required for PTP links in most cases, therefore it is default.\n"
1160         "This parameter must follow a 'port' parameter."},
1161
1162         {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
1163         "Channel selection list for all outgoing calls to the interface.\n"
1164         "A free channels is searched in order of appearance.\n"
1165         "This parameter must follow a 'port' parameter.\n"
1166         " force - Forces the selected port with no acceptable alternative (see Q.931).\n"
1167         "  -> this will be automatically set for multipoint (ptmp) NT-mode ports\n"
1168         " <number>[,...] - List of channels to search.\n"
1169         " free - Select any free channel\n"
1170         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
1171         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
1172
1173         {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
1174         "Channel selection list for all incoming calls from the interface.\n"
1175         "A free channels is accepted if in the list.\n"
1176         "If any channel was requested, the first free channel found is selected.\n"
1177         "This parameter must follow a 'port' parameter.\n"
1178         " <number>[,...] - List of channels to accept.\n"
1179         " free - Accept any free channel"},
1180
1181         {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
1182         "Timeout values for call states. They are both for incoming and outgoing states.\n"
1183         "The default is 120 seconds for all states. Use 0 to disable.\n"
1184         "This parameter must follow a 'port' parameter.\n"},
1185
1186         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
1187         "Incoming caller ID is checked against given MSN numbers.\n"
1188         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
1189
1190         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1191         "Adds an entry for incoming calls to the caller ID screen list.\n"
1192         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
1193         "If '%' is given after old caller ID, it matches even if caller ID has\n"
1194         "additional digits.\n"
1195         "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
1196         "are added.\n"
1197         "Options can be:\n"
1198         " unknown | subsciber | national | international - Change caller ID type.\n"
1199         " present | restrict - Change presentation of caller ID."},
1200                 
1201         {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1202         "Adds an entry for outgoing calls to the caller ID screen list.\n"
1203         "See 'screen-in' for help."},
1204
1205         {"nodtmf", &inter_nodtmf, "",
1206         "Disables DTMF detection for this interface.\n"
1207         "This parameter must follow a 'port' parameter."},
1208
1209         {"filter", &inter_filter, "<filter> <parameters>",
1210         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
1211         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
1212         "pipeline <string> - Sets echo cancelation pipeline.\n"
1213         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
1214
1215         {"dialmax", &inter_dialmax, "<digits>",
1216         "Limits the number of digits in setup/information message."},
1217
1218         {"tones_dir", &inter_tones_dir, "<path>",
1219         "Overrides the given tone_dir in options.conf.\n"
1220         "To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
1221
1222         {"gsm", &inter_gsm, "",
1223         ""},
1224         {"gsm-bs", &inter_gsm_bs, "",
1225         "Sets up GSM base station interface for using OpenBSC.\n"
1226         "See the default/gsm.conf for configuration for this version."},
1227         {"gsm-ms", &inter_gsm_ms, "[<socket>]",
1228         "Sets up GSM mobile station interface for using Osmocom-BB.\n"
1229         "See the default/gsm.conf for configuration for this version.\n"
1230         "The name of the MS folows the interface name.\n"
1231         "The socket is /tmp/osmocom_l2 by default and need to be changed when multiple\n"
1232         "MS interfaces are used."},
1233         {"nonotify", &inter_nonotify, "",
1234         "Prevents sending notify messages to this interface. A call placed on hold will\n"
1235         "Not affect the remote end (phone or telcom switch).\n"
1236         "This parameter must follow a 'port' parameter."},
1237
1238 #ifdef WITH_SS5
1239         {"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
1240         "Interface uses CCITT No. 5 inband signalling rather than D-channel.\n"
1241         "This feature causes CPU load to rise and has no practical intend.\n"
1242         "If you don't know what it is, you don't need it.\n"
1243         "Features apply to protocol behaviour and blueboxing specials, they are:\n"
1244         " connect - Connect incomming call to throughconnect audio, if required.\n"
1245         " nodisconnect - Don't disconnect if incomming exchange disconnects.\n"
1246         " releaseguardtimer - Tries to prevent Blueboxing by a longer release-guard.\n"
1247         " bell - Allow releasing and pulse-dialing via 2600 Hz like old Bell systems.\n"
1248         " pulsedialing - Use pulse dialing on outgoing exchange. (takes long!)\n"
1249         " delay - Use on incomming exchange, to make you feel a delay when blueboxing.\n"
1250         " starrelease - Pulse dialing a star (11 pulses per digit) clears current call.\n"
1251         " suppress - Suppress received tones, as they will be recognized."},
1252 #endif
1253
1254         {"remote", &inter_remote, "<application>",
1255         "Sets up an interface that communicates with the remote application.\n"
1256         "Use \"asterisk\" to use chan_lcr as remote application."},
1257
1258         {NULL, NULL, NULL, NULL}
1259 };
1260
1261 /* read interfaces
1262  *
1263  * read settings from interface.conf
1264  */
1265 char interface_error[256];
1266 struct interface *read_interfaces(void)
1267 {
1268         FILE                    *fp = NULL;
1269         char                    filename[128];
1270         char                    *p;
1271         unsigned int            line, i;
1272         char                    buffer[256];
1273         struct interface        *interface = NULL, /* in case no interface */
1274                                 **interfacep = &interface_newlist;
1275         char                    parameter[128];
1276         char                    value[256];
1277         int                     expecting = 1; /* expecting new interface */
1278         struct interface_param  *ifparam;
1279
1280         if (interface_newlist != NULL)
1281                 FATAL("list is not empty.\n");
1282         interface_error[0] = '\0';
1283         SPRINT(filename, "%s/interface.conf", CONFIG_DATA);
1284
1285         if (!(fp = fopen(filename,"r"))) {
1286                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
1287                 goto error;
1288         }
1289
1290         line=0;
1291         while((GETLINE(buffer, fp))) {
1292                 p=buffer;
1293                 line++;
1294
1295                 while(*p <= 32) { /* skip spaces */
1296                         if (*p == 0)
1297                                 break;
1298                         p++;
1299                 }
1300                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1301                         continue;
1302
1303                 parameter[0]=0;
1304                 value[0]=0;
1305                 i=0; /* read parameter */
1306                 while(*p > 32) {
1307                         if (i+1 >= sizeof(parameter)) {
1308                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
1309                                 goto error;
1310                         }
1311                         parameter[i+1] = '\0';
1312                         parameter[i++] = *p++;
1313                 }
1314
1315                 while(*p <= 32) { /* skip spaces */
1316                         if (*p == 0)
1317                                 break;
1318                         p++;
1319                 }
1320
1321                 if (*p!=0 && *p!='#') { /* missing name */
1322                         i=0; /* read until end */
1323                         while(*p!=0 && *p!='#') {
1324                                 if (i+1 >= sizeof(value)) {
1325                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
1326                                         goto error;
1327                                 }
1328                                 value[i+1] = '\0';
1329                                 value[i++] = *p++;
1330                         }
1331
1332                         /* remove trailing spaces from value */
1333                         while(i) {
1334                                 if (value[i-1]==0 || value[i-1]>32)
1335                                         break;
1336                                 value[i-1] = '\0';
1337                                 i--;
1338                         }
1339                 }
1340
1341                 /* check for interface name as first statement */
1342                 if (expecting && parameter[0]!='[') {
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                 expecting = 0;
1347
1348                 /* check for new interface */
1349                 if (parameter[0] == '[') {
1350                         if (parameter[strlen(parameter)-1] != ']') {
1351                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1352                                 goto error;
1353                         }
1354                         parameter[strlen(parameter)-1] = '\0';
1355
1356                         /* check if interface name already exists */
1357                         interface = interface_newlist;
1358                         while(interface) {
1359                                 if (!strcasecmp(interface->name, parameter+1)) {
1360                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
1361                                         goto error;
1362                                 }
1363                                 interface = interface->next;
1364                         }
1365
1366                         /* append interface to new list */
1367                         interface = (struct interface *)MALLOC(sizeof(struct interface));
1368                         memuse++;
1369
1370                         /* name interface */
1371                         SCPY(interface->name, parameter+1);
1372
1373                         /* attach */
1374                         *interfacep = interface;
1375                         interfacep = &interface->next;
1376
1377                         continue;
1378                 }
1379
1380                 ifparam = interface_param;
1381                 while(ifparam->name) {
1382                         if (!strcasecmp(parameter, ifparam->name)) {
1383                                 if (ifparam->func(interface, filename, line, parameter, value))
1384                                         goto error;
1385                                 break;
1386                         }
1387                         ifparam++;
1388                 }
1389                 if (ifparam->name)
1390                         continue;
1391
1392                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1393                 goto error;
1394         }
1395
1396         if (fp) fclose(fp);
1397         return(interface_newlist);
1398 error:
1399         PERROR_RUNTIME("%s", interface_error);
1400         if (fp) fclose(fp);
1401         free_interfaces(interface_newlist);
1402         interface_newlist = NULL;
1403         return(NULL);
1404 }
1405
1406
1407 /*
1408  * freeing chain of interfaces
1409  */
1410 void free_interfaces(struct interface *interface)
1411 {
1412         void *temp;
1413         struct interface_port *ifport;
1414         struct select_channel *selchannel;
1415         struct interface_msn *ifmsn;
1416         struct interface_screen *ifscreen;
1417
1418         while(interface) {
1419                 ifport = interface->ifport;
1420                 while(ifport) {
1421                         selchannel = ifport->in_channel;
1422                         while(selchannel) {
1423                                 temp = selchannel;
1424                                 selchannel = selchannel->next;
1425                                 FREE(temp, sizeof(struct select_channel));
1426                                 memuse--;
1427                         }
1428                         selchannel = ifport->out_channel;
1429                         while(selchannel) {
1430                                 temp = selchannel;
1431                                 selchannel = selchannel->next;
1432                                 FREE(temp, sizeof(struct select_channel));
1433                                 memuse--;
1434                         }
1435                         temp = ifport;
1436                         ifport = ifport->next;
1437                         FREE(temp, sizeof(struct interface_port));
1438                         memuse--;
1439                 }
1440                 ifmsn = interface->ifmsn;
1441                 while(ifmsn) {
1442                         temp = ifmsn;
1443                         ifmsn = ifmsn->next;
1444                         FREE(temp, sizeof(struct interface_msn));
1445                         memuse--;
1446                 }
1447                 ifscreen = interface->ifscreen_in;
1448                 while(ifscreen) {
1449                         temp = ifscreen;
1450                         ifscreen = ifscreen->next;
1451                         FREE(temp, sizeof(struct interface_screen));
1452                         memuse--;
1453                 }
1454                 ifscreen = interface->ifscreen_out;
1455                 while(ifscreen) {
1456                         temp = ifscreen;
1457                         ifscreen = ifscreen->next;
1458                         FREE(temp, sizeof(struct interface_screen));
1459                         memuse--;
1460                 }
1461                 temp = interface;
1462                 interface = interface->next;
1463                 FREE(temp, sizeof(struct interface));
1464                 memuse--;
1465         }
1466 }
1467
1468 /*
1469  * defaults of ports if not specified by config
1470  */
1471 static void set_defaults(struct interface_port *ifport)
1472 {
1473         /* default channel selection list */
1474         if (!ifport->out_channel)
1475                 default_out_channel(ifport);
1476         if (!ifport->in_channel)
1477                 default_in_channel(ifport);
1478         /* must force the channel on PTMP/NT ports */
1479         if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode)
1480                 ifport->channel_force = 1;
1481         /* default is_tones */
1482         if (ifport->interface->is_tones)
1483                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1484         else
1485                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode || ifport->mISDNport->ss5)?1:0;
1486         /* default is_earlyb */
1487         if (ifport->interface->is_earlyb)
1488                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1489         else
1490                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode && !ifport->mISDNport->ss5)?0:1;
1491         /* set locally flag */
1492         if (ifport->interface->extension)
1493                 ifport->mISDNport->locally = 1;
1494         else
1495                 ifport->mISDNport->locally = 0;
1496 }
1497
1498
1499 /*
1500  * all links between mISDNport and interface are made
1501  * unused mISDNports are closed, new mISDNports are opened
1502  * also set default select_channel lists
1503  */
1504 void relink_interfaces(void)
1505 {
1506         struct mISDNport *mISDNport;
1507         struct interface *interface;
1508         struct interface_port *ifport;
1509
1510         /* unlink all mISDNports */
1511         mISDNport = mISDNport_first;
1512         while(mISDNport) {
1513                 mISDNport->ifport = NULL;
1514                 mISDNport = mISDNport->next;
1515         }
1516
1517         /* relink existing mISDNports */
1518         interface = interface_newlist;
1519         while(interface) {
1520                 ifport = interface->ifport;
1521                 while(ifport) {
1522                         mISDNport = mISDNport_first;
1523                         while(mISDNport) {
1524                                 if (!strcmp(mISDNport->name, ifport->portname))
1525                                         ifport->portnum = mISDNport->portnum; /* same name, so we use same number */
1526                                 if (mISDNport->portnum == ifport->portnum) {
1527                                         PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", ifport->portnum, ifport->portname);
1528                                         ifport->mISDNport = mISDNport;
1529                                         mISDNport->ifport = ifport;
1530                                         set_defaults(ifport);
1531                                 }
1532                                 mISDNport = mISDNport->next;
1533                         }
1534                         ifport = ifport->next;
1535                 }
1536                 interface = interface->next;
1537         }
1538
1539         /* close unused mISDNports */
1540         closeagain:
1541         mISDNport = mISDNport_first;
1542         while(mISDNport) {
1543                 if (mISDNport->ifport == NULL) {
1544                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1545                         /* remove all port objects and destroy port */
1546 #ifdef WITH_GSM_MS
1547                         if (ifport->gsm_ms)
1548                                 gsm_ms_delete(ifport->gsm_ms_name);
1549 #endif
1550                         mISDNport_close(mISDNport);
1551                         goto closeagain;
1552                 }
1553                 mISDNport = mISDNport->next;
1554         }
1555
1556         /* open and link new mISDNports */
1557         interface = interface_newlist;
1558         while(interface) {
1559                 ifport = interface->ifport;
1560                 while(ifport) {
1561                         if (!ifport->mISDNport) {
1562                                 load_port(ifport);
1563                         }
1564                         ifport = ifport->next;
1565                 }
1566                 interface = interface->next;
1567         }
1568
1569 }
1570
1571
1572 /*
1573  * load port
1574  */
1575 void load_port(struct interface_port *ifport)
1576 {
1577         struct mISDNport *mISDNport;
1578
1579         /* open new port */
1580         mISDNport = mISDNport_open(ifport);
1581         if (mISDNport) {
1582                 /* link port */
1583                 ifport->mISDNport = mISDNport;
1584                 mISDNport->ifport = ifport;
1585                 /* set number and name */
1586                 ifport->portnum = mISDNport->portnum;
1587                 SCPY(ifport->portname, mISDNport->name);
1588                 /* set defaults */
1589                 set_defaults(ifport);
1590                 /* load static port instances */
1591                 mISDNport_static(mISDNport);
1592 #ifdef WITH_GSM_MS
1593                 if (ifport->gsm_ms)
1594                         gsm_ms_new(ifport->gsm_ms_name, ifport->gsm_ms_socket);
1595 #endif
1596         } else {
1597                 ifport->block = 2; /* not available */
1598         }
1599 }
1600
1601 /*
1602  * give summary of interface syntax
1603  */
1604 void doc_interface(void)
1605 {
1606         struct interface_param *ifparam;
1607         
1608         printf("Syntax overview\n");
1609         printf("---------------\n\n");
1610
1611         printf("[<name>]\n");
1612         ifparam = interface_param;
1613         while(ifparam->name) {
1614                 if (ifparam->name[0])
1615                         printf("%s %s\n", ifparam->name, ifparam->usage);
1616                 ifparam++;
1617         }
1618
1619         ifparam = interface_param;
1620         while(ifparam->name) {
1621                 if (ifparam->name[0]) {
1622                         printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1623                         printf("%s\n", ifparam->help);
1624                 }
1625                 ifparam++;
1626         }
1627 }
1628
1629
1630 /* screen caller id
1631  * out==0: incoming caller id, out==1: outgoing caller id
1632  */
1633 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1634 {
1635         char                    *msn1;
1636         struct interface_msn    *ifmsn;
1637         struct interface_screen *ifscreen;
1638         char suffix[64];
1639
1640         /* screen incoming caller id */
1641         if (!out) {
1642                 /* check for MSN numbers, use first MSN if no match */
1643                 msn1 = NULL;
1644                 ifmsn = interface->ifmsn;
1645                 while(ifmsn) {
1646                         if (!msn1)
1647                                 msn1 = ifmsn->msn;
1648                         if (!strcmp(ifmsn->msn, id)) {
1649                                 break;
1650                         }
1651                         ifmsn = ifmsn->next;
1652                 }
1653                 if (ifmsn) {
1654                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (found in MSN list)");
1655                         add_trace("msn", NULL, "%s", id);
1656                         end_trace();
1657                 }
1658                 if (!ifmsn && msn1) { // not in list, first msn given
1659                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (not found in MSN list)");
1660                         add_trace("msn", "given", "%s", id);
1661                         add_trace("msn", "used", "%s", msn1);
1662                         end_trace();
1663                         UNCPY(id, msn1, idsize);
1664                         id[idsize-1] = '\0';
1665                 }
1666         }
1667
1668         /* check screen list */
1669         if (out)
1670                 ifscreen = interface->ifscreen_out;
1671         else
1672                 ifscreen = interface->ifscreen_in;
1673         while (ifscreen) {
1674                 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1675                 if (ifscreen->match_present==-1 || ifscreen->match_present==*present) {
1676                         if (strchr(ifscreen->match,'%')) {
1677                                 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1678                                         break;
1679                         } else {
1680                                 if (!strcmp(ifscreen->match, id))
1681                                         break;
1682                         }
1683                 }
1684                 ifscreen = ifscreen->next;
1685         }
1686         if (ifscreen) { // match
1687                 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)");
1688                 switch(*type) {
1689                         case INFO_NTYPE_UNKNOWN:
1690                         add_trace("given", "type", "unknown");
1691                         break;
1692                         case INFO_NTYPE_SUBSCRIBER:
1693                         add_trace("given", "type", "subscriber");
1694                         break;
1695                         case INFO_NTYPE_NATIONAL:
1696                         add_trace("given", "type", "national");
1697                         break;
1698                         case INFO_NTYPE_INTERNATIONAL:
1699                         add_trace("given", "type", "international");
1700                         break;
1701                 }
1702                 switch(*present) {
1703                         case INFO_PRESENT_ALLOWED:
1704                         add_trace("given", "present", "allowed");
1705                         break;
1706                         case INFO_PRESENT_RESTRICTED:
1707                         add_trace("given", "present", "restricted");
1708                         break;
1709                         case INFO_PRESENT_NOTAVAIL:
1710                         add_trace("given", "present", "not available");
1711                         break;
1712                 }
1713                 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1714                 if (ifscreen->result_type != -1) {
1715                         *type = ifscreen->result_type;
1716                         switch(*type) {
1717                                 case INFO_NTYPE_UNKNOWN:
1718                                 add_trace("used", "type", "unknown");
1719                                 break;
1720                                 case INFO_NTYPE_SUBSCRIBER:
1721                                 add_trace("used", "type", "subscriber");
1722                                 break;
1723                                 case INFO_NTYPE_NATIONAL:
1724                                 add_trace("used", "type", "national");
1725                                 break;
1726                                 case INFO_NTYPE_INTERNATIONAL:
1727                                 add_trace("used", "type", "international");
1728                                 break;
1729                         }
1730                 }
1731                 if (ifscreen->result_present != -1) {
1732                         *present = ifscreen->result_present;
1733                         switch(*present) {
1734                                 case INFO_PRESENT_ALLOWED:
1735                                 add_trace("used", "present", "allowed");
1736                                 break;
1737                                 case INFO_PRESENT_RESTRICTED:
1738                                 add_trace("used", "present", "restricted");
1739                                 break;
1740                                 case INFO_PRESENT_NOTAVAIL:
1741                                 add_trace("used", "present", "not available");
1742                                 break;
1743                         }
1744                 }
1745                 if (strchr(ifscreen->match,'%')) {
1746                         SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1747                         UNCPY(id, ifscreen->result, idsize);
1748                         id[idsize-1] = '\0';
1749                         if (strchr(id,'%')) {
1750                                 *strchr(id,'%') = '\0';
1751                                 UNCAT(id, suffix, idsize);
1752                                 id[idsize-1] = '\0';
1753                         }
1754                 } else {
1755                         UNCPY(id, ifscreen->result, idsize);
1756                         id[idsize-1] = '\0';
1757                 }
1758                 add_trace("used", "id", "%s", id[0]?id:"<empty>");
1759                 end_trace();
1760         }
1761 }
1762