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