fixes & improvements
[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 <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include "main.h"
16
17 struct interface *interface_first = NULL; /* first interface is current list */
18 struct interface *interface_newlist = NULL; /* first interface in new list */
19
20
21 /* set default out_channel */
22 void default_out_channel(struct interface_port *ifport)
23 {
24         struct select_channel *selchannel, **selchannelp;
25
26         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
27         memuse++;
28         
29         if (ifport->mISDNport->ntmode)
30                 selchannel->channel = CHANNEL_FREE;
31         else
32                 selchannel->channel = CHANNEL_ANY;
33         
34         ifport->out_channel = selchannel;
35
36         /* additional channel selection for multipoint NT ports */
37         if (!ifport->mISDNport->ptp && ifport->mISDNport->ntmode)
38         {
39                 selchannelp = &(selchannel->next);
40                 selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
41                 memuse++;
42                 selchannel->channel = CHANNEL_NO; // call waiting
43                 *selchannelp = selchannel;
44         }
45 }
46
47
48 /* set default in_channel */
49 void default_in_channel(struct interface_port *ifport)
50 {
51         struct select_channel *selchannel;
52
53         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
54         memuse++;
55         
56         selchannel->channel = CHANNEL_FREE;
57         
58         ifport->in_channel = selchannel;
59 }
60
61
62 /* parse string for a positive number */
63 static int get_number(char *value)
64 {
65         int val = 0;
66         char text[10];
67
68         val = atoi(value);
69         
70         SPRINT(text, "%d", val);
71
72         if (!strcmp(value, text))
73                 return(val);
74
75         return(-1);
76 }
77
78
79 /* remove element from buffer
80  * and return pointer to next element in buffer */
81 static char *get_seperated(char *buffer)
82 {
83         while(*buffer)
84         {
85                 if (*buffer==',' || *buffer<=32) /* seperate */
86                 {
87                         *buffer++ = '\0';
88                         while((*buffer>'\0' && *buffer<=32) || *buffer==',')
89                                 buffer++;
90                         return(buffer);
91                 }
92                 buffer++;
93         }
94         return(buffer);
95 }
96
97 /*
98  * parameter processing
99  */
100 static int inter_block(struct interface *interface, char *filename, int line, char *parameter, char *value)
101 {
102         struct interface_port *ifport;
103
104         /* port in chain ? */
105         if (!interface->ifport)
106         {
107                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
108                 return(-1);
109         }
110         /* goto end of chain */
111         ifport = interface->ifport;
112         while(ifport->next)
113                 ifport = ifport->next;
114         /* add value */
115         if (value[0])
116         {
117                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
118                 return(-1);
119         }
120         ifport->block = 1;
121         return(0);
122 }
123 static int inter_extension(struct interface *interface, char *filename, int line, char *parameter, char *value)
124 {
125         if (value[0])
126         {
127                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
128                 return(-1);
129         }
130         interface->extension = 1;
131         return(0);
132 }
133 static int inter_ptp(struct interface *interface, char *filename, int line, char *parameter, char *value)
134 {
135         struct interface_port *ifport;
136
137         /* port in chain ? */
138         if (!interface->ifport)
139         {
140                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
141                 return(-1);
142         }
143         if (interface->ifport->ptmp)
144         {
145                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptmp was given.\n", filename, line, parameter);
146                 return(-1);
147         }
148         /* goto end of chain */
149         ifport = interface->ifport;
150         while(ifport->next)
151                 ifport = ifport->next;
152         /* add value */
153         if (value[0])
154         {
155                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
156                 return(-1);
157         }
158         ifport->ptp = 1;
159         return(0);
160 }
161 static int inter_ptmp(struct interface *interface, char *filename, int line, char *parameter, char *value)
162 {
163         struct interface_port *ifport;
164
165         /* port in chain ? */
166         if (!interface->ifport)
167         {
168                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
169                 return(-1);
170         }
171         if (interface->ifport->ptp)
172         {
173                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' previously ptp was given.\n", filename, line, parameter);
174                 return(-1);
175         }
176         /* goto end of chain */
177         ifport = interface->ifport;
178         while(ifport->next)
179                 ifport = ifport->next;
180         /* add value */
181         if (value[0])
182         {
183                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
184                 return(-1);
185         }
186         ifport->ptmp = 1;
187         return(0);
188 }
189 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
190 {
191         if (!strcasecmp(value, "yes"))
192         {
193                 interface->is_tones = IS_YES;
194         } else
195         if (!strcasecmp(value, "no"))
196         {
197                 interface->is_tones = IS_NO;
198         } else
199         {
200                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
201                 return(-1);
202         }
203         return(0);
204 }
205 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
206 {
207         if (!strcasecmp(value, "yes"))
208         {
209                 interface->is_earlyb = IS_YES;
210         } else
211         if (!strcasecmp(value, "no"))
212         {
213                 interface->is_earlyb = IS_NO;
214         } else
215         {
216                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
217                 return(-1);
218         }
219         return(0);
220 }
221 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
222 {
223         if (!strcasecmp(value, "linear"))
224         {
225                 interface->hunt = HUNT_LINEAR;
226         } else
227         if (!strcasecmp(value, "roundrobin"))
228         {
229                 interface->hunt = HUNT_ROUNDROBIN;
230         } else
231         {
232                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
233                 return(-1);
234         }
235         return(0);
236 }
237 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
238 {
239         struct interface_port *ifport, **ifportp;
240         struct interface *searchif;
241         int val;
242
243         val = get_number(value);
244         if (val == -1)
245         {
246                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
247                 return(-1);
248         }
249         /* check for port already assigned */
250         searchif = interface_newlist;
251         while(searchif)
252         {
253                 ifport = searchif->ifport;
254                 while(ifport)
255                 {
256                         if (ifport->portnum == val)
257                         {
258                                 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
259                                 return(-1);
260                         }
261                         ifport = ifport->next;
262                 }
263                 searchif = searchif->next;
264         }
265         /* alloc port substructure */
266         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
267         memuse++;
268         ifport->interface = interface;
269         /* set value */
270         ifport->portnum = val;
271         /* tail port */
272         ifportp = &interface->ifport;
273         while(*ifportp)
274                 ifportp = &((*ifportp)->next);
275         *ifportp = ifport;
276         return(0);
277 }
278 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
279 {
280         struct interface_port *ifport;
281         struct select_channel *selchannel, **selchannelp;
282         int val;
283         char *p, *el;
284
285         /* port in chain ? */
286         if (!interface->ifport)
287         {
288                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
289                 return(-1);
290         }
291         /* goto end of chain */
292         ifport = interface->ifport;
293         while(ifport->next)
294                 ifport = ifport->next;
295         p = value;
296         while(*p)
297         {
298                 el = p;
299                 p = get_seperated(p);
300                 if (!strcasecmp(el, "force"))
301                 {
302                         ifport->channel_force = 1;
303                         if (ifport->out_channel)
304                         {
305                                 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
306                                 return(-1);
307                         }
308                 } else
309                 if (!strcasecmp(el, "any"))
310                 {
311                         val = CHANNEL_ANY;
312                         goto selchannel;
313                 } else
314                 if (!strcasecmp(el, "free"))
315                 {
316                         val = CHANNEL_FREE;
317                         goto selchannel;
318                 } else
319                 if (!strcasecmp(el, "no"))
320                 {
321                         val = CHANNEL_NO;
322                         goto selchannel;
323                 } else
324                 {
325                         val = get_number(el);
326                         if (val == -1)
327                         {
328                                 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);
329                                 return(-1);
330                         }
331
332                         if (val<1 || val==16 || val>126)
333                         {
334                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
335                                 return(-1);
336                         }
337                         selchannel:
338                         /* add to select-channel list */
339                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
340                         memuse++;
341                         /* set value */
342                         selchannel->channel = val;
343                         /* tail port */
344                         selchannelp = &ifport->out_channel;
345                         while(*selchannelp)
346                                 selchannelp = &((*selchannelp)->next);
347                         *selchannelp = selchannel;
348                 }
349         }
350         return(0);
351 }
352 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
353 {
354         struct interface_port *ifport;
355         struct select_channel *selchannel, **selchannelp;
356         int val;
357         char *p, *el;
358
359         /* port in chain ? */
360         if (!interface->ifport)
361         {
362                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
363                 return(-1);
364         }
365         /* goto end of chain */
366         ifport = interface->ifport;
367         while(ifport->next)
368                 ifport = ifport->next;
369         p = value;
370         while(*p)
371         {
372                 el = p;
373                 p = get_seperated(p);
374                 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE)
375                 {
376                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
377                                 return(-1);
378                 }
379                 if (!strcasecmp(el, "free"))
380                 {
381                         val = CHANNEL_FREE;
382                         goto selchannel;
383                 } else
384                 {
385                         val = get_number(el);
386                         if (val == -1)
387                         {
388                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
389                                 return(-1);
390                         }
391
392                         if (val<1 || val==16 || val>126)
393                         {
394                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
395                                 return(-1);
396                         }
397                         selchannel:
398                         /* add to select-channel list */
399                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
400                         memuse++;
401                         /* set value */
402                         selchannel->channel = val;
403                         /* tail port */
404                         selchannelp = &ifport->in_channel;
405                         while(*selchannelp)
406                                 selchannelp = &((*selchannelp)->next);
407                         *selchannelp = selchannel;
408                 }
409         }
410         return(0);
411 }
412 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
413 {
414         struct interface_msn *ifmsn, **ifmsnp;
415         char *p, *el;
416
417         if (!value[0])
418         {
419                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
420                 return(-1);
421         }
422         if (interface->ifscreen_in)
423         {
424                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
425                 return(-1);
426         }
427
428         /* process list */
429         p = value;
430         while(*p)
431         {
432                 el = p;
433                 p = get_seperated(p);
434                 /* add MSN to list */
435                 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
436                 memuse++;
437                 /* set value */
438                 SCPY(ifmsn->msn, el);
439                 /* tail port */
440                 ifmsnp = &interface->ifmsn;
441                 while(*ifmsnp)
442                         ifmsnp = &((*ifmsnp)->next);
443                 *ifmsnp = ifmsn;
444         }
445         return(0);
446 }
447 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
448 {
449         struct interface_screen *ifscreen;
450         char *p, *el;
451
452         if (!value[0])
453         {
454                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
455                 return(-1);
456         }
457         p = value;
458         el = p;
459         p = get_seperated(p);
460         /* add screen entry to list*/
461         ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
462         memuse++;
463         ifscreen->match_type = -1; /* unchecked */
464         ifscreen->match_present = -1; /* unchecked */
465         ifscreen->result_type = -1; /* unchanged */
466         ifscreen->result_present = -1; /* unchanged */
467         /* tail port */
468         while(*ifscreenp)
469                 ifscreenp = &((*ifscreenp)->next);
470         *ifscreenp = ifscreen;
471         /* get match */
472         while(*p)
473         {
474                 el = p;
475                 p = get_seperated(p);
476                 if (!strcasecmp(el, "unknown"))
477                 {
478                         if (ifscreen->match_type != -1)
479                         {
480                                 typeerror:
481                                 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
482                                 return(-1);
483                         }
484                         ifscreen->match_type = INFO_NTYPE_UNKNOWN;
485                 } else
486                 if (!strcasecmp(el, "subscriber"))
487                 {
488                         if (ifscreen->match_type != -1)
489                                 goto typeerror;
490                         ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
491                 } else
492                 if (!strcasecmp(el, "national"))
493                 {
494                         if (ifscreen->match_type != -1)
495                                 goto typeerror;
496                         ifscreen->match_type = INFO_NTYPE_NATIONAL;
497                 } else
498                 if (!strcasecmp(el, "international"))
499                 {
500                         if (ifscreen->match_type != -1)
501                                 goto typeerror;
502                         ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
503                 } else
504                 if (!strcasecmp(el, "allowed"))
505                 {
506                         if (ifscreen->match_present != -1)
507                         {
508                                 presenterror:
509                                 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
510                                 return(-1);
511                         }
512                         ifscreen->match_present = INFO_PRESENT_ALLOWED;
513                 } else
514                 if (!strcasecmp(el, "restricted"))
515                 {
516                         if (ifscreen->match_present != -1)
517                                 goto presenterror;
518                         ifscreen->match_present = INFO_PRESENT_RESTRICTED;
519                 } else {
520                         SCPY(ifscreen->match, el);
521                         /* check for % at the end */
522                         if (strchr(el, '%'))
523                         {
524                                 if (strchr(el, '%') != el+strlen(el)-1)
525                                 {
526                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
527                                         return(-1);
528                                 }
529                         }
530                         break;
531                 }
532         }
533         if (ifscreen->match[0] == '\0')
534         {
535                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
536                 return(-1);
537         }
538         /* get result */
539         while(*p)
540         {
541                 el = p;
542                 p = get_seperated(p);
543                 if (!strcasecmp(el, "unknown"))
544                 {
545                         if (ifscreen->result_type != -1)
546                                 goto typeerror;
547                         ifscreen->result_type = INFO_NTYPE_UNKNOWN;
548                 } else
549                 if (!strcasecmp(el, "subscriber"))
550                 {
551                         if (ifscreen->result_type != -1)
552                                 goto typeerror;
553                         ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
554                 } else
555                 if (!strcasecmp(el, "national"))
556                 {
557                         if (ifscreen->result_type != -1)
558                                 goto typeerror;
559                         ifscreen->result_type = INFO_NTYPE_NATIONAL;
560                 } else
561                 if (!strcasecmp(el, "international"))
562                 {
563                         if (ifscreen->result_type != -1)
564                                 goto typeerror;
565                         ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
566                 } else
567                 if (!strcasecmp(el, "allowed"))
568                 {
569                         if (ifscreen->result_present != -1)
570                                 goto presenterror;
571                         ifscreen->result_present = INFO_PRESENT_ALLOWED;
572                 } else
573                 if (!strcasecmp(el, "restricted"))
574                 {
575                         if (ifscreen->result_present != -1)
576                                 goto presenterror;
577                         ifscreen->result_present = INFO_PRESENT_RESTRICTED;
578                 } else {
579                         SCPY(ifscreen->result, el);
580                         /* check for % at the end */
581                         if (strchr(el, '%'))
582                         {
583                                 if (strchr(el, '%') != el+strlen(el)-1)
584                                 {
585                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
586                                         return(-1);
587                                 }
588                         }
589                         break;
590                 }
591         }
592         if (ifscreen->result[0] == '\0')
593         {
594                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
595                 return(-1);
596         }
597         return(0);
598 }
599 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
600 {
601         if (interface->ifmsn)
602         {
603                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
604                 return(-1);
605         }
606
607         return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
608 }
609 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
610 {
611         return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
612 }
613 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
614 {
615         struct interface_port *ifport;
616
617         /* port in chain ? */
618         if (!interface->ifport)
619         {
620                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
621                 return(-1);
622         }
623         /* goto end of chain */
624         ifport = interface->ifport;
625         while(ifport->next)
626                 ifport = ifport->next;
627         ifport->nodtmf = 1;
628         return(0);
629 }
630 #warning filter to be done
631 #if 0
632 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
633 {
634         return(0);
635 }
636 #endif
637
638
639 /*
640  * structure of parameters
641  */
642 struct interface_param interface_param[] = {
643         { "extension", &inter_extension, "",
644         "If keyword is given, calls to interface are handled as internal extensions."},
645         {"tones", &inter_tones, "yes | no",
646         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode interfaces generate tones."},
647
648         {"earlyb", &inter_earlyb, "yes | no",
649         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode interfaces receive tones."},
650
651         {"hunt", &inter_hunt, "linear | roundrobin",
652         "Select the algorithm for selecting port with free channel."},
653
654         {"port", &inter_port, "<number>",
655         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
656
657         {"block", &inter_block, "",
658         "If keyword is given, calls on this interface are blocked.\n"
659         "This parameter must follow a 'port' parameter."},
660
661         {"ptp", &inter_ptp, "",
662         "The given port above is opened as point-to-point.\n"
663         "This is required on NT-mode ports that are multipoint by default.\n"
664         "This parameter must follow a 'port' parameter."},
665
666         {"ptmp", &inter_ptmp, "",
667         "The given port above is opened as point-to-multipoint.\n"
668         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
669         "This parameter must follow a 'port' parameter."},
670
671         {"channel_out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
672         "Channel selection list for all outgoing calls to the interface.\n"
673         "A free channels is searched in order of appearance.\n"
674         "This parameter must follow a 'port' parameter.\n"
675         " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
676         " <number>[,...] - List of channels to search.\n"
677         " free - Select any free channel\n"
678         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
679         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
680
681         {"channel_in", &inter_channel_in, "[force,][<number>][,...][,free][,any][,no]",
682         "Channel selection list for all incomming calls from the interface.\n"
683         "A free channels is accepted if in the list.\n"
684         "If no channel was requested, the first free channel found is selected.\n"
685         "This parameter must follow a 'port' parameter.\n"
686         " <number>[,...] - List of channels to accept.\n"
687         " free - Accept any free channel"},
688
689         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
690         "Incomming caller ID is checked against given MSN numbers.\n"
691         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
692
693         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%%] [options] <new caller ID>[%%]",
694         "Adds an entry for incomming calls to the caller ID screen list.\n"
695         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
696         "If '%%' is given after old caller ID, it matches even if caller ID has\n"
697         "additional digits.\n"
698         "If '%%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
699         "are added.\n"
700         "Options can be:\n"
701         " unknown | subsciber | national | international - Change caller ID type.\n"
702         " present | restrict - Change presentation of caller ID."},
703                 
704         {"screen-out", &inter_screen_out, "<old caller ID> <new caller ID> [options]",
705         "Adds an entry for outgoing calls to the caller ID screen list.\n"
706         "See 'screen-in' for help."},
707
708         {"nodtmf", &inter_nodtmf, "",
709         "Disables DTMF detection for this interface.\n"
710         "This parameter must follow a 'port' parameter."},
711
712 #if 0
713 #warning todo: filter, also in the PmISDN object
714         {"filter", &inter_filter, "<filter> [parameters]",
715         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
716         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
717         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
718 #endif
719
720         {NULL, NULL, NULL, NULL}
721 };
722
723 /* read interfaces
724  *
725  * read settings from interface.conf
726  */
727 char interface_error[256];
728 struct interface *read_interfaces(void)
729 {
730         FILE                    *fp = NULL;
731         char                    filename[128];
732         char                    *p;
733         unsigned int            line, i;
734         char                    buffer[256];
735         struct interface        *interface = NULL, /* in case no interface */
736                                 **interfacep = &interface_newlist;
737         char                    parameter[128];
738         char                    value[256];
739         int                     expecting = 1; /* expecting new interface */
740         struct interface_param  *ifparam;
741
742         if (interface_newlist != NULL)
743                 FATAL("list is not empty.\n");
744         interface_error[0] = '\0';
745         SPRINT(filename, "%s/interface.conf", INSTALL_DATA);
746
747         if (!(fp = fopen(filename,"r")))
748         {
749                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
750                 goto error;
751         }
752
753         line=0;
754         while((fgets(buffer,sizeof(buffer),fp)))
755         {
756                 buffer[sizeof(buffer)-1]=0;
757                 if (buffer[0]) buffer[strlen(buffer)-1]=0;
758                 p=buffer;
759                 line++;
760
761                 while(*p <= 32) /* skip spaces */
762                 {
763                         if (*p == 0)
764                                 break;
765                         p++;
766                 }
767                 if (*p==0 || *p=='#') /* ignore comments and empty line */
768                         continue;
769
770                 parameter[0]=0;
771                 value[0]=0;
772                 i=0; /* read parameter */
773                 while(*p > 32)
774                 {
775                         if (i+1 >= sizeof(parameter))
776                         {
777                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
778                                 goto error;
779                         }
780                         parameter[i+1] = '\0';
781                         parameter[i++] = *p++;
782                 }
783
784                 while(*p <= 32) /* skip spaces */
785                 {
786                         if (*p == 0)
787                                 break;
788                         p++;
789                 }
790
791                 if (*p!=0 && *p!='#') /* missing name */
792                 {
793                         i=0; /* read until end */
794                         while(*p!=0 && *p!='#')
795                         {
796                                 if (i+1 >= sizeof(value))
797                                 {
798                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
799                                         goto error;
800                                 }
801                                 value[i+1] = '\0';
802                                 value[i++] = *p++;
803                         }
804
805                         /* remove trailing spaces from value */
806                         while(i)
807                         {
808                                 if (value[i-1]==0 || value[i-1]>32)
809                                         break;
810                                 value[i-1] = '\0';
811                                 i--;
812                         }
813                 }
814
815                 /* check for interface name as first statement */
816                 if (expecting && parameter[0]!='[')
817                 {
818                         SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
819                         goto error;
820                 }
821                 expecting = 0;
822
823                 /* check for new interface */
824                 if (parameter[0] == '[')
825                 {
826                         if (parameter[strlen(parameter)-1] != ']')
827                         {
828                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
829                                 goto error;
830                         }
831                         parameter[strlen(parameter)-1] = '\0';
832
833                         /* check if interface name already exists */
834                         interface = interface_newlist;
835                         while(interface)
836                         {
837                                 if (!strcasecmp(interface->name, parameter+1))
838                                 {
839                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
840                                         goto error;
841                                 }
842                                 interface = interface->next;
843                         }
844
845                         /* append interface to new list */
846                         interface = (struct interface *)MALLOC(sizeof(struct interface));
847                         memuse++;
848
849                         /* name interface */
850                         SCPY(interface->name, parameter+1);
851
852                         /* attach */
853                         *interfacep = interface;
854                         interfacep = &interface->next;
855
856                         continue;
857                 }
858
859                 ifparam = interface_param;
860                 while(ifparam->name)
861                 {
862                         if (!strcasecmp(parameter, ifparam->name))
863                         {
864                                 if (ifparam->func(interface, filename, line, parameter, value))
865                                         goto error;
866                                 break;
867                         }
868                         ifparam++;
869                 }
870                 if (ifparam->name)
871                         continue;
872
873                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
874                 goto error;
875         }
876
877         if (fp) fclose(fp);
878         return(interface_newlist);
879 error:
880         PERROR_RUNTIME("%s", interface_error);
881         if (fp) fclose(fp);
882         free_interfaces(interface_newlist);
883         interface_newlist = NULL;
884         return(NULL);
885 }
886
887
888 /*
889  * freeing chain of interfaces
890  */
891 void free_interfaces(struct interface *interface)
892 {
893         void *temp;
894         struct interface_port *ifport;
895         struct select_channel *selchannel;
896         struct interface_msn *ifmsn;
897         struct interface_screen *ifscreen;
898         struct interface_filter *iffilter;
899
900         while(interface)
901         {
902                 ifport = interface->ifport;
903                 while(ifport)
904                 {
905                         selchannel = ifport->in_channel;
906                         while(selchannel)
907                         {
908                                 temp = selchannel;
909                                 selchannel = selchannel->next;
910                                 FREE(temp, sizeof(struct select_channel));
911                                 memuse--;
912                         }
913                         selchannel = ifport->out_channel;
914                         while(selchannel)
915                         {
916                                 temp = selchannel;
917                                 selchannel = selchannel->next;
918                                 FREE(temp, sizeof(struct select_channel));
919                                 memuse--;
920                         }
921                         temp = ifport;
922                         ifport = ifport->next;
923                         FREE(temp, sizeof(struct interface_port));
924                         memuse--;
925                 }
926                 ifmsn = interface->ifmsn;
927                 while(ifmsn)
928                 {
929                         temp = ifmsn;
930                         ifmsn = ifmsn->next;
931                         FREE(temp, sizeof(struct interface_msn));
932                         memuse--;
933                 }
934                 ifscreen = interface->ifscreen_in;
935                 while(ifscreen)
936                 {
937                         temp = ifscreen;
938                         ifscreen = ifscreen->next;
939                         FREE(temp, sizeof(struct interface_screen));
940                         memuse--;
941                 }
942                 ifscreen = interface->ifscreen_out;
943                 while(ifscreen)
944                 {
945                         temp = ifscreen;
946                         ifscreen = ifscreen->next;
947                         FREE(temp, sizeof(struct interface_screen));
948                         memuse--;
949                 }
950                 iffilter = interface->iffilter;
951                 while(iffilter)
952                 {
953                         temp = iffilter;
954                         iffilter = iffilter->next;
955                         FREE(temp, sizeof(struct interface_filter));
956                         memuse--;
957                 }
958                 temp = interface;
959                 interface = interface->next;
960                 FREE(temp, sizeof(struct interface));
961                 memuse--;
962         }
963 }
964
965 /*
966  * defaults of ports if not specified by config
967  */
968 static void set_defaults(struct interface_port *ifport)
969 {
970         /* default channel selection list */
971         if (!ifport->out_channel)
972                 default_out_channel(ifport);
973         if (!ifport->in_channel)
974                 default_in_channel(ifport);
975         /* default is_tones */
976         if (ifport->interface->is_tones)
977                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
978         else
979                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
980         /* default is_earlyb */
981         if (ifport->interface->is_earlyb)
982                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
983         else
984                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
985         /* set locally flag */
986         if (ifport->interface->extension)
987                 ifport->mISDNport->locally = 1;
988         else
989                 ifport->mISDNport->locally = 0;
990 }
991
992
993 /*
994  * all links between mISDNport and interface are made
995  * unused mISDNports are closed, new mISDNports are opened
996  * also set default select_channel lists
997  */
998 void relink_interfaces(void)
999 {
1000         struct mISDNport *mISDNport;
1001         struct interface *interface;
1002         struct interface_port *ifport;
1003
1004         /* unlink all mISDNports */
1005         mISDNport = mISDNport_first;
1006         while(mISDNport)
1007         {
1008                 mISDNport->ifport = NULL;
1009                 mISDNport = mISDNport->next;
1010         }
1011
1012         /* relink existing mISDNports */
1013         interface = interface_newlist;
1014         while(interface)
1015         {
1016                 ifport = interface->ifport;
1017                 while(ifport)
1018                 {
1019                         mISDNport = mISDNport_first;
1020                         while(mISDNport)
1021                         {
1022                                 if (mISDNport->portnum == ifport->portnum)
1023                                 {
1024                                         ifport->mISDNport = mISDNport;
1025                                         mISDNport->ifport = ifport;
1026                                         set_defaults(ifport);
1027                                 }
1028                                 mISDNport = mISDNport->next;
1029                         }
1030                         ifport = ifport->next;
1031                 }
1032                 interface = interface->next;
1033         }
1034
1035         /* close unused mISDNports */
1036         closeagain:
1037         mISDNport = mISDNport_first;
1038         while(mISDNport)
1039         {
1040                 if (mISDNport->ifport == NULL)
1041                 {
1042                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1043                         /* remove all port objects and destroy port */
1044                         mISDNport_close(mISDNport);
1045                         goto closeagain;
1046                 }
1047                 mISDNport = mISDNport->next;
1048         }
1049
1050         /* open and link new mISDNports */
1051         interface = interface_newlist;
1052         while(interface)
1053         {
1054                 ifport = interface->ifport;
1055                 while(ifport)
1056                 {
1057                         if (!ifport->mISDNport)
1058                         {
1059                                 load_port(ifport);
1060                         }
1061                         ifport = ifport->next;
1062                 }
1063                 interface = interface->next;
1064         }
1065
1066 }
1067
1068
1069 /*
1070  * load port
1071  */
1072 void load_port(struct interface_port *ifport)
1073 {
1074         struct mISDNport *mISDNport;
1075
1076         /* open new port */
1077         mISDNport = mISDNport_open(ifport->portnum, ifport->ptp, ifport->ptmp, ifport->interface);
1078         if (mISDNport)
1079         {
1080                 /* link port */
1081                 ifport->mISDNport = mISDNport;
1082                 mISDNport->ifport = ifport;
1083                 set_defaults(ifport);
1084         } else
1085         {
1086                 ifport->block = 2; /* not available */
1087         }
1088 }
1089
1090 /*
1091  * give summary of interface syntax
1092  */
1093 void doc_interface(void)
1094 {
1095         struct interface_param *ifparam;
1096         
1097         printf("Syntax overview\n");
1098         printf("---------------\n\n");
1099
1100         printf("[<name>]\n");
1101         ifparam = interface_param;
1102         while(ifparam->name)
1103         {
1104                 printf("%s %s\n", ifparam->name, ifparam->usage);
1105                 ifparam++;
1106         }
1107
1108         ifparam = interface_param;
1109         while(ifparam->name)
1110         {
1111                 printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1112                 printf("%s\n", ifparam->help);
1113                 ifparam++;
1114         }
1115 }
1116