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