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