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