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