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