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