Fixed trace bugs.
[lcr.git] / interface.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** LCR                                                                       **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** reading interface.conf file and filling structure                         **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 struct interface *interface_first = NULL; /* first interface is current list */
15 struct interface *interface_newlist = NULL; /* first interface in new list */
16
17
18 /* set default out_channel */
19 void default_out_channel(struct interface_port *ifport)
20 {
21         struct select_channel *selchannel, **selchannelp;
22
23         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
24         memuse++;
25         
26         if (ifport->mISDNport->ntmode)
27                 selchannel->channel = CHANNEL_FREE;
28         else
29                 selchannel->channel = CHANNEL_ANY;
30         
31         ifport->out_channel = selchannel;
32
33         /* additional channel selection for multipoint NT ports */
34         if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode)
35         {
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
58
59 /* parse string for a positive number */
60 static int get_number(char *value)
61 {
62         int val = 0;
63         char text[10];
64
65         val = atoi(value);
66         
67         SPRINT(text, "%d", val);
68
69         if (!strcmp(value, text))
70                 return(val);
71
72         return(-1);
73 }
74
75
76 /* remove element from buffer
77  * and return pointer to next element in buffer */
78 static char *get_seperated(char *buffer)
79 {
80         while(*buffer)
81         {
82                 if (*buffer==',' || *buffer<=32) /* seperate */
83                 {
84                         *buffer++ = '\0';
85                         while((*buffer>'\0' && *buffer<=32) || *buffer==',')
86                                 buffer++;
87                         return(buffer);
88                 }
89                 buffer++;
90         }
91         return(buffer);
92 }
93
94 /*
95  * parameter processing
96  */
97 static int inter_block(struct interface *interface, char *filename, int line, char *parameter, char *value)
98 {
99         struct interface_port *ifport;
100
101         /* port in chain ? */
102         if (!interface->ifport)
103         {
104                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
105                 return(-1);
106         }
107         /* goto end of chain */
108         ifport = interface->ifport;
109         while(ifport->next)
110                 ifport = ifport->next;
111         /* add value */
112         if (value[0])
113         {
114                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
115                 return(-1);
116         }
117         ifport->block = 1;
118         return(0);
119 }
120 static int inter_extension(struct interface *interface, char *filename, int line, char *parameter, char *value)
121 {
122         if (value[0])
123         {
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_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
131 {
132         struct interface_port *ifport;
133
134         /* port in chain ? */
135         if (!interface->ifport)
136         {
137                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
138                 return(-1);
139         }
140         if (interface->ifport->ptmp)
141         {
142                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptmp was given.\n", filename, line, parameter);
143                 return(-1);
144         }
145         /* goto end of chain */
146         ifport = interface->ifport;
147         while(ifport->next)
148                 ifport = ifport->next;
149         /* add value */
150         if (value[0])
151         {
152                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
153                 return(-1);
154         }
155         ifport->ptp = 1;
156         return(0);
157 }
158 #if 0
159 static int inter_ptmp(struct interface *interface, char *filename, int line, char *parameter, char *value)
160 {
161         struct interface_port *ifport;
162
163         /* port in chain ? */
164         if (!interface->ifport)
165         {
166                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
167                 return(-1);
168         }
169         if (interface->ifport->ptp)
170         {
171                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptp was given.\n", filename, line, parameter);
172                 return(-1);
173         }
174         /* goto end of chain */
175         ifport = interface->ifport;
176         while(ifport->next)
177                 ifport = ifport->next;
178         /* add value */
179         if (value[0])
180         {
181                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
182                 return(-1);
183         }
184         ifport->ptmp = 1;
185         return(0);
186 }
187 #endif
188 static int inter_nt(struct interface *interface, char *filename, int line, char *parameter, char *value)
189 {
190         struct interface_port *ifport;
191
192         /* port in chain ? */
193         if (!interface->ifport)
194         {
195                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
196                 return(-1);
197         }
198         /* goto end of chain */
199         ifport = interface->ifport;
200         while(ifport->next)
201                 ifport = ifport->next;
202         /* add value */
203         if (value[0])
204         {
205                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
206                 return(-1);
207         }
208         ifport->nt = 1;
209         return(0);
210 }
211 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
212 {
213         if (!strcasecmp(value, "yes"))
214         {
215                 interface->is_tones = IS_YES;
216         } else
217         if (!strcasecmp(value, "no"))
218         {
219                 interface->is_tones = IS_NO;
220         } else
221         {
222                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
223                 return(-1);
224         }
225         return(0);
226 }
227 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
228 {
229         if (!strcasecmp(value, "yes"))
230         {
231                 interface->is_earlyb = IS_YES;
232         } else
233         if (!strcasecmp(value, "no"))
234         {
235                 interface->is_earlyb = IS_NO;
236         } else
237         {
238                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
239                 return(-1);
240         }
241         return(0);
242 }
243 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
244 {
245         if (!strcasecmp(value, "linear"))
246         {
247                 interface->hunt = HUNT_LINEAR;
248         } else
249         if (!strcasecmp(value, "roundrobin"))
250         {
251                 interface->hunt = HUNT_ROUNDROBIN;
252         } else
253         {
254                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
255                 return(-1);
256         }
257         return(0);
258 }
259 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
260 {
261         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);
262         return(-1);
263 }
264 static int inter_portnum(struct interface *interface, char *filename, int line, char *parameter, char *value)
265 {
266         struct interface_port *ifport, **ifportp;
267         struct interface *searchif;
268         int val;
269
270         val = get_number(value);
271         if (val == -1)
272         {
273                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
274                 return(-1);
275         }
276         /* check for port already assigned */
277         searchif = interface_newlist;
278         while(searchif)
279         {
280                 ifport = searchif->ifport;
281                 while(ifport)
282                 {
283                         if (ifport->portnum == val)
284                         {
285                                 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
286                                 return(-1);
287                         }
288                         ifport = ifport->next;
289                 }
290                 searchif = searchif->next;
291         }
292         /* alloc port substructure */
293         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
294         memuse++;
295         ifport->interface = interface;
296         /* set value */
297         ifport->portnum = val;
298         /* tail port */
299         ifportp = &interface->ifport;
300         while(*ifportp)
301                 ifportp = &((*ifportp)->next);
302         *ifportp = ifport;
303         return(0);
304 }
305 static int inter_portname(struct interface *interface, char *filename, int line, char *parameter, char *value)
306 {
307         struct interface_port *ifport, **ifportp;
308         struct interface *searchif;
309
310         /* check for port already assigned */
311         searchif = interface_newlist;
312         while(searchif)
313         {
314                 ifport = searchif->ifport;
315                 while(ifport)
316                 {
317                         if (!strcasecmp(ifport->portname, value))
318                         {
319                                 SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
320                                 return(-1);
321                         }
322                         ifport = ifport->next;
323                 }
324                 searchif = searchif->next;
325         }
326         /* alloc port substructure */
327         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
328         memuse++;
329         ifport->interface = interface;
330         /* set value */
331         ifport->portnum = -1; // disable until resolved
332         SCPY(ifport->portname, value);
333         /* tail port */
334         ifportp = &interface->ifport;
335         while(*ifportp)
336                 ifportp = &((*ifportp)->next);
337         *ifportp = ifport;
338         return(0);
339 }
340 static int inter_l2hold(struct interface *interface, char *filename, int line, char *parameter, char *value)
341 {
342         struct interface_port *ifport;
343
344         /* port in chain ? */
345         if (!interface->ifport)
346         {
347                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
348                 return(-1);
349         }
350         /* goto end of chain */
351         ifport = interface->ifport;
352         while(ifport->next)
353                 ifport = ifport->next;
354         if (!strcmp(value, "yes"))
355         {
356                 ifport->l2hold = 1;
357         } else
358         if (!strcmp(value, "no"))
359         {
360                 ifport->l2hold = -1;
361         } else
362         {
363                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expecting parameter 'yes' or 'no'.\n", filename, line, parameter);
364                 return(-1);
365         }
366         return(0);
367 }
368 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
369 {
370         struct interface_port *ifport;
371         struct select_channel *selchannel, **selchannelp;
372         int val;
373         char *p, *el;
374
375         /* port in chain ? */
376         if (!interface->ifport)
377         {
378                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
379                 return(-1);
380         }
381         /* goto end of chain */
382         ifport = interface->ifport;
383         while(ifport->next)
384                 ifport = ifport->next;
385         p = value;
386         while(*p)
387         {
388                 el = p;
389                 p = get_seperated(p);
390                 if (!strcasecmp(el, "force"))
391                 {
392                         ifport->channel_force = 1;
393                         if (ifport->out_channel)
394                         {
395                                 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
396                                 return(-1);
397                         }
398                 } else
399                 if (!strcasecmp(el, "any"))
400                 {
401                         val = CHANNEL_ANY;
402                         goto selchannel;
403                 } else
404                 if (!strcasecmp(el, "free"))
405                 {
406                         val = CHANNEL_FREE;
407                         goto selchannel;
408                 } else
409                 if (!strcasecmp(el, "no"))
410                 {
411                         val = CHANNEL_NO;
412                         goto selchannel;
413                 } else
414                 {
415                         val = get_number(el);
416                         if (val == -1)
417                         {
418                                 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);
419                                 return(-1);
420                         }
421
422                         if (val<1 || val==16 || val>126)
423                         {
424                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
425                                 return(-1);
426                         }
427                         selchannel:
428                         /* add to select-channel list */
429                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
430                         memuse++;
431                         /* set value */
432                         selchannel->channel = val;
433                         /* tail port */
434                         selchannelp = &ifport->out_channel;
435                         while(*selchannelp)
436                                 selchannelp = &((*selchannelp)->next);
437                         *selchannelp = selchannel;
438                 }
439         }
440         return(0);
441 }
442 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
443 {
444         struct interface_port *ifport;
445         struct select_channel *selchannel, **selchannelp;
446         int val;
447         char *p, *el;
448
449         /* port in chain ? */
450         if (!interface->ifport)
451         {
452                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
453                 return(-1);
454         }
455         /* goto end of chain */
456         ifport = interface->ifport;
457         while(ifport->next)
458                 ifport = ifport->next;
459         p = value;
460         while(*p)
461         {
462                 el = p;
463                 p = get_seperated(p);
464                 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE)
465                 {
466                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
467                                 return(-1);
468                 }
469                 if (!strcasecmp(el, "free"))
470                 {
471                         val = CHANNEL_FREE;
472                         goto selchannel;
473                 } else
474                 {
475                         val = get_number(el);
476                         if (val == -1)
477                         {
478                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
479                                 return(-1);
480                         }
481
482                         if (val<1 || val==16 || val>126)
483                         {
484                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
485                                 return(-1);
486                         }
487                         selchannel:
488                         /* add to select-channel list */
489                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
490                         memuse++;
491                         /* set value */
492                         selchannel->channel = val;
493                         /* tail port */
494                         selchannelp = &ifport->in_channel;
495                         while(*selchannelp)
496                                 selchannelp = &((*selchannelp)->next);
497                         *selchannelp = selchannel;
498                 }
499         }
500         return(0);
501 }
502 static int inter_timeouts(struct interface *interface, char *filename, int line, char *parameter, char *value)
503 {
504         struct interface_port *ifport;
505 //      struct select_channel *selchannel, **selchannelp;
506 //      int val;
507         char *p, *el;
508
509         /* port in chain ? */
510         if (!interface->ifport)
511         {
512                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
513                 return(-1);
514         }
515         /* goto end of chain */
516         ifport = interface->ifport;
517         while(ifport->next)
518                 ifport = ifport->next;
519         p = value;
520         if (!*p)
521         {
522                 nofive:
523                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects five timeout values.\n", filename, line, parameter);
524                 return(-1);
525         }
526         el = p;
527         p = get_seperated(p);
528         ifport->tout_setup = atoi(el);
529         if (!*p)
530                 goto nofive;
531         el = p;
532         p = get_seperated(p);
533         ifport->tout_dialing = atoi(el);
534         if (!*p)
535                 goto nofive;
536         el = p;
537         p = get_seperated(p);
538         ifport->tout_proceeding = atoi(el);
539         if (!*p)
540                 goto nofive;
541         el = p;
542         p = get_seperated(p);
543         ifport->tout_alerting = atoi(el);
544         if (!*p)
545                 goto nofive;
546         el = p;
547         p = get_seperated(p);
548         ifport->tout_disconnect = atoi(el);
549         return(0);
550 }
551 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
552 {
553         struct interface_msn *ifmsn, **ifmsnp;
554         char *p, *el;
555
556         if (!value[0])
557         {
558                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
559                 return(-1);
560         }
561         if (interface->ifscreen_in)
562         {
563                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
564                 return(-1);
565         }
566
567         /* process list */
568         p = value;
569         while(*p)
570         {
571                 el = p;
572                 p = get_seperated(p);
573                 /* add MSN to list */
574                 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
575                 memuse++;
576                 /* set value */
577                 SCPY(ifmsn->msn, el);
578                 /* tail port */
579                 ifmsnp = &interface->ifmsn;
580                 while(*ifmsnp)
581                         ifmsnp = &((*ifmsnp)->next);
582                 *ifmsnp = ifmsn;
583         }
584         return(0);
585 }
586 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
587 {
588         struct interface_screen *ifscreen;
589         char *p, *el;
590
591         if (!value[0])
592         {
593                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
594                 return(-1);
595         }
596         /* add screen entry to list*/
597         ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
598         memuse++;
599         ifscreen->match_type = -1; /* unchecked */
600         ifscreen->match_present = -1; /* unchecked */
601         ifscreen->result_type = -1; /* unchanged */
602         ifscreen->result_present = -1; /* unchanged */
603         /* tail port */
604         while(*ifscreenp)
605                 ifscreenp = &((*ifscreenp)->next);
606         *ifscreenp = ifscreen;
607 //      printf("interface=%s\n", interface->name);
608         /* get match */
609         p = value;
610         while(*p)
611         {
612                 el = p;
613                 p = get_seperated(p);
614                 if (!strcasecmp(el, "unknown"))
615                 {
616                         if (ifscreen->match_type != -1)
617                         {
618                                 typeerror:
619                                 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
620                                 return(-1);
621                         }
622                         ifscreen->match_type = INFO_NTYPE_UNKNOWN;
623                 } else
624                 if (!strcasecmp(el, "subscriber"))
625                 {
626                         if (ifscreen->match_type != -1)
627                                 goto typeerror;
628                         ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
629                 } else
630                 if (!strcasecmp(el, "national"))
631                 {
632                         if (ifscreen->match_type != -1)
633                                 goto typeerror;
634                         ifscreen->match_type = INFO_NTYPE_NATIONAL;
635                 } else
636                 if (!strcasecmp(el, "international"))
637                 {
638                         if (ifscreen->match_type != -1)
639                                 goto typeerror;
640                         ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
641                 } else
642                 if (!strcasecmp(el, "allowed"))
643                 {
644                         if (ifscreen->match_present != -1)
645                         {
646                                 presenterror:
647                                 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
648                                 return(-1);
649                         }
650                         ifscreen->match_present = INFO_PRESENT_ALLOWED;
651                 } else
652                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted"))
653                 {
654                         if (ifscreen->match_present != -1)
655                                 goto presenterror;
656                         ifscreen->match_present = INFO_PRESENT_RESTRICTED;
657                 } else {
658                         SCPY(ifscreen->match, el);
659                         /* check for % at the end */
660                         if (strchr(el, '%'))
661                         {
662                                 if (strchr(el, '%') != el+strlen(el)-1)
663                                 {
664                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
665                                         return(-1);
666                                 }
667                         }
668                         break;
669                 }
670         }
671         if (ifscreen->match[0] == '\0')
672         {
673                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
674                 return(-1);
675         }
676         /* get result */
677         while(*p)
678         {
679                 el = p;
680                 p = get_seperated(p);
681                 if (!strcasecmp(el, "unknown"))
682                 {
683                         if (ifscreen->result_type != -1)
684                                 goto typeerror;
685                         ifscreen->result_type = INFO_NTYPE_UNKNOWN;
686                 } else
687                 if (!strcasecmp(el, "subscriber"))
688                 {
689                         if (ifscreen->result_type != -1)
690                                 goto typeerror;
691                         ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
692                 } else
693                 if (!strcasecmp(el, "national"))
694                 {
695                         if (ifscreen->result_type != -1)
696                                 goto typeerror;
697                         ifscreen->result_type = INFO_NTYPE_NATIONAL;
698                 } else
699                 if (!strcasecmp(el, "international"))
700                 {
701                         if (ifscreen->result_type != -1)
702                                 goto typeerror;
703                         ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
704                 } else
705                 if (!strcasecmp(el, "present") || !strcasecmp(el, "presented") || !strcasecmp(el, "allowed") || !strcasecmp(el, "allow"))
706                 {
707                         if (ifscreen->result_present != -1)
708                                 goto presenterror;
709                         ifscreen->result_present = INFO_PRESENT_ALLOWED;
710                 } else
711                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted") || !strcasecmp(el, "deny") || !strcasecmp(el, "denied"))
712                 {
713                         if (ifscreen->result_present != -1)
714                                 goto presenterror;
715                         ifscreen->result_present = INFO_PRESENT_RESTRICTED;
716                 } else {
717                         SCPY(ifscreen->result, el);
718                         /* check for % at the end */
719                         if (strchr(el, '%'))
720                         {
721                                 if (strchr(el, '%') != el+strlen(el)-1)
722                                 {
723                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
724                                         return(-1);
725                                 }
726                         }
727                         break;
728                 }
729         }
730         if (ifscreen->result[0] == '\0')
731         {
732                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
733                 return(-1);
734         }
735         return(0);
736 }
737 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
738 {
739         if (interface->ifmsn)
740         {
741                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
742                 return(-1);
743         }
744
745         return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
746 }
747 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
748 {
749         return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
750 }
751 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
752 {
753         struct interface_port *ifport;
754
755         /* port in chain ? */
756         if (!interface->ifport)
757         {
758                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
759                 return(-1);
760         }
761         /* goto end of chain */
762         ifport = interface->ifport;
763         while(ifport->next)
764                 ifport = ifport->next;
765         ifport->nodtmf = 1;
766         return(0);
767 }
768 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
769 {
770         char *p, *q;
771
772         /* seperate parameter from filter */
773         p = value;
774         while(*p > 32)
775                 p++;
776         if (*p)
777         {
778                 *p++ = 0;
779                 while(*p > 0 && *p <= 32)
780                         p++;
781         }
782
783         if (!strcasecmp(value, "gain"))
784         {
785                 q = p;
786                 while(*q > 32)
787                         q++;
788                 if (*q)
789                 {
790                         *q++ = 0;
791                         while(*q > 0 && *q <= 32)
792                                 q++;
793                 }
794                 if (*p == 0 || *q == 0)
795                 {
796                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects two gain values.\n", filename, line, parameter, value);
797                         return(-1);
798                 }
799                 if (atoi(p)<-8 || atoi(p)>8 || atoi(q)<-8 || atoi(q)>8)
800                 {
801                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' gain values not in range. (-8...8)\n", filename, line, parameter, value);
802                         return(-1);
803                 }
804                 interface->tx_gain = atoi(p);
805                 interface->rx_gain = atoi(q);
806         } else
807         if (!strcasecmp(value, "pipeline"))
808         {
809                 if (*p == 0)
810                 {
811                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects pipeline string.\n", filename, line, parameter, value);
812                         return(-1);
813                 }
814                 SCPY(interface->pipeline, p);
815         } else
816         if (!strcasecmp(value, "blowfish"))
817         {
818                 unsigned char key[56];
819                 int l;
820                 
821                 if (!!strncmp(p, "0x", 2))
822                 {
823                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects blowfish key starting with '0x'.\n", filename, line, parameter, value);
824                         return(-1);
825                 }
826                 p += 2;
827                 l = 0; 
828                 while(*p)
829                 {
830                         if (l == 56)
831                         {
832                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key too long.\n", filename, line, parameter, value);
833                                 return(-1);
834                         }
835                         if (*p >= '0' && *p <= '9')
836                                 key[l] = (*p-'0')<<4;
837                         else if (*p >= 'a' && *p <= 'f')
838                                 key[l] = (*p-'a'+10)<<4;
839                         else if (*p >= 'A' && *p <= 'F')
840                                 key[l] = (*p-'A'+10)<<4;
841                         else
842                         {
843                                 digout:
844                                 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);
845                                 return(-1);
846                         }
847                         p++;
848                         if (*p == 0)
849                         {
850                                 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);
851                                 return(-1);
852                         }
853                         if (*p >= '0' && *p <= '9')
854                                 key[l] = (*p-'0')<<4;
855                         else if (*p >= 'a' && *p <= 'f')
856                                 key[l] = (*p-'a'+10)<<4;
857                         else if (*p >= 'A' && *p <= 'F')
858                                 key[l] = (*p-'A'+10)<<4;
859                         else
860                                 goto digout;
861                         p++;
862                         l++;
863                 }
864                 if (l < 4)
865                 {
866                         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);
867                         return(-1);
868                 }
869                 memcpy(interface->bf_key, key, l);
870                 interface->bf_len = l;
871         } else
872         {
873                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has unknown filter '%s'.\n", filename, line, parameter, value);
874                 return(-1);
875         }
876         return(0);
877 }
878
879
880 /*
881  * structure of parameters
882  */
883 struct interface_param interface_param[] = {
884         { "extension", &inter_extension, "",
885         "If keyword is given, calls to interface are handled as internal extensions."},
886         {"tones", &inter_tones, "yes | no",
887         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
888
889         {"earlyb", &inter_earlyb, "yes | no",
890         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
891
892         {"hunt", &inter_hunt, "linear | roundrobin",
893         "Select the algorithm for selecting port with free channel."},
894
895         {"port", &inter_port, "<number>",
896         ""},
897         {"portnum", &inter_portnum, "<number>",
898         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
899         {"portname", &inter_portname, "<name>",
900         "Same as 'portnum', but the name is given instead.\nUse 'isdninfo' to list all available ports and names."},
901
902         {"block", &inter_block, "",
903         "If keyword is given, calls on this interface are blocked.\n"
904         "This parameter must follow a 'port' parameter."},
905
906         {"ptp", &inter_ptp, "",
907         "The given port above is opened as point-to-point.\n"
908         "This is required on NT-mode ports that are multipoint by default.\n"
909         "This parameter must follow a 'port' parameter."},
910
911 #if 0
912         {"ptmp", &inter_ptmp, "",
913         "The given port above is opened as point-to-multipoint.\n"
914         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
915         "This parameter must follow a 'port' parameter."},
916 #endif
917
918         {"nt", &inter_nt, "",
919         "The given port above is opened in NT-mode.\n"
920         "This is required on interfaces that support both NT-mode and TE-mode.\n"
921         "This parameter must follow a 'port' parameter."},
922
923         {"layer2hold", &inter_l2hold, "yes | no",
924         "The given port will continuously try to establish layer 2 link and hold it.\n"
925         "It is required for PTP links in most cases, therefore it is default.\n"
926         "This parameter must follow a 'port' parameter."},
927
928         {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
929         "Channel selection list for all outgoing calls to the interface.\n"
930         "A free channels is searched in order of appearance.\n"
931         "This parameter must follow a 'port' parameter.\n"
932         " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
933         " <number>[,...] - List of channels to search.\n"
934         " free - Select any free channel\n"
935         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
936         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
937
938         {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
939         "Channel selection list for all incoming calls from the interface.\n"
940         "A free channels is accepted if in the list.\n"
941         "If any channel was requested, the first free channel found is selected.\n"
942         "This parameter must follow a 'port' parameter.\n"
943         " <number>[,...] - List of channels to accept.\n"
944         " free - Accept any free channel"},
945
946         {"timeouts", &inter_timeouts, "<setup> <dialing> <proceeding> <alerting> <disconnect>",
947         "Timeout values for call states. They are both for incoming and outgoing states.\n"
948         "The default is 120 seconds for all states. Use 0 to disable.\n"
949         "This parameter must follow a 'port' parameter.\n"},
950
951         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
952         "Incoming caller ID is checked against given MSN numbers.\n"
953         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
954
955         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
956         "Adds an entry for incoming calls to the caller ID screen list.\n"
957         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
958         "If '%' is given after old caller ID, it matches even if caller ID has\n"
959         "additional digits.\n"
960         "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
961         "are added.\n"
962         "Options can be:\n"
963         " unknown | subsciber | national | international - Change caller ID type.\n"
964         " present | restrict - Change presentation of caller ID."},
965                 
966         {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
967         "Adds an entry for outgoing calls to the caller ID screen list.\n"
968         "See 'screen-in' for help."},
969
970         {"nodtmf", &inter_nodtmf, "",
971         "Disables DTMF detection for this interface.\n"
972         "This parameter must follow a 'port' parameter."},
973
974         {"filter", &inter_filter, "<filter> <parameters>",
975         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
976         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
977         "pipeline <string> - Sets echo cancelation pipeline.\n"
978         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
979
980         {NULL, NULL, NULL, NULL}
981 };
982
983 /* read interfaces
984  *
985  * read settings from interface.conf
986  */
987 char interface_error[256];
988 struct interface *read_interfaces(void)
989 {
990         FILE                    *fp = NULL;
991         char                    filename[128];
992         char                    *p;
993         unsigned int            line, i;
994         char                    buffer[256];
995         struct interface        *interface = NULL, /* in case no interface */
996                                 **interfacep = &interface_newlist;
997         char                    parameter[128];
998         char                    value[256];
999         int                     expecting = 1; /* expecting new interface */
1000         struct interface_param  *ifparam;
1001
1002         if (interface_newlist != NULL)
1003                 FATAL("list is not empty.\n");
1004         interface_error[0] = '\0';
1005         SPRINT(filename, "%s/interface.conf", INSTALL_DATA);
1006
1007         if (!(fp = fopen(filename,"r")))
1008         {
1009                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
1010                 goto error;
1011         }
1012
1013         line=0;
1014         while((fgets(buffer,sizeof(buffer),fp)))
1015         {
1016                 buffer[sizeof(buffer)-1]=0;
1017                 if (buffer[0]) buffer[strlen(buffer)-1]=0;
1018                 p=buffer;
1019                 line++;
1020
1021                 while(*p <= 32) /* skip spaces */
1022                 {
1023                         if (*p == 0)
1024                                 break;
1025                         p++;
1026                 }
1027                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1028                         continue;
1029
1030                 parameter[0]=0;
1031                 value[0]=0;
1032                 i=0; /* read parameter */
1033                 while(*p > 32)
1034                 {
1035                         if (i+1 >= sizeof(parameter))
1036                         {
1037                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
1038                                 goto error;
1039                         }
1040                         parameter[i+1] = '\0';
1041                         parameter[i++] = *p++;
1042                 }
1043
1044                 while(*p <= 32) /* skip spaces */
1045                 {
1046                         if (*p == 0)
1047                                 break;
1048                         p++;
1049                 }
1050
1051                 if (*p!=0 && *p!='#') /* missing name */
1052                 {
1053                         i=0; /* read until end */
1054                         while(*p!=0 && *p!='#')
1055                         {
1056                                 if (i+1 >= sizeof(value))
1057                                 {
1058                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
1059                                         goto error;
1060                                 }
1061                                 value[i+1] = '\0';
1062                                 value[i++] = *p++;
1063                         }
1064
1065                         /* remove trailing spaces from value */
1066                         while(i)
1067                         {
1068                                 if (value[i-1]==0 || value[i-1]>32)
1069                                         break;
1070                                 value[i-1] = '\0';
1071                                 i--;
1072                         }
1073                 }
1074
1075                 /* check for interface name as first statement */
1076                 if (expecting && parameter[0]!='[')
1077                 {
1078                         SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1079                         goto error;
1080                 }
1081                 expecting = 0;
1082
1083                 /* check for new interface */
1084                 if (parameter[0] == '[')
1085                 {
1086                         if (parameter[strlen(parameter)-1] != ']')
1087                         {
1088                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
1089                                 goto error;
1090                         }
1091                         parameter[strlen(parameter)-1] = '\0';
1092
1093                         /* check if interface name already exists */
1094                         interface = interface_newlist;
1095                         while(interface)
1096                         {
1097                                 if (!strcasecmp(interface->name, parameter+1))
1098                                 {
1099                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
1100                                         goto error;
1101                                 }
1102                                 interface = interface->next;
1103                         }
1104
1105                         /* append interface to new list */
1106                         interface = (struct interface *)MALLOC(sizeof(struct interface));
1107                         memuse++;
1108
1109                         /* name interface */
1110                         SCPY(interface->name, parameter+1);
1111
1112                         /* attach */
1113                         *interfacep = interface;
1114                         interfacep = &interface->next;
1115
1116                         continue;
1117                 }
1118
1119                 ifparam = interface_param;
1120                 while(ifparam->name)
1121                 {
1122                         if (!strcasecmp(parameter, ifparam->name))
1123                         {
1124                                 if (ifparam->func(interface, filename, line, parameter, value))
1125                                         goto error;
1126                                 break;
1127                         }
1128                         ifparam++;
1129                 }
1130                 if (ifparam->name)
1131                         continue;
1132
1133                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1134                 goto error;
1135         }
1136
1137         if (fp) fclose(fp);
1138         return(interface_newlist);
1139 error:
1140         PERROR_RUNTIME("%s", interface_error);
1141         if (fp) fclose(fp);
1142         free_interfaces(interface_newlist);
1143         interface_newlist = NULL;
1144         return(NULL);
1145 }
1146
1147
1148 /*
1149  * freeing chain of interfaces
1150  */
1151 void free_interfaces(struct interface *interface)
1152 {
1153         void *temp;
1154         struct interface_port *ifport;
1155         struct select_channel *selchannel;
1156         struct interface_msn *ifmsn;
1157         struct interface_screen *ifscreen;
1158
1159         while(interface)
1160         {
1161                 ifport = interface->ifport;
1162                 while(ifport)
1163                 {
1164                         selchannel = ifport->in_channel;
1165                         while(selchannel)
1166                         {
1167                                 temp = selchannel;
1168                                 selchannel = selchannel->next;
1169                                 FREE(temp, sizeof(struct select_channel));
1170                                 memuse--;
1171                         }
1172                         selchannel = ifport->out_channel;
1173                         while(selchannel)
1174                         {
1175                                 temp = selchannel;
1176                                 selchannel = selchannel->next;
1177                                 FREE(temp, sizeof(struct select_channel));
1178                                 memuse--;
1179                         }
1180                         temp = ifport;
1181                         ifport = ifport->next;
1182                         FREE(temp, sizeof(struct interface_port));
1183                         memuse--;
1184                 }
1185                 ifmsn = interface->ifmsn;
1186                 while(ifmsn)
1187                 {
1188                         temp = ifmsn;
1189                         ifmsn = ifmsn->next;
1190                         FREE(temp, sizeof(struct interface_msn));
1191                         memuse--;
1192                 }
1193                 ifscreen = interface->ifscreen_in;
1194                 while(ifscreen)
1195                 {
1196                         temp = ifscreen;
1197                         ifscreen = ifscreen->next;
1198                         FREE(temp, sizeof(struct interface_screen));
1199                         memuse--;
1200                 }
1201                 ifscreen = interface->ifscreen_out;
1202                 while(ifscreen)
1203                 {
1204                         temp = ifscreen;
1205                         ifscreen = ifscreen->next;
1206                         FREE(temp, sizeof(struct interface_screen));
1207                         memuse--;
1208                 }
1209                 temp = interface;
1210                 interface = interface->next;
1211                 FREE(temp, sizeof(struct interface));
1212                 memuse--;
1213         }
1214 }
1215
1216 /*
1217  * defaults of ports if not specified by config
1218  */
1219 static void set_defaults(struct interface_port *ifport)
1220 {
1221         /* default channel selection list */
1222         if (!ifport->out_channel)
1223                 default_out_channel(ifport);
1224         if (!ifport->in_channel)
1225                 default_in_channel(ifport);
1226         /* default is_tones */
1227         if (ifport->interface->is_tones)
1228                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1229         else
1230                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
1231         /* default is_earlyb */
1232         if (ifport->interface->is_earlyb)
1233                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1234         else
1235                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
1236         /* set locally flag */
1237         if (ifport->interface->extension)
1238                 ifport->mISDNport->locally = 1;
1239         else
1240                 ifport->mISDNport->locally = 0;
1241 }
1242
1243
1244 /*
1245  * all links between mISDNport and interface are made
1246  * unused mISDNports are closed, new mISDNports are opened
1247  * also set default select_channel lists
1248  */
1249 void relink_interfaces(void)
1250 {
1251         struct mISDNport *mISDNport;
1252         struct interface *interface;
1253         struct interface_port *ifport;
1254
1255         /* unlink all mISDNports */
1256         mISDNport = mISDNport_first;
1257         while(mISDNport)
1258         {
1259                 mISDNport->ifport = NULL;
1260                 mISDNport = mISDNport->next;
1261         }
1262
1263         /* relink existing mISDNports */
1264         interface = interface_newlist;
1265         while(interface)
1266         {
1267                 ifport = interface->ifport;
1268                 while(ifport)
1269                 {
1270                         mISDNport = mISDNport_first;
1271                         while(mISDNport)
1272                         {
1273                                 if (mISDNport->portnum == ifport->portnum)
1274                                 {
1275                                         ifport->mISDNport = mISDNport;
1276                                         mISDNport->ifport = ifport;
1277                                         set_defaults(ifport);
1278                                 }
1279                                 mISDNport = mISDNport->next;
1280                         }
1281                         ifport = ifport->next;
1282                 }
1283                 interface = interface->next;
1284         }
1285
1286         /* close unused mISDNports */
1287         closeagain:
1288         mISDNport = mISDNport_first;
1289         while(mISDNport)
1290         {
1291                 if (mISDNport->ifport == NULL)
1292                 {
1293                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1294                         /* remove all port objects and destroy port */
1295                         mISDNport_close(mISDNport);
1296                         goto closeagain;
1297                 }
1298                 mISDNport = mISDNport->next;
1299         }
1300
1301         /* open and link new mISDNports */
1302         interface = interface_newlist;
1303         while(interface)
1304         {
1305                 ifport = interface->ifport;
1306                 while(ifport)
1307                 {
1308                         if (!ifport->mISDNport)
1309                         {
1310                                 load_port(ifport);
1311                         }
1312                         ifport = ifport->next;
1313                 }
1314                 interface = interface->next;
1315         }
1316
1317 }
1318
1319
1320 /*
1321  * load port
1322  */
1323 void load_port(struct interface_port *ifport)
1324 {
1325         struct mISDNport *mISDNport;
1326
1327         /* open new port */
1328         mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->l2hold, ifport->interface);
1329         if (mISDNport)
1330         {
1331                 /* link port */
1332                 ifport->mISDNport = mISDNport;
1333                 mISDNport->ifport = ifport;
1334                 /* set number and name */
1335                 ifport->portnum = mISDNport->portnum;
1336                 SCPY(ifport->portname, mISDNport->name);
1337                 /* set defaults */
1338                 set_defaults(ifport);
1339         } else
1340         {
1341                 ifport->block = 2; /* not available */
1342         }
1343 }
1344
1345 /*
1346  * give summary of interface syntax
1347  */
1348 void doc_interface(void)
1349 {
1350         struct interface_param *ifparam;
1351         
1352         printf("Syntax overview\n");
1353         printf("---------------\n\n");
1354
1355         printf("[<name>]\n");
1356         ifparam = interface_param;
1357         while(ifparam->name)
1358         {
1359                 if (ifparam->name[0])
1360                         printf("%s %s\n", ifparam->name, ifparam->usage);
1361                 ifparam++;
1362         }
1363
1364         ifparam = interface_param;
1365         while(ifparam->name)
1366         {
1367                 if (ifparam->name[0])
1368                 {
1369                         printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1370                         printf("%s\n", ifparam->help);
1371                 }
1372                 ifparam++;
1373         }
1374 }
1375
1376
1377 /* screen caller id
1378  * out==0: incoming caller id, out==1: outgoing caller id
1379  */
1380 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1381 {
1382         char                    *msn1;
1383         struct interface_msn    *ifmsn;
1384         struct interface_screen *ifscreen;
1385         char suffix[64];
1386
1387         /* screen incoming caller id */
1388         if (!out)
1389         {
1390                 /* check for MSN numbers, use first MSN if no match */
1391                 msn1 = NULL;
1392                 ifmsn = interface->ifmsn;
1393                 while(ifmsn)
1394                 {
1395                         if (!msn1)
1396                                 msn1 = ifmsn->msn;
1397                         if (!strcmp(ifmsn->msn, id))
1398                         {
1399                                 break;
1400                         }
1401                         ifmsn = ifmsn->next;
1402                 }
1403                 if (ifmsn)
1404                 {
1405                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (found in MSN list)");
1406                         add_trace("msn", NULL, "%s", id);
1407                         end_trace();
1408                 }
1409                 if (!ifmsn && msn1) // not in list, first msn given
1410                 {
1411                         start_trace(-1, interface, numberrize_callerinfo(id, *type, options.national, options.international), NULL, DIRECTION_IN, 0, 0, "SCREEN (not found in MSN list)");
1412                         add_trace("msn", "given", "%s", id);
1413                         add_trace("msn", "used", "%s", msn1);
1414                         end_trace();
1415                         UNCPY(id, msn1, idsize);
1416                         id[idsize-1] = '\0';
1417                 }
1418         }
1419
1420         /* check screen list */
1421         if (out)
1422                 ifscreen = interface->ifscreen_out;
1423         else
1424                 ifscreen = interface->ifscreen_in;
1425         while (ifscreen)
1426         {
1427                 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1428                 if (ifscreen->match_present==-1 || ifscreen->match_present==*present)
1429                 {
1430                         if (strchr(ifscreen->match,'%'))
1431                         {
1432                                 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1433                                         break;
1434                         } else
1435                         {
1436                                 if (!strcmp(ifscreen->match, id))
1437                                         break;
1438                         }
1439                 }
1440                 ifscreen = ifscreen->next;
1441         }
1442         if (ifscreen) // match
1443         {
1444                 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)");
1445                 switch(*type)
1446                 {
1447                         case INFO_NTYPE_UNKNOWN:
1448                         add_trace("given", "type", "unknown");
1449                         break;
1450                         case INFO_NTYPE_SUBSCRIBER:
1451                         add_trace("given", "type", "subscriber");
1452                         break;
1453                         case INFO_NTYPE_NATIONAL:
1454                         add_trace("given", "type", "national");
1455                         break;
1456                         case INFO_NTYPE_INTERNATIONAL:
1457                         add_trace("given", "type", "international");
1458                         break;
1459                 }
1460                 switch(*present)
1461                 {
1462                         case INFO_PRESENT_ALLOWED:
1463                         add_trace("given", "present", "allowed");
1464                         break;
1465                         case INFO_PRESENT_RESTRICTED:
1466                         add_trace("given", "present", "restricted");
1467                         break;
1468                         case INFO_PRESENT_NOTAVAIL:
1469                         add_trace("given", "present", "not available");
1470                         break;
1471                 }
1472                 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1473                 if (ifscreen->result_type != -1)
1474                 {
1475                         *type = ifscreen->result_type;
1476                         switch(*type)
1477                         {
1478                                 case INFO_NTYPE_UNKNOWN:
1479                                 add_trace("used", "type", "unknown");
1480                                 break;
1481                                 case INFO_NTYPE_SUBSCRIBER:
1482                                 add_trace("used", "type", "subscriber");
1483                                 break;
1484                                 case INFO_NTYPE_NATIONAL:
1485                                 add_trace("used", "type", "national");
1486                                 break;
1487                                 case INFO_NTYPE_INTERNATIONAL:
1488                                 add_trace("used", "type", "international");
1489                                 break;
1490                         }
1491                 }
1492                 if (ifscreen->result_present != -1)
1493                 {
1494                         *present = ifscreen->result_present;
1495                         switch(*present)
1496                         {
1497                                 case INFO_PRESENT_ALLOWED:
1498                                 add_trace("used", "present", "allowed");
1499                                 break;
1500                                 case INFO_PRESENT_RESTRICTED:
1501                                 add_trace("used", "present", "restricted");
1502                                 break;
1503                                 case INFO_PRESENT_NOTAVAIL:
1504                                 add_trace("used", "present", "not available");
1505                                 break;
1506                         }
1507                 }
1508                 if (strchr(ifscreen->match,'%'))
1509                 {
1510                         SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1511                         UNCPY(id, ifscreen->result, idsize);
1512                         id[idsize-1] = '\0';
1513                         if (strchr(id,'%'))
1514                         {
1515                                 *strchr(id,'%') = '\0';
1516                                 UNCAT(id, suffix, idsize);
1517                                 id[idsize-1] = '\0';
1518                         }
1519                 } else
1520                 {
1521                         UNCPY(id, ifscreen->result, idsize);
1522                         id[idsize-1] = '\0';
1523                 }
1524                 add_trace("used", "id", "%s", id[0]?id:"<empty>");
1525                 end_trace();
1526         }
1527 }
1528