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