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