Changes for Asterisk TRUNK r357721
[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 #ifdef WITH_MISDN
19 /* set default out_channel */
20 void default_out_channel(struct interface_port *ifport)
21 {
22         struct select_channel *selchannel, **selchannelp;
23
24         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
25         memuse++;
26
27         if (ifport->mISDNport->ntmode)
28                 selchannel->channel = CHANNEL_FREE;
29         else
30                 selchannel->channel = CHANNEL_ANY;
31         
32         ifport->out_channel = selchannel;
33
34         /* additional channel selection for multipoint NT ports */
35         if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode) {
36                 selchannelp = &(selchannel->next);
37                 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
38                 memuse++;
39                 selchannel->channel = CHANNEL_NO; // call waiting
40                 *selchannelp = selchannel;
41         }
42 }
43
44
45 /* set default in_channel */
46 void default_in_channel(struct interface_port *ifport)
47 {
48         struct select_channel *selchannel;
49
50         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
51         memuse++;
52         
53         selchannel->channel = CHANNEL_FREE;
54         
55         ifport->in_channel = selchannel;
56 }
57 #endif
58
59
60 /* parse string for a positive number */
61 static int get_number(char *value)
62 {
63         int val = 0;
64         char text[10];
65
66         val = atoi(value);
67         
68         SPRINT(text, "%d", val);
69
70         if (!strcmp(value, text))
71                 return(val);
72
73         return(-1);
74 }
75
76
77 /* remove element from buffer
78  * and return pointer to next element in buffer */
79 static char *get_seperated(char *buffer)
80 {
81         while(*buffer) {
82                 if (*buffer==',' || *buffer<=32) { /* seperate */
83                         *buffer++ = '\0';
84                         while((*buffer>'\0' && *buffer<=32) || *buffer==',')
85                                 buffer++;
86                         return(buffer);
87                 }
88                 buffer++;
89         }
90         return(buffer);
91 }
92
93 /*
94  * parameter processing
95  */
96 static int inter_block(struct interface *interface, char *filename, int line, char *parameter, char *value)
97 {
98         struct interface_port *ifport;
99
100         /* port in chain ? */
101         if (!interface->ifport) {
102                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
103                 return(-1);
104         }
105         /* goto end of chain */
106         ifport = interface->ifport;
107         while(ifport->next)
108                 ifport = ifport->next;
109         /* add value */
110         if (value[0]) {
111                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
112                 return(-1);
113         }
114         ifport->block = 1;
115         return(0);
116 }
117 static int inter_extension(struct interface *interface, char *filename, int line, char *parameter, char *value)
118 {
119         if (interface->external) {
120                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is external interface.\n", filename, line, parameter);
121                 return(-1);
122         }
123         if (value[0]) {
124                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
125                 return(-1);
126         }
127         interface->extension = 1;
128         return(0);
129 }
130 static int inter_extern(struct interface *interface, char *filename, int line, char *parameter, char *value)
131 {
132         if (interface->extension) {
133                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed, because interface is an extension.\n", filename, line, parameter);
134                 return(-1);
135         }
136         if (value[0]) {
137                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
138                 return(-1);
139         }
140         interface->external = 1;
141         return(0);
142 }
143 static int inter_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
144 {
145         struct interface_port *ifport;
146
147         /* port in chain ? */
148         if (!interface->ifport) {
149                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
150                 return(-1);
151         }
152         if (interface->ifport->ptmp) {
153                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptmp was given.\n", filename, line, parameter);
154                 return(-1);
155         }
156         /* goto end of chain */
157         ifport = interface->ifport;
158         while(ifport->next)
159                 ifport = ifport->next;
160         /* add value */
161         if (value[0]) {
162                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
163                 return(-1);
164         }
165         ifport->ptp = 1;
166         return(0);
167 }
168 #if 0
169 static int inter_ptmp(struct interface *interface, char *filename, int line, char *parameter, char *value)
170 {
171         struct interface_port *ifport;
172
173         /* port in chain ? */
174         if (!interface->ifport) {
175                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
176                 return(-1);
177         }
178         if (interface->ifport->ptp) {
179                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptp was given.\n", filename, line, parameter);
180                 return(-1);
181         }
182         /* goto end of chain */
183         ifport = interface->ifport;
184         while(ifport->next)
185                 ifport = ifport->next;
186         /* add value */
187         if (value[0]) {
188                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
189                 return(-1);
190         }
191         ifport->ptmp = 1;
192         return(0);
193 }
194 #endif
195 static int inter_nt(struct interface *interface, char *filename, int line, char *parameter, char *value)
196 {
197         struct interface_port *ifport;
198
199         /* port in chain ? */
200         if (!interface->ifport) {
201                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
202                 return(-1);
203         }
204         /* goto end of chain */
205         ifport = interface->ifport;
206         while(ifport->next)
207                 ifport = ifport->next;
208         /* add value */
209         if (value[0]) {
210                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
211                 return(-1);
212         }
213         ifport->nt = 1;
214         return(0);
215 }
216 static int inter_tespecial(struct interface *interface, char *filename, int line, char *parameter, char *value)
217 {
218         struct interface_port *ifport;
219
220         /* port in chain ? */
221         if (!interface->ifport) {
222                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
223                 return(-1);
224         }
225         /* goto end of chain */
226         ifport = interface->ifport;
227         while(ifport->next)
228                 ifport = ifport->next;
229         /* add value */
230         if (value[0]) {
231                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
232                 return(-1);
233         }
234         ifport->tespecial = 1;
235         return(0);
236 }
237 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
238 {
239         if (!strcasecmp(value, "yes")) {
240                 interface->is_tones = IS_YES;
241         } else
242         if (!strcasecmp(value, "no")) {
243                 interface->is_tones = IS_NO;
244         } else {
245                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
246                 return(-1);
247         }
248         return(0);
249 }
250 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
251 {
252         if (!strcasecmp(value, "yes")) {
253                 interface->is_earlyb = IS_YES;
254         } else
255         if (!strcasecmp(value, "no")) {
256                 interface->is_earlyb = IS_NO;
257         } else {
258                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
259                 return(-1);
260         }
261         return(0);
262 }
263 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
264 {
265         if (!strcasecmp(value, "linear")) {
266                 interface->hunt = HUNT_LINEAR;
267         } else
268         if (!strcasecmp(value, "roundrobin")) {
269                 interface->hunt = HUNT_ROUNDROBIN;
270         } else {
271                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
272                 return(-1);
273         }
274         return(0);
275 }
276 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
277 {
278         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);
279         return(-1);
280 }
281 static int inter_portnum(struct interface *interface, char *filename, int line, char *parameter, char *value)
282 {
283 #ifndef WITH_MISDN
284         SPRINT(interface_error, "Error in %s (line %d): mISDN support is not compiled in.\n", filename, line);
285         return(-1);
286 #else
287         struct interface_port *ifport, **ifportp;
288         struct interface *searchif;
289         int val;
290
291         val = get_number(value);
292         if (val == -1) {
293                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
294                 return(-1);
295         }
296         /* check for port already assigned */
297         searchif = interface_newlist;
298         while(searchif) {
299                 ifport = searchif->ifport;
300                 while(ifport) {
301                         if (ifport->portnum == val) {
302                                 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
303                                 return(-1);
304                         }
305                         ifport = ifport->next;
306                 }
307                 searchif = searchif->next;
308         }
309         /* alloc port substructure */
310         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
311         memuse++;
312         ifport->interface = interface;
313         /* set value */
314         ifport->portnum = val;
315         /* tail port */
316         ifportp = &interface->ifport;
317         while(*ifportp)
318                 ifportp = &((*ifportp)->next);
319         *ifportp = ifport;
320         return(0);
321 #endif
322 }
323 static int inter_portname(struct interface *interface, char *filename, int line, char *parameter, char *value)
324 {
325 #ifndef WITH_MISDN
326         SPRINT(interface_error, "Error in %s (line %d): mISDN support is not compiled in.\n", filename, line);
327         return(-1);
328 #else
329         struct interface_port *ifport, **ifportp;
330         struct interface *searchif;
331
332         /* goto end of chain */
333         ifport = interface->ifport;
334         if (ifport) {
335                 while(ifport->next)
336                         ifport = ifport->next;
337         }
338
339         /* check for port already assigned, but not for shared loop interface */
340         searchif = interface_newlist;
341         if (!!strcmp(value, options.loopback_lcr))
342         {
343                 while(searchif) {
344                         ifport = searchif->ifport;
345                         while(ifport) {
346                                 if (!strcasecmp(ifport->portname, value)) {
347                                         SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
348                                         return(-1);
349                                 }
350                                 ifport = ifport->next;
351                         }
352                         searchif = searchif->next;
353                 }
354         }
355         /* alloc port substructure */
356         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
357         memuse++;
358         ifport->interface = interface;
359         /* set value */
360         ifport->portnum = -1; // disable until resolved
361         SCPY(ifport->portname, value);
362         /* tail port */
363         ifportp = &interface->ifport;
364         while(*ifportp)
365                 ifportp = &((*ifportp)->next);
366         *ifportp = ifport;
367         return(0);
368 #endif
369 }
370 static int inter_l1hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
371 {
372         struct interface_port *ifport;
373
374         /* port in chain ? */
375         if (!interface->ifport) {
376                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
377                 return(-1);
378         }
379         /* goto end of chain */
380         ifport = interface->ifport;
381         while(ifport->next)
382                 ifport = ifport->next;
383         if (!strcmp(value, "yes")) {
384                 ifport->l1hold = 1;
385         } else
386         if (!strcmp(value, "no")) {
387                 ifport->l1hold = 0;
388         } else {
389                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
390                 return(-1);
391         }
392         return(0);
393 }
394 static int inter_l2hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
395 {
396         struct interface_port *ifport;
397
398         /* port in chain ? */
399         if (!interface->ifport) {
400                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
401                 return(-1);
402         }
403         /* goto end of chain */
404         ifport = interface->ifport;
405         while(ifport->next)
406                 ifport = ifport->next;
407         if (!strcmp(value, "yes")) {
408                 ifport->l2hold = 1;
409         } else
410         if (!strcmp(value, "no")) {
411                 ifport->l2hold = -1;
412         } else {
413                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
414                 return(-1);
415         }
416         return(0);
417 }
418 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
419 {
420         struct interface_port *ifport;
421         struct select_channel *selchannel, **selchannelp;
422         int val;
423         char *p, *el;
424
425         /* port in chain ? */
426         if (!interface->ifport) {
427                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
428                 return(-1);
429         }
430         /* goto end of chain */
431         ifport = interface->ifport;
432         while(ifport->next)
433                 ifport = ifport->next;
434         p = value;
435         while(*p) {
436                 el = p;
437                 p = get_seperated(p);
438                 if (!strcasecmp(el, "force")) {
439                         ifport->channel_force = 1;
440                         if (ifport->out_channel) {
441                                 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
442                                 return(-1);
443                         }
444                 } else
445                 if (!strcasecmp(el, "any")) {
446                         val = CHANNEL_ANY;
447                         goto selchannel;
448                 } else
449                 if (!strcasecmp(el, "free")) {
450                         val = CHANNEL_FREE;
451                         goto selchannel;
452                 } else
453                 if (!strcasecmp(el, "no")) {
454                         val = CHANNEL_NO;
455                         goto selchannel;
456                 } else {
457                         val = get_number(el);
458                         if (val == -1) {
459                                 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);
460                                 return(-1);
461                         }
462
463                         if (val<1 || val==16 || val>126) {
464                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
465                                 return(-1);
466                         }
467                         selchannel:
468                         /* add to select-channel list */
469                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
470                         memuse++;
471                         /* set value */
472                         selchannel->channel = val;
473                         /* tail port */
474                         selchannelp = &ifport->out_channel;
475                         while(*selchannelp)
476                                 selchannelp = &((*selchannelp)->next);
477                         *selchannelp = selchannel;
478                 }
479         }
480         return(0);
481 }
482 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
483 {
484         struct interface_port *ifport;
485         struct select_channel *selchannel, **selchannelp;
486         int val;
487         char *p, *el;
488
489         /* port in chain ? */
490         if (!interface->ifport) {
491                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
492                 return(-1);
493         }
494         /* goto end of chain */
495         ifport = interface->ifport;
496         while(ifport->next)
497                 ifport = ifport->next;
498         p = value;
499         while(*p) {
500                 el = p;
501                 p = get_seperated(p);
502                 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE) {
503                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
504                                 return(-1);
505                 }
506                 if (!strcasecmp(el, "free")) {
507                         val = CHANNEL_FREE;
508                         goto selchannel;
509                 } else {
510                         val = get_number(el);
511                         if (val == -1) {
512                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
513                                 return(-1);
514                         }
515
516                         if (val<1 || val==16 || val>126) {
517                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
518                                 return(-1);
519                         }
520                         selchannel:
521                         /* add to select-channel list */
522                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
523                         memuse++;
524                         /* set value */
525                         selchannel->channel = val;
526                         /* tail port */
527                         selchannelp = &ifport->in_channel;
528                         while(*selchannelp)
529                                 selchannelp = &((*selchannelp)->next);
530                         *selchannelp = selchannel;
531                 }
532         }
533         return(0);
534 }
535 static int inter_timeouts(struct interface *interface, char *filename, int line, char *parameter, char *value)
536 {
537         struct interface_port *ifport;
538 //      struct select_channel *selchannel, **selchannelp;
539 //      int val;
540         char *p, *el;
541
542         /* port in chain ? */
543         if (!interface->ifport) {
544                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
545                 return(-1);
546         }
547         /* goto end of chain */
548         ifport = interface->ifport;
549         while(ifport->next)
550                 ifport = ifport->next;
551         p = value;
552         if (!*p) {
553                 nofive:
554                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects five timeout values.\n", filename, line, parameter);
555                 return(-1);
556         }
557         el = p;
558         p = get_seperated(p);
559         ifport->tout_setup = atoi(el);
560         if (!*p)
561                 goto nofive;
562         el = p;
563         p = get_seperated(p);
564         ifport->tout_dialing = atoi(el);
565         if (!*p)
566                 goto nofive;
567         el = p;
568         p = get_seperated(p);
569         ifport->tout_proceeding = atoi(el);
570         if (!*p)
571                 goto nofive;
572         el = p;
573         p = get_seperated(p);
574         ifport->tout_alerting = atoi(el);
575         if (!*p)
576                 goto nofive;
577         el = p;
578         p = get_seperated(p);
579         ifport->tout_disconnect = atoi(el);
580         return(0);
581 }
582 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
583 {
584         struct interface_msn *ifmsn, **ifmsnp;
585         char *p, *el;
586
587         if (!value[0]) {
588                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
589                 return(-1);
590         }
591         if (interface->ifscreen_in) {
592                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
593                 return(-1);
594         }
595
596         /* process list */
597         p = value;
598         while(*p) {
599                 el = p;
600                 p = get_seperated(p);
601                 /* add MSN to list */
602                 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
603                 memuse++;
604                 /* set value */
605                 SCPY(ifmsn->msn, el);
606                 /* tail port */
607                 ifmsnp = &interface->ifmsn;
608                 while(*ifmsnp)
609                         ifmsnp = &((*ifmsnp)->next);
610                 *ifmsnp = ifmsn;
611         }
612         return(0);
613 }
614 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
615 {
616         struct interface_screen *ifscreen;
617         char *p, *el;
618
619         if (!value[0]) {
620                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
621                 return(-1);
622         }
623         /* add screen entry to list*/
624         ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
625         memuse++;
626         ifscreen->match_type = -1; /* unchecked */
627         ifscreen->match_present = -1; /* unchecked */
628         ifscreen->result_type = -1; /* unchanged */
629         ifscreen->result_present = -1; /* unchanged */
630         /* tail port */
631         while(*ifscreenp)
632                 ifscreenp = &((*ifscreenp)->next);
633         *ifscreenp = ifscreen;
634 //      printf("interface=%s\n", interface->name);
635         /* get match */
636         p = value;
637         while(*p) {
638                 el = p;
639                 p = get_seperated(p);
640                 if (!strcasecmp(el, "unknown")) {
641                         if (ifscreen->match_type != -1) {
642                                 typeerror:
643                                 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
644                                 return(-1);
645                         }
646                         ifscreen->match_type = INFO_NTYPE_UNKNOWN;
647                 } else
648                 if (!strcasecmp(el, "subscriber")) {
649                         if (ifscreen->match_type != -1)
650                                 goto typeerror;
651                         ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
652                 } else
653                 if (!strcasecmp(el, "national")) {
654                         if (ifscreen->match_type != -1)
655                                 goto typeerror;
656                         ifscreen->match_type = INFO_NTYPE_NATIONAL;
657                 } else
658                 if (!strcasecmp(el, "international")) {
659                         if (ifscreen->match_type != -1)
660                                 goto typeerror;
661                         ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
662                 } else
663                 if (!strcasecmp(el, "allowed")) {
664                         if (ifscreen->match_present != -1) {
665                                 presenterror:
666                                 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
667                                 return(-1);
668                         }
669                         ifscreen->match_present = INFO_PRESENT_ALLOWED;
670                 } else
671                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted")) {
672                         if (ifscreen->match_present != -1)
673                                 goto presenterror;
674                         ifscreen->match_present = INFO_PRESENT_RESTRICTED;
675                 } else {
676                         SCPY(ifscreen->match, el);
677                         /* check for % at the end */
678                         if (strchr(el, '%')) {
679                                 if (strchr(el, '%') != el+strlen(el)-1) {
680                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
681                                         return(-1);
682                                 }
683                         }
684                         break;
685                 }
686         }
687         if (ifscreen->match[0] == '\0') {
688                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
689                 return(-1);
690         }
691         /* get result */
692         while(*p) {
693                 el = p;
694                 p = get_seperated(p);
695                 if (!strcasecmp(el, "unknown")) {
696                         if (ifscreen->result_type != -1)
697                                 goto typeerror;
698                         ifscreen->result_type = INFO_NTYPE_UNKNOWN;
699                 } else
700                 if (!strcasecmp(el, "subscriber")) {
701                         if (ifscreen->result_type != -1)
702                                 goto typeerror;
703                         ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
704                 } else
705                 if (!strcasecmp(el, "national")) {
706                         if (ifscreen->result_type != -1)
707                                 goto typeerror;
708                         ifscreen->result_type = INFO_NTYPE_NATIONAL;
709                 } else
710                 if (!strcasecmp(el, "international")) {
711                         if (ifscreen->result_type != -1)
712                                 goto typeerror;
713                         ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
714                 } else
715                 if (!strcasecmp(el, "present") || !strcasecmp(el, "presented") || !strcasecmp(el, "allowed") || !strcasecmp(el, "allow")) {
716                         if (ifscreen->result_present != -1)
717                                 goto presenterror;
718                         ifscreen->result_present = INFO_PRESENT_ALLOWED;
719                 } else
720                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted") || !strcasecmp(el, "deny") || !strcasecmp(el, "denied")) {
721                         if (ifscreen->result_present != -1)
722                                 goto presenterror;
723                         ifscreen->result_present = INFO_PRESENT_RESTRICTED;
724                 } else {
725                         SCPY(ifscreen->result, el);
726                         /* check for % at the end */
727                         if (strchr(el, '%')) {
728                                 if (strchr(el, '%') != el+strlen(el)-1) {
729                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
730                                         return(-1);
731                                 }
732                         }
733                         break;
734                 }
735         }
736         if (ifscreen->result[0] == '\0') {
737                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
738                 return(-1);
739         }
740         return(0);
741 }
742 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
743 {
744         if (interface->ifmsn) {
745                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
746                 return(-1);
747         }
748
749         return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
750 }
751 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
752 {
753         return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
754 }
755 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
756 {
757         struct interface_port *ifport;
758
759         /* port in chain ? */
760         if (!interface->ifport) {
761                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
762                 return(-1);
763         }
764         /* goto end of chain */
765         ifport = interface->ifport;
766         while(ifport->next)
767                 ifport = ifport->next;
768         ifport->nodtmf = 1;
769         return(0);
770 }
771 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
772 {
773         char *p, *q;
774
775         /* seperate parameter from filter */
776         p = value;
777         while(*p > 32)
778                 p++;
779         if (*p) {
780                 *p++ = 0;
781                 while(*p > 0 && *p <= 32)
782                         p++;
783         }
784
785         if (!strcasecmp(value, "gain")) {
786                 q = p;
787                 while(*q > 32)
788                         q++;
789                 if (*q) {
790                         *q++ = 0;
791                         while(*q > 0 && *q <= 32)
792                                 q++;
793                 }
794                 if (*p == 0 || *q == 0) {
795                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects two gain values.\n", filename, line, parameter, value);
796                         return(-1);
797                 }
798                 if (atoi(p)<-8 || atoi(p)>8 || atoi(q)<-8 || atoi(q)>8) {
799                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' gain values not in range. (-8...8)\n", filename, line, parameter, value);
800                         return(-1);
801                 }
802                 interface->tx_gain = atoi(p);
803                 interface->rx_gain = atoi(q);
804         } else
805         if (!strcasecmp(value, "pipeline")) {
806                 if (*p == 0) {
807                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects pipeline string.\n", filename, line, parameter, value);
808                         return(-1);
809                 }
810                 SCPY(interface->pipeline, p);
811         } else
812         if (!strcasecmp(value, "blowfish")) {
813                 unsigned char key[56];
814                 int l;
815                 
816                 if (!!strncmp(p, "0x", 2)) {
817                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects blowfish key starting with '0x'.\n", filename, line, parameter, value);
818                         return(-1);
819                 }
820                 p += 2;
821                 l = 0; 
822                 while(*p) {
823                         if (l == 56) {
824                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key too long.\n", filename, line, parameter, value);
825                                 return(-1);
826                         }
827                         if (*p >= '0' && *p <= '9')
828                                 key[l] = (*p-'0')<<4;
829                         else if (*p >= 'a' && *p <= 'f')
830                                 key[l] = (*p-'a'+10)<<4;
831                         else if (*p >= 'A' && *p <= 'F')
832                                 key[l] = (*p-'A'+10)<<4;
833                         else {
834                                 digout:
835                                 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);
836                                 return(-1);
837                         }
838                         p++;
839                         if (*p == 0) {
840                                 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);
841                                 return(-1);
842                         }
843                         if (*p >= '0' && *p <= '9')
844                                 key[l] = (*p-'0')<<4;
845                         else if (*p >= 'a' && *p <= 'f')
846                                 key[l] = (*p-'a'+10)<<4;
847                         else if (*p >= 'A' && *p <= 'F')
848                                 key[l] = (*p-'A'+10)<<4;
849                         else
850                                 goto digout;
851                         p++;
852                         l++;
853                 }
854                 if (l < 4) {
855                         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);
856                         return(-1);
857                 }
858                 memcpy(interface->bf_key, key, l);
859                 interface->bf_len = l;
860         } else {
861                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has unknown filter '%s'.\n", filename, line, parameter, value);
862                 return(-1);
863         }
864         return(0);
865 }
866 static int inter_dialmax(struct interface *interface, char *filename, int line, char *parameter, char *value)
867 {
868         struct interface_port *ifport;
869
870         /* port in chain ? */
871         if (!interface->ifport) {
872                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
873                 return(-1);
874         }
875         /* goto end of chain */
876         ifport = interface->ifport;
877         while(ifport->next)
878                 ifport = ifport->next;
879         ifport->dialmax = atoi(value);
880         return(0);
881 }
882 static int inter_tones_dir(struct interface *interface, char *filename, int line, char *parameter, char *value)
883 {
884         struct interface_port *ifport;
885
886         /* port in chain ? */
887         if (!interface->ifport) {
888                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
889                 return(-1);
890         }
891         /* goto end of chain */
892         ifport = interface->ifport;
893         while(ifport->next)
894                 ifport = ifport->next;
895         SCPY(ifport->tones_dir, value);
896         return(0);
897 }
898 static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
899 {
900         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);
901         return(-1);
902 }
903 static int inter_gsm_bs(struct interface *interface, char *filename, int line, char *parameter, char *value)
904 {
905 #ifndef WITH_GSM_BS
906         SPRINT(interface_error, "Error in %s (line %d): GSM BS side not compiled in.\n", filename, line);
907         return(-1);
908 #else
909         struct interface *searchif;
910
911         searchif = interface_newlist;
912         while(searchif) {
913                 if (searchif->gsm_bs) {
914                         SPRINT(interface_error, "Error in %s (line %d): interface '%s' already uses gsm BS side.\n", filename, line, searchif->name);
915                         return(-1);
916                 }
917                 searchif = searchif->next;
918         }
919
920         /* goto end of chain again to set gsmflag */
921         interface->gsm_bs = 1;
922
923         return(0);
924 #endif
925 }
926 static int inter_gsm_ms(struct interface *interface, char *filename, int line, char *parameter, char *value)
927 {
928 #ifndef WITH_GSM_MS
929         SPRINT(interface_error, "Error in %s (line %d): GSM MS side not compiled in.\n", filename, line);
930         return(-1);
931 #else
932         struct interface *searchif;
933
934         interface->gsm_ms = 1;
935
936         /* copy values */
937         if (!value || !value[0]) {
938                 SPRINT(interface_error, "Error in %s (line %d): Missing MS name and socket name.\n", filename, line);
939                 return(-1);
940         }
941         SCPY(interface->gsm_ms_name, value);
942
943         /* check if name is used multiple times */
944         searchif = interface_newlist;
945         while(searchif) {
946                 if (searchif != interface && !strcmp(searchif->gsm_ms_name, interface->gsm_ms_name)) {
947                         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);
948                         return(-1);
949                 }
950                 searchif = searchif->next;
951         }
952
953         return(0);
954 #endif
955 }
956 static int inter_sip(struct interface *interface, char *filename, int line, char *parameter, char *value)
957 {
958 #ifndef WITH_SIP
959         SPRINT(interface_error, "Error in %s (line %d): SIP not compiled in.\n", filename, line);
960         return(-1);
961 #else
962         char *p;
963
964         interface->sip = 1;
965
966         /* copy values */
967         if (!value || !value[0]) {
968                 SPRINT(interface_error, "Error in %s (line %d): Missing SIP local IP.\n", filename, line);
969                 return(-1);
970         }
971         p = get_seperated(value);
972         if (!p[0]) {
973                 SPRINT(interface_error, "Error in %s (line %d): Missing SIP remote IP.\n", filename, line);
974                 return(-1);
975         }
976         SCPY(interface->sip_local_peer, value);
977         SCPY(interface->sip_remote_peer, p);
978
979         return(0);
980 #endif
981 }
982 static int inter_rtp_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value)
983 {
984         int supported = 0;
985
986 #ifdef WITH_GSM_BS
987         if (interface->gsm_bs)
988                 supported = 1;
989 #endif
990 #ifdef WITH_SIP
991         if (interface->sip)
992                 supported = 1;
993 #endif
994         if (!supported) {
995                 SPRINT(interface_error, "Error in %s (line %d): Interface does not support RTP\n", filename, line);
996                 return(-1);
997         }
998         interface->rtp_bridge = 1;
999
1000         return(0);
1001 }
1002 #if 0
1003 static int inter_rtp_payload(struct interface *interface, char *filename, int line, char *parameter, char *value)
1004 {
1005 #ifndef WITH_GSM_BS
1006         SPRINT(interface_error, "Error in %s (line %d): GSM BS side not compiled in.\n", filename, line);
1007         return(-1);
1008 #else
1009         if (!interface->gsm_bs) {
1010                 SPRINT(interface_error, "Error in %s (line %d): This parameter only works for GSM BS side interface\n", filename, line);
1011                 return(-1);
1012         }
1013         if (!interface->rtp_bridge) {
1014                 SPRINT(interface_error, "Error in %s (line %d): This parameter only works here, if RTP bridging is enabled\n", filename, line);
1015                 return(-1);
1016         }
1017         if (!value[0]) {
1018                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one payload type\n", filename, line, parameter);
1019                 return(-1);
1020         }
1021         if (interface->gsm_bs_payloads == sizeof(interface->gsm_bs_payload_types)) {
1022                 SPRINT(interface_error, "Error in %s (line %d): Too many payload types defined\n", filename, line);
1023                 return(-1);
1024         }
1025         interface->gsm_bs_payload_types[interface->gsm_bs_payloads++] = atoi(value);
1026
1027         return(0);
1028 #endif
1029 }
1030 #endif
1031 static int inter_nonotify(struct interface *interface, char *filename, int line, char *parameter, char *value)
1032 {
1033         struct interface_port *ifport;
1034
1035         /* port in chain ? */
1036         if (!interface->ifport) {
1037                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
1038                 return(-1);
1039         }
1040         /* goto end of chain */
1041         ifport = interface->ifport;
1042         while(ifport->next)
1043                 ifport = ifport->next;
1044         ifport->nonotify = 1;
1045         return(0);
1046 }
1047 #ifdef WITH_SS5
1048 static int inter_ss5(struct interface *interface, char *filename, int line, char *parameter, char *value)
1049 {
1050         struct interface_port *ifport;
1051         char *element;
1052
1053         /* port in chain ? */
1054         if (!interface->ifport) {
1055                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
1056                 return(-1);
1057         }
1058         /* goto end of chain */
1059         ifport = interface->ifport;
1060         while(ifport->next)
1061                 ifport = ifport->next;
1062         ifport->ss5 |= SS5_ENABLE;
1063         while((element = strsep(&value, " "))) {
1064                 if (element[0] == '\0')
1065                         continue;
1066                 if (!strcasecmp(element, "connect"))
1067                         ifport->ss5 |= SS5_FEATURE_CONNECT;
1068                 else
1069                 if (!strcasecmp(element, "nodisconnect"))
1070                         ifport->ss5 |= SS5_FEATURE_NODISCONNECT;
1071                 else
1072                 if (!strcasecmp(element, "releaseguardtimer"))
1073                         ifport->ss5 |= SS5_FEATURE_RELEASEGUARDTIMER;
1074                 else
1075                 if (!strcasecmp(element, "bell"))
1076                         ifport->ss5 |= SS5_FEATURE_BELL;
1077                 else
1078                 if (!strcasecmp(element, "pulsedialing"))
1079                         ifport->ss5 |= SS5_FEATURE_PULSEDIALING;
1080                 else
1081                 if (!strcasecmp(element, "delay"))
1082                         ifport->ss5 |= SS5_FEATURE_DELAY;
1083                 else
1084                 if (!strcasecmp(element, "starrelease"))
1085                         ifport->ss5 |= SS5_FEATURE_STAR_RELEASE;
1086                 else
1087                 if (!strcasecmp(element, "suppress"))
1088                         ifport->ss5 |= SS5_FEATURE_SUPPRESS;
1089                 else {
1090                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' does not allow value element '%s'.\n", filename, line, parameter, element);
1091                         return(-1);
1092                 }
1093         }
1094         return(0);
1095 }
1096 #endif
1097 static int inter_remote(struct interface *interface, char *filename, int line, char *parameter, char *value)
1098 {
1099         struct interface_port *ifport;
1100         struct interface *searchif;
1101
1102         if (!value[0]) {
1103                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects application name as value.\n", filename, line, parameter);
1104                 return(-1);
1105         }
1106         searchif = interface_newlist;
1107         while(searchif) {
1108                 ifport = searchif->ifport;
1109                 while(ifport) {
1110                         if (ifport->remote && !strcmp(ifport->remote_app, value)) {
1111                                 SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses remote application '%s'.\n", filename, line, ifport->portname, value);
1112                                 return(-1);
1113                         }
1114                         ifport = ifport->next;
1115                 }
1116                 searchif = searchif->next;
1117         }
1118
1119         /* set portname */
1120         if (inter_portname(interface, filename, line, (char *)"portname", options.loopback_lcr))
1121                 return(-1);
1122
1123         /* goto end of chain again to set application name */
1124         ifport = interface->ifport;
1125         while(ifport->next)
1126                 ifport = ifport->next;
1127         ifport->remote = 1;
1128         SCPY(ifport->remote_app, value);
1129
1130         return(0);
1131 }
1132 static int inter_shutdown(struct interface *interface, char *filename, int line, char *parameter, char *value)
1133 {
1134         interface->shutdown = 1;
1135
1136         return(0);
1137 }
1138 static int inter_bridge(struct interface *interface, char *filename, int line, char *parameter, char *value)
1139 {
1140         if (!value || !value[0]) {
1141                 SPRINT(interface_error, "Error in %s (line %d): Missing destination interface name.\n", filename, line);
1142                 return(-1);
1143         }
1144         interface->app = EAPP_TYPE_BRIDGE;
1145         SCPY(interface->bridge_if, value);
1146
1147         return(0);
1148 }
1149
1150
1151 /*
1152  * structure of parameters
1153  */
1154 struct interface_param interface_param[] = {
1155         { "extension", &inter_extension, "",
1156         "If keyword is given, calls to interface are handled as internal extensions."},
1157
1158         { "extern", &inter_extern, "",
1159         "If keyword is given, this interface will be used for external calls.\n"
1160         "Calls require an external interface, if the routing action 'extern' is used\nwithout specific interface given.\n"
1161         "Calls forwarded by extension's 'settings' also require an external interface."},
1162
1163         {"tones", &inter_tones, "yes | no",
1164         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
1165
1166         {"earlyb", &inter_earlyb, "yes | no",
1167         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
1168
1169         {"hunt", &inter_hunt, "linear | roundrobin",
1170         "Select the algorithm for selecting port with free channel."},
1171
1172         {"port", &inter_port, "<number>",
1173         ""},
1174         {"portnum", &inter_portnum, "<number>",
1175         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
1176         {"portname", &inter_portname, "<name>",
1177         "Same as 'portnum', but the name is given instead.\nUse 'isdninfo' to list all available ports and names."},
1178
1179         {"block", &inter_block, "",
1180         "If keyword is given, calls on this interface are blocked.\n"
1181         "This parameter must follow a 'port' parameter."},
1182
1183         {"ptp", &inter_ptp, "",
1184         "The given port above is opened as point-to-point.\n"
1185         "This is required on NT-mode ports that are multipoint by default.\n"
1186         "This parameter must follow a 'port' parameter."},
1187
1188 #if 0
1189         {"ptmp", &inter_ptmp, "",
1190         "The given port above is opened as point-to-multipoint.\n"
1191         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
1192         "This parameter must follow a 'port' parameter."},
1193 #endif
1194
1195         {"nt", &inter_nt, "",
1196         "The given port above is opened in NT-mode.\n"
1197         "This is required on interfaces that support both NT-mode and TE-mode.\n"
1198         "This parameter must follow a 'port' parameter."},
1199
1200         {"te-special", &inter_tespecial, "",
1201         "The given port uses a modified TE-mode.\n"
1202         "All information elements that are allowed Network->User will then be\n"
1203         "transmitted User->Network also. This is usefull to pass all informations\n"
1204         "between two interconnected LCRs, like 'redirected number' or 'display'.\n"
1205         "Note that this is not compliant with ISDN protocol.\n"
1206         "This parameter must follow a 'port' parameter."},
1207
1208         {"layer1hold", &inter_l1hold, "yes | no",
1209         "The given port will not release layer 1 after layer 2 is down.\n"
1210         "It is required to keep layer 1 of telephones up, to solve activation problems.\n"
1211         "This parameter must follow a 'port' parameter."},
1212
1213         {"layer2hold", &inter_l2hold, "yes | no",
1214         "The given port will continuously try to establish layer 2 link and hold it.\n"
1215         "It is required for PTP links in most cases, therefore it is default.\n"
1216         "This parameter must follow a 'port' parameter."},
1217
1218         {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
1219         "Channel selection list for all outgoing calls to the interface.\n"
1220         "A free channels is searched in order of appearance.\n"
1221         "This parameter must follow a 'port' parameter.\n"
1222         " force - Forces the selected port with no acceptable alternative (see Q.931).\n"
1223         "  -> this will be automatically set for multipoint (ptmp) NT-mode ports\n"
1224         " <number>[,...] - List of channels to search.\n"
1225         " free - Select any free channel\n"
1226         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
1227         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
1228
1229         {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
1230         "Channel selection list for all incoming calls from the interface.\n"
1231         "A free channels is accepted if in the list.\n"
1232         "If any channel was requested, the first free channel found is selected.\n"
1233         "This parameter must follow a 'port' parameter.\n"
1234         " <number>[,...] - List of channels to accept.\n"
1235         " free - Accept any free channel"},
1236
1237         {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
1238         "Timeout values for call states. They are both for incoming and outgoing states.\n"
1239         "The default is 120 seconds for all states. Use 0 to disable.\n"
1240         "This parameter must follow a 'port' parameter.\n"},
1241
1242         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
1243         "Incoming caller ID is checked against given MSN numbers.\n"
1244         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
1245
1246         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1247         "Adds an entry for incoming calls to the caller ID screen list.\n"
1248         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
1249         "If '%' is given after old caller ID, it matches even if caller ID has\n"
1250         "additional digits.\n"
1251         "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
1252         "are added.\n"
1253         "Options can be:\n"
1254         " unknown | subsciber | national | international - Change caller ID type.\n"
1255         " present | restrict - Change presentation of caller ID."},
1256                 
1257         {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
1258         "Adds an entry for outgoing calls to the caller ID screen list.\n"
1259         "See 'screen-in' for help."},
1260
1261         {"nodtmf", &inter_nodtmf, "",
1262         "Disables DTMF detection for this interface.\n"
1263         "This parameter must follow a 'port' parameter."},
1264
1265         {"filter", &inter_filter, "<filter> <parameters>",
1266         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
1267         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
1268         "pipeline <string> - Sets echo cancelation pipeline.\n"
1269         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
1270
1271         {"dialmax", &inter_dialmax, "<digits>",
1272         "Limits the number of digits in setup/information message."},
1273
1274         {"tones_dir", &inter_tones_dir, "<path>",
1275         "Overrides the given tone_dir in options.conf.\n"
1276         "To used kernel tones in mISDN_dsp.ko, say 'american', 'german', or 'oldgerman'."},
1277
1278         {"gsm", &inter_gsm, "",
1279         ""},
1280         {"gsm-bs", &inter_gsm_bs, "",
1281         "Sets up GSM base station interface for using OpenBSC."},
1282         {"gsm-ms", &inter_gsm_ms, "<socket>",
1283         "Sets up GSM mobile station interface for using Osmocom-BB.\n"
1284         "The name of the MS folows the interface name.\n"
1285         "The socket is /tmp/osmocom_l2 by default and need to be changed when multiple\n"
1286         "MS interfaces are used."},
1287         {"sip", &inter_sip, "<local IP> <remote IP>",
1288         "Sets up SIP interface that represents one SIP endpoint.\n"
1289         "Give SIP configuration file."},
1290         {"rtp-bridge", &inter_rtp_bridge, "",
1291         "Enables RTP bridging directly from this interface.\n"
1292         "This only works, if both ends support RTP. (like gsm-bs and sip)"},
1293 #if 0
1294         not needed, since ms defines what is supports and remote (sip) tells what is selected
1295         {"rtp-payload", &inter_rtp_payload, "<codec>",
1296         "Define RTP payload to use. Only valid in conjuntion with gsm-bs!\n"
1297         "If multiple payloads are defined, the first has highest priority.\n"
1298         "If none are defined, GSM fullrate V1 (type 3) is assumed.\n"},
1299 #endif
1300         {"nonotify", &inter_nonotify, "",
1301         "Prevents sending notify messages to this interface. A call placed on hold will\n"
1302         "Not affect the remote end (phone or telcom switch).\n"
1303         "This parameter must follow a 'port' parameter."},
1304         {"bridge", &inter_bridge, "<destination interface>",
1305         "Define bridge application for this interface. All calls received on this\n"
1306         "interface will be directly bridged to the given destination interface.\n"
1307         "There will be no PBX application, nor routing."},
1308
1309 #ifdef WITH_SS5
1310         {"ccitt5", &inter_ss5, "[<feature> [feature ...]]",
1311         "Interface uses CCITT No. 5 inband signalling rather than D-channel.\n"
1312         "This feature causes CPU load to rise and has no practical intend.\n"
1313         "If you don't know what it is, you don't need it.\n"
1314         "Features apply to protocol behaviour and blueboxing specials, they are:\n"
1315         " connect - Connect incomming call to throughconnect audio, if required.\n"
1316         " nodisconnect - Don't disconnect if incomming exchange disconnects.\n"
1317         " releaseguardtimer - Tries to prevent Blueboxing by a longer release-guard.\n"
1318         " bell - Allow releasing and pulse-dialing via 2600 Hz like old Bell systems.\n"
1319         " pulsedialing - Use pulse dialing on outgoing exchange. (takes long!)\n"
1320         " delay - Use on incomming exchange, to make you feel a delay when blueboxing.\n"
1321         " starrelease - Pulse dialing a star (11 pulses per digit) clears current call.\n"
1322         " suppress - Suppress received tones, as they will be recognized."},
1323 #endif
1324
1325         {"remote", &inter_remote, "<application>",
1326         "Sets up an interface that communicates with the remote application.\n"
1327         "Use \"asterisk\" to use chan_lcr as remote application."},
1328
1329         {"shutdown", &inter_shutdown, "",
1330         "Interface will not be loaded when processing interface.conf"},
1331
1332         {NULL, NULL, NULL, NULL}
1333 };
1334
1335 /* read interfaces
1336  *
1337  * read settings from interface.conf
1338  */
1339 char interface_error[256];
1340 struct interface *read_interfaces(void)
1341 {
1342         FILE                    *fp = NULL;
1343         char                    filename[128];
1344         char                    *p;
1345         unsigned int            line, i;
1346         char                    buffer[256];
1347         struct interface        *interface = NULL, /* in case no interface */
1348                                 **interfacep = &interface_newlist;
1349         char                    parameter[128];
1350         char                    value[256];
1351         int                     expecting = 1; /* expecting new interface */
1352         struct interface_param  *ifparam;
1353
1354         if (interface_newlist != NULL)
1355                 FATAL("list is not empty.\n");
1356         interface_error[0] = '\0';
1357         SPRINT(filename, "%s/interface.conf", CONFIG_DATA);
1358
1359         if (!(fp = fopen(filename,"r"))) {
1360                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
1361                 goto error;
1362         }
1363
1364         line=0;
1365         while((GETLINE(buffer, fp))) {
1366                 p=buffer;
1367                 line++;
1368
1369                 while(*p <= 32) { /* skip spaces */
1370                         if (*p == 0)
1371                                 break;
1372                         p++;
1373                 }
1374                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1375                         continue;
1376
1377                 parameter[0]=0;
1378                 value[0]=0;
1379                 i=0; /* read parameter */
1380                 while(*p > 32) {
1381                         if (i+1 >= sizeof(parameter)) {
1382                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
1383                                 goto error;
1384                         }
1385                         parameter[i+1] = '\0';
1386                         parameter[i++] = *p++;
1387                 }
1388
1389                 while(*p <= 32) { /* skip spaces */
1390                         if (*p == 0)
1391                                 break;
1392                         p++;
1393                 }
1394
1395                 if (*p!=0 && *p!='#') { /* missing name */
1396                         i=0; /* read until end */
1397                         while(*p!=0 && *p!='#') {
1398                                 if (i+1 >= sizeof(value)) {
1399                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
1400                                         goto error;
1401                                 }
1402                                 value[i+1] = '\0';
1403                                 value[i++] = *p++;
1404                         }
1405
1406                         /* remove trailing spaces from value */
1407                         while(i) {
1408                                 if (value[i-1]==0 || value[i-1]>32)
1409                                         break;
1410                                 value[i-1] = '\0';
1411                                 i--;
1412                         }
1413                 }
1414
1415                 /* check for interface name as first statement */
1416                 if (expecting && parameter[0]!='[') {
1417                         SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1418                         goto error;
1419                 }
1420                 expecting = 0;
1421
1422                 /* check for new interface */
1423                 if (parameter[0] == '[') {
1424                         if (parameter[strlen(parameter)-1] != ']') {
1425                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1426                                 goto error;
1427                         }
1428                         parameter[strlen(parameter)-1] = '\0';
1429
1430                         /* check if interface name already exists */
1431                         interface = interface_newlist;
1432                         while(interface) {
1433                                 if (!strcasecmp(interface->name, parameter+1)) {
1434                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
1435                                         goto error;
1436                                 }
1437                                 interface = interface->next;
1438                         }
1439
1440                         /* append interface to new list */
1441                         interface = (struct interface *)MALLOC(sizeof(struct interface));
1442                         memuse++;
1443
1444                         /* name interface */
1445                         SCPY(interface->name, parameter+1);
1446
1447                         /* attach */
1448                         *interfacep = interface;
1449                         interfacep = &interface->next;
1450
1451                         continue;
1452                 }
1453
1454                 ifparam = interface_param;
1455                 while(ifparam->name) {
1456                         if (!strcasecmp(parameter, ifparam->name)) {
1457                                 if (ifparam->func(interface, filename, line, parameter, value))
1458                                         goto error;
1459                                 break;
1460                         }
1461                         ifparam++;
1462                 }
1463                 if (ifparam->name)
1464                         continue;
1465
1466                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1467                 goto error;
1468         }
1469
1470         if (fp) fclose(fp);
1471         return(interface_newlist);
1472 error:
1473         PERROR_RUNTIME("%s", interface_error);
1474         if (fp) fclose(fp);
1475         free_interfaces(interface_newlist);
1476         interface_newlist = NULL;
1477         return(NULL);
1478 }
1479
1480
1481 /*
1482  * freeing chain of interfaces
1483  */
1484 void free_interfaces(struct interface *interface)
1485 {
1486         void *temp;
1487         struct interface_port *ifport;
1488         struct select_channel *selchannel;
1489         struct interface_msn *ifmsn;
1490         struct interface_screen *ifscreen;
1491
1492         while(interface) {
1493                 ifport = interface->ifport;
1494                 while(ifport) {
1495                         selchannel = ifport->in_channel;
1496                         while(selchannel) {
1497                                 temp = selchannel;
1498                                 selchannel = selchannel->next;
1499                                 FREE(temp, sizeof(struct select_channel));
1500                                 memuse--;
1501                         }
1502                         selchannel = ifport->out_channel;
1503                         while(selchannel) {
1504                                 temp = selchannel;
1505                                 selchannel = selchannel->next;
1506                                 FREE(temp, sizeof(struct select_channel));
1507                                 memuse--;
1508                         }
1509                         temp = ifport;
1510                         ifport = ifport->next;
1511                         FREE(temp, sizeof(struct interface_port));
1512                         memuse--;
1513                 }
1514                 ifmsn = interface->ifmsn;
1515                 while(ifmsn) {
1516                         temp = ifmsn;
1517                         ifmsn = ifmsn->next;
1518                         FREE(temp, sizeof(struct interface_msn));
1519                         memuse--;
1520                 }
1521                 ifscreen = interface->ifscreen_in;
1522                 while(ifscreen) {
1523                         temp = ifscreen;
1524                         ifscreen = ifscreen->next;
1525                         FREE(temp, sizeof(struct interface_screen));
1526                         memuse--;
1527                 }
1528                 ifscreen = interface->ifscreen_out;
1529                 while(ifscreen) {
1530                         temp = ifscreen;
1531                         ifscreen = ifscreen->next;
1532                         FREE(temp, sizeof(struct interface_screen));
1533                         memuse--;
1534                 }
1535                 temp = interface;
1536                 interface = interface->next;
1537                 FREE(temp, sizeof(struct interface));
1538                 memuse--;
1539         }
1540 }
1541
1542 #ifdef WITH_MISDN
1543 /*
1544  * defaults of ports if not specified by config
1545  */
1546 static void set_mISDN_defaults(struct interface_port *ifport)
1547 {
1548         /* default channel selection list */
1549         if (!ifport->out_channel)
1550                 default_out_channel(ifport);
1551         if (!ifport->in_channel)
1552                 default_in_channel(ifport);
1553         /* must force the channel on PTMP/NT ports */
1554         if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode)
1555                 ifport->channel_force = 1;
1556         /* default is_tones */
1557         if (ifport->interface->is_tones)
1558                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1559         else
1560                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode || ifport->mISDNport->ss5)?1:0;
1561         /* default is_earlyb */
1562         if (ifport->interface->is_earlyb)
1563                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1564         else
1565                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode && !ifport->mISDNport->ss5)?0:1;
1566         /* set locally flag */
1567         if (ifport->interface->extension)
1568                 ifport->mISDNport->locally = 1;
1569         else
1570                 ifport->mISDNport->locally = 0;
1571 }
1572 #endif
1573
1574
1575 /*
1576  * all links between mISDNport and interface are made
1577  * unused mISDNports are closed, new mISDNports are opened
1578  * also set default select_channel lists
1579  */
1580 void relink_interfaces(void)
1581 {
1582 #ifdef WITH_MISDN
1583         struct mISDNport *mISDNport;
1584         struct interface_port *ifport;
1585 #endif
1586         struct interface *interface, *temp;
1587         int found;
1588
1589         interface = interface_first;
1590         while(interface) {
1591                 found = 0;
1592                 temp = interface_newlist;
1593                 while(temp) {
1594                         if (!strcmp(temp->name, interface->name))
1595                                 found = 1;
1596                         temp = temp->next;
1597                 }
1598                 if (!found) {
1599 #ifdef WITH_GSM_MS
1600                         if (interface->gsm_ms)
1601                                 gsm_ms_delete(interface->gsm_ms_name);
1602 #endif
1603 #ifdef WITH_GSM_BS
1604                         if (interface->gsm_bs)
1605                                 gsm_bs_exit(0);
1606 #endif
1607 #ifdef WITH_SIP
1608                         if (interface->sip)
1609                                 sip_exit_inst(interface);
1610 #endif
1611                 }
1612                 interface = interface->next;
1613         }
1614
1615         interface = interface_newlist;
1616         while(interface) {
1617                 found = 0;
1618                 temp = interface_first;
1619                 while(temp) {
1620                         if (!strcmp(temp->name, interface->name))
1621                                 found = 1;
1622                         temp = temp->next;
1623                 }
1624                 if (!found) {
1625 #ifdef WITH_GSM_MS
1626                         if (interface->gsm_ms)
1627                                 gsm_ms_new(interface);
1628 #endif
1629 #ifdef WITH_GSM_BS
1630                         if (interface->gsm_bs)
1631                                 gsm_bs_init(interface);
1632 #endif
1633 #ifdef WITH_SIP
1634                         if (interface->sip)
1635                                 sip_init_inst(interface);
1636 #endif
1637                 }
1638                 interface = interface->next;
1639         }
1640
1641 #ifdef WITH_MISDN
1642         /* unlink all mISDNports */
1643         mISDNport = mISDNport_first;
1644         while(mISDNport) {
1645                 mISDNport->ifport = NULL;
1646                 mISDNport = mISDNport->next;
1647         }
1648
1649         /* relink existing mISDNports */
1650         interface = interface_newlist;
1651         while(interface) {
1652                 ifport = interface->ifport;
1653                 while(ifport) {
1654                         mISDNport = mISDNport_first;
1655                         while(mISDNport) {
1656                                 if (!strcmp(mISDNport->name, ifport->portname))
1657                                         ifport->portnum = mISDNport->portnum; /* same name, so we use same number */
1658                                 if (mISDNport->portnum == ifport->portnum) {
1659                                         PDEBUG(DEBUG_ISDN, "Port %d:%s relinking!\n", ifport->portnum, ifport->portname);
1660                                         ifport->mISDNport = mISDNport;
1661                                         mISDNport->ifport = ifport;
1662                                         set_mISDN_defaults(ifport);
1663                                 }
1664                                 mISDNport = mISDNport->next;
1665                         }
1666                         ifport = ifport->next;
1667                 }
1668                 interface = interface->next;
1669         }
1670
1671         /* close unused mISDNports */
1672         closeagain:
1673         mISDNport = mISDNport_first;
1674         while(mISDNport) {
1675                 if (mISDNport->ifport == NULL) {
1676                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1677                         /* destroy port */
1678                         mISDNport_close(mISDNport);
1679                         goto closeagain;
1680                 }
1681                 mISDNport = mISDNport->next;
1682         }
1683
1684         /* open and link new mISDNports */
1685         interface = interface_newlist;
1686         while(interface) {
1687                 ifport = interface->ifport;
1688                 while(ifport) {
1689                         if (!ifport->mISDNport) {
1690                                 if (!interface->shutdown) {
1691                                         load_mISDN_port(ifport);
1692                                 } else {
1693                                         ifport->block = 2;
1694                                 }
1695                         }
1696                         ifport = ifport->next;
1697                 }
1698                 interface = interface->next;
1699         }
1700 #endif
1701 }
1702
1703
1704 #ifdef WITH_MISDN
1705 /*
1706  * load port
1707  */
1708 void load_mISDN_port(struct interface_port *ifport)
1709 {
1710         struct mISDNport *mISDNport;
1711
1712         /* open new port */
1713         mISDNport = mISDNport_open(ifport);
1714         if (mISDNport) {
1715                 /* link port */
1716                 ifport->mISDNport = mISDNport;
1717                 mISDNport->ifport = ifport;
1718                 /* set number and name */
1719                 ifport->portnum = mISDNport->portnum;
1720                 SCPY(ifport->portname, mISDNport->name);
1721                 /* set defaults */
1722                 set_mISDN_defaults(ifport);
1723                 /* load static port instances */
1724                 mISDNport_static(mISDNport);
1725         } else {
1726                 ifport->block = 2; /* not available */
1727         }
1728 }
1729 #endif
1730
1731 /*
1732  * give summary of interface syntax
1733  */
1734 void doc_interface(void)
1735 {
1736         struct interface_param *ifparam;
1737         
1738         printf("Syntax overview\n");
1739         printf("---------------\n\n");
1740
1741         printf("[<name>]\n");
1742         ifparam = interface_param;
1743         while(ifparam->name) {
1744                 if (ifparam->name[0])
1745                         printf("%s %s\n", ifparam->name, ifparam->usage);
1746                 ifparam++;
1747         }
1748
1749         ifparam = interface_param;
1750         while(ifparam->name) {
1751                 if (ifparam->name[0]) {
1752                         printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1753                         printf("%s\n", ifparam->help);
1754                 }
1755                 ifparam++;
1756         }
1757 }
1758
1759
1760 /* screen caller id
1761  * out==0: incoming caller id, out==1: outgoing caller id
1762  */
1763 void do_screen(int out, char *id, int idsize, int *type, int *present, const char *interface_name)
1764 {
1765         char                    *msn1;
1766         struct interface_msn    *ifmsn;
1767         struct interface_screen *ifscreen;
1768         char suffix[64];
1769         struct interface *interface = interface_first;
1770
1771         interface = getinterfacebyname(interface_name);
1772         if (!interface)
1773                 return;
1774
1775         /* screen incoming caller id */
1776         if (!out) {
1777                 /* check for MSN numbers, use first MSN if no match */
1778                 msn1 = NULL;
1779                 ifmsn = interface->ifmsn;
1780                 while(ifmsn) {
1781                         if (!msn1)
1782                                 msn1 = ifmsn->msn;
1783                         if (!strcmp(ifmsn->msn, id)) {
1784                                 break;
1785                         }
1786                         ifmsn = ifmsn->next;
1787                 }
1788                 if (ifmsn) {
1789                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (found in MSN list)");
1790                         add_trace("msn", NULL, "%s", id);
1791                         end_trace();
1792                 }
1793                 if (!ifmsn && msn1) { // not in list, first msn given
1794                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (not found in MSN list)");
1795                         add_trace("msn", "given", "%s", id);
1796                         add_trace("msn", "used", "%s", msn1);
1797                         end_trace();
1798                         UNCPY(id, msn1, idsize);
1799                         id[idsize-1] = '\0';
1800                 }
1801         }
1802
1803         /* check screen list */
1804         if (out)
1805                 ifscreen = interface->ifscreen_out;
1806         else
1807                 ifscreen = interface->ifscreen_in;
1808         while (ifscreen) {
1809                 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1810                 if (ifscreen->match_present==-1 || ifscreen->match_present==*present) {
1811                         if (strchr(ifscreen->match,'%')) {
1812                                 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1813                                         break;
1814                         } else {
1815                                 if (!strcmp(ifscreen->match, id))
1816                                         break;
1817                         }
1818                 }
1819                 ifscreen = ifscreen->next;
1820         }
1821         if (ifscreen) { // match
1822                 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)");
1823                 switch(*type) {
1824                         case INFO_NTYPE_UNKNOWN:
1825                         add_trace("given", "type", "unknown");
1826                         break;
1827                         case INFO_NTYPE_SUBSCRIBER:
1828                         add_trace("given", "type", "subscriber");
1829                         break;
1830                         case INFO_NTYPE_NATIONAL:
1831                         add_trace("given", "type", "national");
1832                         break;
1833                         case INFO_NTYPE_INTERNATIONAL:
1834                         add_trace("given", "type", "international");
1835                         break;
1836                 }
1837                 switch(*present) {
1838                         case INFO_PRESENT_ALLOWED:
1839                         add_trace("given", "present", "allowed");
1840                         break;
1841                         case INFO_PRESENT_RESTRICTED:
1842                         add_trace("given", "present", "restricted");
1843                         break;
1844                         case INFO_PRESENT_NOTAVAIL:
1845                         add_trace("given", "present", "not available");
1846                         break;
1847                 }
1848                 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1849                 if (ifscreen->result_type != -1) {
1850                         *type = ifscreen->result_type;
1851                         switch(*type) {
1852                                 case INFO_NTYPE_UNKNOWN:
1853                                 add_trace("used", "type", "unknown");
1854                                 break;
1855                                 case INFO_NTYPE_SUBSCRIBER:
1856                                 add_trace("used", "type", "subscriber");
1857                                 break;
1858                                 case INFO_NTYPE_NATIONAL:
1859                                 add_trace("used", "type", "national");
1860                                 break;
1861                                 case INFO_NTYPE_INTERNATIONAL:
1862                                 add_trace("used", "type", "international");
1863                                 break;
1864                         }
1865                 }
1866                 if (ifscreen->result_present != -1) {
1867                         *present = ifscreen->result_present;
1868                         switch(*present) {
1869                                 case INFO_PRESENT_ALLOWED:
1870                                 add_trace("used", "present", "allowed");
1871                                 break;
1872                                 case INFO_PRESENT_RESTRICTED:
1873                                 add_trace("used", "present", "restricted");
1874                                 break;
1875                                 case INFO_PRESENT_NOTAVAIL:
1876                                 add_trace("used", "present", "not available");
1877                                 break;
1878                         }
1879                 }
1880                 if (strchr(ifscreen->match,'%')) {
1881                         SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1882                         UNCPY(id, ifscreen->result, idsize);
1883                         id[idsize-1] = '\0';
1884                         if (strchr(id,'%')) {
1885                                 *strchr(id,'%') = '\0';
1886                                 UNCAT(id, suffix, idsize);
1887                                 id[idsize-1] = '\0';
1888                         }
1889                 } else {
1890                         UNCPY(id, ifscreen->result, idsize);
1891                         id[idsize-1] = '\0';
1892                 }
1893                 add_trace("used", "id", "%s", id[0]?id:"<empty>");
1894                 end_trace();
1895         }
1896 }
1897
1898 struct interface *getinterfacebyname(const char *name)
1899 {
1900         struct interface *interface = interface_first;
1901
1902         while (interface) {
1903                 if (!strcmp(interface->name, name))
1904                         return interface;
1905                 interface = interface->next;
1906         }
1907
1908         return NULL;
1909 }
1910