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