fixes, screen in and out works, fixed release problem in mISDNuser
[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_nt(struct interface *interface, char *filename, int line, char *parameter, char *value)
190 {
191 #ifdef SOCKET_MISDN
192         struct interface_port *ifport;
193
194         /* port in chain ? */
195         if (!interface->ifport)
196         {
197                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
198                 return(-1);
199         }
200         /* goto end of chain */
201         ifport = interface->ifport;
202         while(ifport->next)
203                 ifport = ifport->next;
204         /* add value */
205         if (value[0])
206         {
207                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects no value.\n", filename, line, parameter);
208                 return(-1);
209         }
210         ifport->nt = 1;
211 #endif
212         return(0);
213 }
214 static int inter_tones(struct interface *interface, char *filename, int line, char *parameter, char *value)
215 {
216         if (!strcasecmp(value, "yes"))
217         {
218                 interface->is_tones = IS_YES;
219         } else
220         if (!strcasecmp(value, "no"))
221         {
222                 interface->is_tones = IS_NO;
223         } else
224         {
225                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
226                 return(-1);
227         }
228         return(0);
229 }
230 static int inter_earlyb(struct interface *interface, char *filename, int line, char *parameter, char *value)
231 {
232         if (!strcasecmp(value, "yes"))
233         {
234                 interface->is_earlyb = IS_YES;
235         } else
236         if (!strcasecmp(value, "no"))
237         {
238                 interface->is_earlyb = IS_NO;
239         } else
240         {
241                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'yes' or 'no'.\n", filename, line, parameter);
242                 return(-1);
243         }
244         return(0);
245 }
246 static int inter_hunt(struct interface *interface, char *filename, int line, char *parameter, char *value)
247 {
248         if (!strcasecmp(value, "linear"))
249         {
250                 interface->hunt = HUNT_LINEAR;
251         } else
252         if (!strcasecmp(value, "roundrobin"))
253         {
254                 interface->hunt = HUNT_ROUNDROBIN;
255         } else
256         {
257                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects value 'linear' or 'roundrobin'.\n", filename, line, parameter);
258                 return(-1);
259         }
260         return(0);
261 }
262 static int inter_port(struct interface *interface, char *filename, int line, char *parameter, char *value)
263 {
264         struct interface_port *ifport, **ifportp;
265         struct interface *searchif;
266         int val;
267
268         val = get_number(value);
269         if (val == -1)
270         {
271                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one numeric value.\n", filename, line, parameter);
272                 return(-1);
273         }
274         /* check for port already assigned */
275         searchif = interface_newlist;
276         while(searchif)
277         {
278                 ifport = searchif->ifport;
279                 while(ifport)
280                 {
281                         if (ifport->portnum == val)
282                         {
283                                 SPRINT(interface_error, "Error in %s (line %d): port '%d' already used above.\n", filename, line, val);
284                                 return(-1);
285                         }
286                         ifport = ifport->next;
287                 }
288                 searchif = searchif->next;
289         }
290         /* alloc port substructure */
291         ifport = (struct interface_port *)MALLOC(sizeof(struct interface_port));
292         memuse++;
293         ifport->interface = interface;
294         /* set value */
295         ifport->portnum = val;
296         /* tail port */
297         ifportp = &interface->ifport;
298         while(*ifportp)
299                 ifportp = &((*ifportp)->next);
300         *ifportp = ifport;
301         return(0);
302 }
303 static int inter_channel_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
304 {
305         struct interface_port *ifport;
306         struct select_channel *selchannel, **selchannelp;
307         int val;
308         char *p, *el;
309
310         /* port in chain ? */
311         if (!interface->ifport)
312         {
313                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
314                 return(-1);
315         }
316         /* goto end of chain */
317         ifport = interface->ifport;
318         while(ifport->next)
319                 ifport = ifport->next;
320         p = value;
321         while(*p)
322         {
323                 el = p;
324                 p = get_seperated(p);
325                 if (!strcasecmp(el, "force"))
326                 {
327                         ifport->channel_force = 1;
328                         if (ifport->out_channel)
329                         {
330                                 SPRINT(interface_error, "Error in %s (line %d): value 'force' may only appear as first element in list.\n", filename, line);
331                                 return(-1);
332                         }
333                 } else
334                 if (!strcasecmp(el, "any"))
335                 {
336                         val = CHANNEL_ANY;
337                         goto selchannel;
338                 } else
339                 if (!strcasecmp(el, "free"))
340                 {
341                         val = CHANNEL_FREE;
342                         goto selchannel;
343                 } else
344                 if (!strcasecmp(el, "no"))
345                 {
346                         val = CHANNEL_NO;
347                         goto selchannel;
348                 } else
349                 {
350                         val = get_number(el);
351                         if (val == -1)
352                         {
353                                 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);
354                                 return(-1);
355                         }
356
357                         if (val<1 || val==16 || val>126)
358                         {
359                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
360                                 return(-1);
361                         }
362                         selchannel:
363                         /* add to select-channel list */
364                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
365                         memuse++;
366                         /* set value */
367                         selchannel->channel = val;
368                         /* tail port */
369                         selchannelp = &ifport->out_channel;
370                         while(*selchannelp)
371                                 selchannelp = &((*selchannelp)->next);
372                         *selchannelp = selchannel;
373                 }
374         }
375         return(0);
376 }
377 static int inter_channel_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
378 {
379         struct interface_port *ifport;
380         struct select_channel *selchannel, **selchannelp;
381         int val;
382         char *p, *el;
383
384         /* port in chain ? */
385         if (!interface->ifport)
386         {
387                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
388                 return(-1);
389         }
390         /* goto end of chain */
391         ifport = interface->ifport;
392         while(ifport->next)
393                 ifport = ifport->next;
394         p = value;
395         while(*p)
396         {
397                 el = p;
398                 p = get_seperated(p);
399                 if (ifport->in_channel) if (ifport->in_channel->channel == CHANNEL_FREE)
400                 {
401                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has values behind 'free' keyword. They has no effect.\n", filename, line, parameter);
402                                 return(-1);
403                 }
404                 if (!strcasecmp(el, "free"))
405                 {
406                         val = CHANNEL_FREE;
407                         goto selchannel;
408                 } else
409                 {
410                         val = get_number(el);
411                         if (val == -1)
412                         {
413                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects a comma seperated list of channel numbers and 'free'.\n", filename, line, parameter);
414                                 return(-1);
415                         }
416
417                         if (val<1 || val==16 || val>126)
418                         {
419                                 SPRINT(interface_error, "Error in %s (line %d): channel '%d' out of range.\n", filename, line, val);
420                                 return(-1);
421                         }
422                         selchannel:
423                         /* add to select-channel list */
424                         selchannel = (struct select_channel *)MALLOC(sizeof(struct select_channel));
425                         memuse++;
426                         /* set value */
427                         selchannel->channel = val;
428                         /* tail port */
429                         selchannelp = &ifport->in_channel;
430                         while(*selchannelp)
431                                 selchannelp = &((*selchannelp)->next);
432                         *selchannelp = selchannel;
433                 }
434         }
435         return(0);
436 }
437 static int inter_msn(struct interface *interface, char *filename, int line, char *parameter, char *value)
438 {
439         struct interface_msn *ifmsn, **ifmsnp;
440         char *p, *el;
441
442         if (!value[0])
443         {
444                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects one MSN number or a list.\n", filename, line, parameter);
445                 return(-1);
446         }
447         if (interface->ifscreen_in)
448         {
449                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'screen_in' parameter.\n", filename, line, parameter);
450                 return(-1);
451         }
452
453         /* process list */
454         p = value;
455         while(*p)
456         {
457                 el = p;
458                 p = get_seperated(p);
459                 /* add MSN to list */
460                 ifmsn = (struct interface_msn *)MALLOC(sizeof(struct interface_msn));
461                 memuse++;
462                 /* set value */
463                 SCPY(ifmsn->msn, el);
464                 /* tail port */
465                 ifmsnp = &interface->ifmsn;
466                 while(*ifmsnp)
467                         ifmsnp = &((*ifmsnp)->next);
468                 *ifmsnp = ifmsn;
469         }
470         return(0);
471 }
472 static int inter_screen(struct interface_screen **ifscreenp, struct interface *interface, char *filename, int line, char *parameter, char *value)
473 {
474         struct interface_screen *ifscreen;
475         char *p, *el;
476
477         if (!value[0])
478         {
479                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID and new caller ID.\n", filename, line, parameter);
480                 return(-1);
481         }
482         /* add screen entry to list*/
483         ifscreen = (struct interface_screen *)MALLOC(sizeof(struct interface_screen));
484         memuse++;
485         ifscreen->match_type = -1; /* unchecked */
486         ifscreen->match_present = -1; /* unchecked */
487         ifscreen->result_type = -1; /* unchanged */
488         ifscreen->result_present = -1; /* unchanged */
489         /* tail port */
490         while(*ifscreenp)
491                 ifscreenp = &((*ifscreenp)->next);
492         *ifscreenp = ifscreen;
493 //      printf("interface=%s\n", interface->name);
494         /* get match */
495         p = value;
496         while(*p)
497         {
498                 el = p;
499                 p = get_seperated(p);
500                 if (!strcasecmp(el, "unknown"))
501                 {
502                         if (ifscreen->match_type != -1)
503                         {
504                                 typeerror:
505                                 SPRINT(interface_error, "Error in %s (line %d): number type already set earlier.\n", filename, line, parameter);
506                                 return(-1);
507                         }
508                         ifscreen->match_type = INFO_NTYPE_UNKNOWN;
509                 } else
510                 if (!strcasecmp(el, "subscriber"))
511                 {
512                         if (ifscreen->match_type != -1)
513                                 goto typeerror;
514                         ifscreen->match_type = INFO_NTYPE_SUBSCRIBER;
515                 } else
516                 if (!strcasecmp(el, "national"))
517                 {
518                         if (ifscreen->match_type != -1)
519                                 goto typeerror;
520                         ifscreen->match_type = INFO_NTYPE_NATIONAL;
521                 } else
522                 if (!strcasecmp(el, "international"))
523                 {
524                         if (ifscreen->match_type != -1)
525                                 goto typeerror;
526                         ifscreen->match_type = INFO_NTYPE_INTERNATIONAL;
527                 } else
528                 if (!strcasecmp(el, "allowed"))
529                 {
530                         if (ifscreen->match_present != -1)
531                         {
532                                 presenterror:
533                                 SPRINT(interface_error, "Error in %s (line %d): presentation type already set earlier.\n", filename, line);
534                                 return(-1);
535                         }
536                         ifscreen->match_present = INFO_PRESENT_ALLOWED;
537                 } else
538                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted"))
539                 {
540                         if (ifscreen->match_present != -1)
541                                 goto presenterror;
542                         ifscreen->match_present = INFO_PRESENT_RESTRICTED;
543                 } else {
544                         SCPY(ifscreen->match, el);
545                         /* check for % at the end */
546                         if (strchr(el, '%'))
547                         {
548                                 if (strchr(el, '%') != el+strlen(el)-1)
549                                 {
550                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
551                                         return(-1);
552                                 }
553                         }
554                         break;
555                 }
556         }
557         if (ifscreen->match[0] == '\0')
558         {
559                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects old caller ID.\n", filename, line, parameter);
560                 return(-1);
561         }
562         /* get result */
563         while(*p)
564         {
565                 el = p;
566                 p = get_seperated(p);
567                 if (!strcasecmp(el, "unknown"))
568                 {
569                         if (ifscreen->result_type != -1)
570                                 goto typeerror;
571                         ifscreen->result_type = INFO_NTYPE_UNKNOWN;
572                 } else
573                 if (!strcasecmp(el, "subscriber"))
574                 {
575                         if (ifscreen->result_type != -1)
576                                 goto typeerror;
577                         ifscreen->result_type = INFO_NTYPE_SUBSCRIBER;
578                 } else
579                 if (!strcasecmp(el, "national"))
580                 {
581                         if (ifscreen->result_type != -1)
582                                 goto typeerror;
583                         ifscreen->result_type = INFO_NTYPE_NATIONAL;
584                 } else
585                 if (!strcasecmp(el, "international"))
586                 {
587                         if (ifscreen->result_type != -1)
588                                 goto typeerror;
589                         ifscreen->result_type = INFO_NTYPE_INTERNATIONAL;
590                 } else
591                 if (!strcasecmp(el, "allowed"))
592                 {
593                         if (ifscreen->result_present != -1)
594                                 goto presenterror;
595                         ifscreen->result_present = INFO_PRESENT_ALLOWED;
596                 } else
597                 if (!strcasecmp(el, "restrict") || !strcasecmp(el, "restricted"))
598                 {
599                         if (ifscreen->result_present != -1)
600                                 goto presenterror;
601                         ifscreen->result_present = INFO_PRESENT_RESTRICTED;
602                 } else {
603                         SCPY(ifscreen->result, el);
604                         /* check for % at the end */
605                         if (strchr(el, '%'))
606                         {
607                                 if (strchr(el, '%') != el+strlen(el)-1)
608                                 {
609                                         SPRINT(interface_error, "Error in %s (line %d): %% joker found, but must at the end.\n", filename, line, parameter);
610                                         return(-1);
611                                 }
612                         }
613                         break;
614                 }
615         }
616         if (ifscreen->result[0] == '\0')
617         {
618                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects new caller ID.\n", filename, line, parameter);
619                 return(-1);
620         }
621         return(0);
622 }
623 static int inter_screen_in(struct interface *interface, char *filename, int line, char *parameter, char *value)
624 {
625         if (interface->ifmsn)
626         {
627                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' not allowed with 'msn' parameter.\n", filename, line, parameter);
628                 return(-1);
629         }
630
631         return(inter_screen(&interface->ifscreen_in, interface, filename, line, parameter, value));
632 }
633 static int inter_screen_out(struct interface *interface, char *filename, int line, char *parameter, char *value)
634 {
635         return(inter_screen(&interface->ifscreen_out, interface, filename, line, parameter, value));
636 }
637 static int inter_nodtmf(struct interface *interface, char *filename, int line, char *parameter, char *value)
638 {
639         struct interface_port *ifport;
640
641         /* port in chain ? */
642         if (!interface->ifport)
643         {
644                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' expects previous 'port' definition.\n", filename, line, parameter);
645                 return(-1);
646         }
647         /* goto end of chain */
648         ifport = interface->ifport;
649         while(ifport->next)
650                 ifport = ifport->next;
651         ifport->nodtmf = 1;
652         return(0);
653 }
654 #warning filter to be done
655 #if 0
656 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
657 {
658         return(0);
659 }
660 #endif
661
662
663 /*
664  * structure of parameters
665  */
666 struct interface_param interface_param[] = {
667         { "extension", &inter_extension, "",
668         "If keyword is given, calls to interface are handled as internal extensions."},
669         {"tones", &inter_tones, "yes | no",
670         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
671
672         {"earlyb", &inter_earlyb, "yes | no",
673         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
674
675         {"hunt", &inter_hunt, "linear | roundrobin",
676         "Select the algorithm for selecting port with free channel."},
677
678         {"port", &inter_port, "<number>",
679         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
680
681         {"block", &inter_block, "",
682         "If keyword is given, calls on this interface are blocked.\n"
683         "This parameter must follow a 'port' parameter."},
684
685         {"ptp", &inter_ptp, "",
686         "The given port above is opened as point-to-point.\n"
687         "This is required on NT-mode ports that are multipoint by default.\n"
688         "This parameter must follow a 'port' parameter."},
689
690         {"ptmp", &inter_ptmp, "",
691         "The given port above is opened as point-to-multipoint.\n"
692         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
693         "This parameter must follow a 'port' parameter."},
694         {"nt", &inter_nt, "",
695         "The given port above is opened in NT-mode.\n"
696 #ifdef SOCKET_MISDN
697         "This is required on interfaces that support both NT-mode and TE-mode.\n"
698 #else
699         "This parameter is only required for socket based mISDN driver.\n"
700 #endif
701         "This parameter must follow a 'port' parameter."},
702
703         {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
704         "Channel selection list for all outgoing calls to the interface.\n"
705         "A free channels is searched in order of appearance.\n"
706         "This parameter must follow a 'port' parameter.\n"
707         " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
708         " <number>[,...] - List of channels to search.\n"
709         " free - Select any free channel\n"
710         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
711         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
712
713         {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
714         "Channel selection list for all incomming calls from the interface.\n"
715         "A free channels is accepted if in the list.\n"
716         "If any channel was requested, the first free channel found is selected.\n"
717         "This parameter must follow a 'port' parameter.\n"
718         " <number>[,...] - List of channels to accept.\n"
719         " free - Accept any free channel"},
720
721         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
722         "Incomming caller ID is checked against given MSN numbers.\n"
723         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
724
725         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
726         "Adds an entry for incomming calls to the caller ID screen list.\n"
727         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
728         "If '%' is given after old caller ID, it matches even if caller ID has\n"
729         "additional digits.\n"
730         "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
731         "are added.\n"
732         "Options can be:\n"
733         " unknown | subsciber | national | international - Change caller ID type.\n"
734         " present | restrict - Change presentation of caller ID."},
735                 
736         {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
737         "Adds an entry for outgoing calls to the caller ID screen list.\n"
738         "See 'screen-in' for help."},
739
740         {"nodtmf", &inter_nodtmf, "",
741         "Disables DTMF detection for this interface.\n"
742         "This parameter must follow a 'port' parameter."},
743
744 #if 0
745         {"layer2keep", &inter_layer2keep, "yes | no",
746         "By default, layer 2 is establised and kept up on PTP interfaces.\n"
747         ".\n"
748         "This parameter must follow a 'port' parameter."},
749 #endif
750
751 #if 0
752 #warning todo: filter, also in the PmISDN object
753         {"filter", &inter_filter, "<filter> [parameters]",
754         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
755         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
756         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
757 #endif
758
759         {NULL, NULL, NULL, NULL}
760 };
761
762 /* read interfaces
763  *
764  * read settings from interface.conf
765  */
766 char interface_error[256];
767 struct interface *read_interfaces(void)
768 {
769         FILE                    *fp = NULL;
770         char                    filename[128];
771         char                    *p;
772         unsigned int            line, i;
773         char                    buffer[256];
774         struct interface        *interface = NULL, /* in case no interface */
775                                 **interfacep = &interface_newlist;
776         char                    parameter[128];
777         char                    value[256];
778         int                     expecting = 1; /* expecting new interface */
779         struct interface_param  *ifparam;
780
781         if (interface_newlist != NULL)
782                 FATAL("list is not empty.\n");
783         interface_error[0] = '\0';
784         SPRINT(filename, "%s/interface.conf", INSTALL_DATA);
785
786         if (!(fp = fopen(filename,"r")))
787         {
788                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
789                 goto error;
790         }
791
792         line=0;
793         while((fgets(buffer,sizeof(buffer),fp)))
794         {
795                 buffer[sizeof(buffer)-1]=0;
796                 if (buffer[0]) buffer[strlen(buffer)-1]=0;
797                 p=buffer;
798                 line++;
799
800                 while(*p <= 32) /* skip spaces */
801                 {
802                         if (*p == 0)
803                                 break;
804                         p++;
805                 }
806                 if (*p==0 || *p=='#') /* ignore comments and empty line */
807                         continue;
808
809                 parameter[0]=0;
810                 value[0]=0;
811                 i=0; /* read parameter */
812                 while(*p > 32)
813                 {
814                         if (i+1 >= sizeof(parameter))
815                         {
816                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
817                                 goto error;
818                         }
819                         parameter[i+1] = '\0';
820                         parameter[i++] = *p++;
821                 }
822
823                 while(*p <= 32) /* skip spaces */
824                 {
825                         if (*p == 0)
826                                 break;
827                         p++;
828                 }
829
830                 if (*p!=0 && *p!='#') /* missing name */
831                 {
832                         i=0; /* read until end */
833                         while(*p!=0 && *p!='#')
834                         {
835                                 if (i+1 >= sizeof(value))
836                                 {
837                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
838                                         goto error;
839                                 }
840                                 value[i+1] = '\0';
841                                 value[i++] = *p++;
842                         }
843
844                         /* remove trailing spaces from value */
845                         while(i)
846                         {
847                                 if (value[i-1]==0 || value[i-1]>32)
848                                         break;
849                                 value[i-1] = '\0';
850                                 i--;
851                         }
852                 }
853
854                 /* check for interface name as first statement */
855                 if (expecting && parameter[0]!='[')
856                 {
857                         SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
858                         goto error;
859                 }
860                 expecting = 0;
861
862                 /* check for new interface */
863                 if (parameter[0] == '[')
864                 {
865                         if (parameter[strlen(parameter)-1] != ']')
866                         {
867                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
868                                 goto error;
869                         }
870                         parameter[strlen(parameter)-1] = '\0';
871
872                         /* check if interface name already exists */
873                         interface = interface_newlist;
874                         while(interface)
875                         {
876                                 if (!strcasecmp(interface->name, parameter+1))
877                                 {
878                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
879                                         goto error;
880                                 }
881                                 interface = interface->next;
882                         }
883
884                         /* append interface to new list */
885                         interface = (struct interface *)MALLOC(sizeof(struct interface));
886                         memuse++;
887
888                         /* name interface */
889                         SCPY(interface->name, parameter+1);
890
891                         /* attach */
892                         *interfacep = interface;
893                         interfacep = &interface->next;
894
895                         continue;
896                 }
897
898                 ifparam = interface_param;
899                 while(ifparam->name)
900                 {
901                         if (!strcasecmp(parameter, ifparam->name))
902                         {
903                                 if (ifparam->func(interface, filename, line, parameter, value))
904                                         goto error;
905                                 break;
906                         }
907                         ifparam++;
908                 }
909                 if (ifparam->name)
910                         continue;
911
912                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
913                 goto error;
914         }
915
916         if (fp) fclose(fp);
917         return(interface_newlist);
918 error:
919         PERROR_RUNTIME("%s", interface_error);
920         if (fp) fclose(fp);
921         free_interfaces(interface_newlist);
922         interface_newlist = NULL;
923         return(NULL);
924 }
925
926
927 /*
928  * freeing chain of interfaces
929  */
930 void free_interfaces(struct interface *interface)
931 {
932         void *temp;
933         struct interface_port *ifport;
934         struct select_channel *selchannel;
935         struct interface_msn *ifmsn;
936         struct interface_screen *ifscreen;
937         struct interface_filter *iffilter;
938
939         while(interface)
940         {
941                 ifport = interface->ifport;
942                 while(ifport)
943                 {
944                         selchannel = ifport->in_channel;
945                         while(selchannel)
946                         {
947                                 temp = selchannel;
948                                 selchannel = selchannel->next;
949                                 FREE(temp, sizeof(struct select_channel));
950                                 memuse--;
951                         }
952                         selchannel = ifport->out_channel;
953                         while(selchannel)
954                         {
955                                 temp = selchannel;
956                                 selchannel = selchannel->next;
957                                 FREE(temp, sizeof(struct select_channel));
958                                 memuse--;
959                         }
960                         temp = ifport;
961                         ifport = ifport->next;
962                         FREE(temp, sizeof(struct interface_port));
963                         memuse--;
964                 }
965                 ifmsn = interface->ifmsn;
966                 while(ifmsn)
967                 {
968                         temp = ifmsn;
969                         ifmsn = ifmsn->next;
970                         FREE(temp, sizeof(struct interface_msn));
971                         memuse--;
972                 }
973                 ifscreen = interface->ifscreen_in;
974                 while(ifscreen)
975                 {
976                         temp = ifscreen;
977                         ifscreen = ifscreen->next;
978                         FREE(temp, sizeof(struct interface_screen));
979                         memuse--;
980                 }
981                 ifscreen = interface->ifscreen_out;
982                 while(ifscreen)
983                 {
984                         temp = ifscreen;
985                         ifscreen = ifscreen->next;
986                         FREE(temp, sizeof(struct interface_screen));
987                         memuse--;
988                 }
989                 iffilter = interface->iffilter;
990                 while(iffilter)
991                 {
992                         temp = iffilter;
993                         iffilter = iffilter->next;
994                         FREE(temp, sizeof(struct interface_filter));
995                         memuse--;
996                 }
997                 temp = interface;
998                 interface = interface->next;
999                 FREE(temp, sizeof(struct interface));
1000                 memuse--;
1001         }
1002 }
1003
1004 /*
1005  * defaults of ports if not specified by config
1006  */
1007 static void set_defaults(struct interface_port *ifport)
1008 {
1009         /* default channel selection list */
1010         if (!ifport->out_channel)
1011                 default_out_channel(ifport);
1012         if (!ifport->in_channel)
1013                 default_in_channel(ifport);
1014         /* default is_tones */
1015         if (ifport->interface->is_tones)
1016                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1017         else
1018                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
1019         /* default is_earlyb */
1020         if (ifport->interface->is_earlyb)
1021                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1022         else
1023                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
1024         /* set locally flag */
1025         if (ifport->interface->extension)
1026                 ifport->mISDNport->locally = 1;
1027         else
1028                 ifport->mISDNport->locally = 0;
1029 }
1030
1031
1032 /*
1033  * all links between mISDNport and interface are made
1034  * unused mISDNports are closed, new mISDNports are opened
1035  * also set default select_channel lists
1036  */
1037 void relink_interfaces(void)
1038 {
1039         struct mISDNport *mISDNport;
1040         struct interface *interface;
1041         struct interface_port *ifport;
1042
1043         /* unlink all mISDNports */
1044         mISDNport = mISDNport_first;
1045         while(mISDNport)
1046         {
1047                 mISDNport->ifport = NULL;
1048                 mISDNport = mISDNport->next;
1049         }
1050
1051         /* relink existing mISDNports */
1052         interface = interface_newlist;
1053         while(interface)
1054         {
1055                 ifport = interface->ifport;
1056                 while(ifport)
1057                 {
1058                         mISDNport = mISDNport_first;
1059                         while(mISDNport)
1060                         {
1061                                 if (mISDNport->portnum == ifport->portnum)
1062                                 {
1063                                         ifport->mISDNport = mISDNport;
1064                                         mISDNport->ifport = ifport;
1065                                         set_defaults(ifport);
1066                                 }
1067                                 mISDNport = mISDNport->next;
1068                         }
1069                         ifport = ifport->next;
1070                 }
1071                 interface = interface->next;
1072         }
1073
1074         /* close unused mISDNports */
1075         closeagain:
1076         mISDNport = mISDNport_first;
1077         while(mISDNport)
1078         {
1079                 if (mISDNport->ifport == NULL)
1080                 {
1081                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1082                         /* remove all port objects and destroy port */
1083                         mISDNport_close(mISDNport);
1084                         goto closeagain;
1085                 }
1086                 mISDNport = mISDNport->next;
1087         }
1088
1089         /* open and link new mISDNports */
1090         interface = interface_newlist;
1091         while(interface)
1092         {
1093                 ifport = interface->ifport;
1094                 while(ifport)
1095                 {
1096                         if (!ifport->mISDNport)
1097                         {
1098                                 load_port(ifport);
1099                         }
1100                         ifport = ifport->next;
1101                 }
1102                 interface = interface->next;
1103         }
1104
1105 }
1106
1107
1108 /*
1109  * load port
1110  */
1111 void load_port(struct interface_port *ifport)
1112 {
1113         struct mISDNport *mISDNport;
1114
1115         /* open new port */
1116         mISDNport = mISDNport_open(ifport->portnum, ifport->ptp, ifport->ptmp, ifport->nt, ifport->interface);
1117         if (mISDNport)
1118         {
1119                 /* link port */
1120                 ifport->mISDNport = mISDNport;
1121                 mISDNport->ifport = ifport;
1122                 set_defaults(ifport);
1123         } else
1124         {
1125                 ifport->block = 2; /* not available */
1126         }
1127 }
1128
1129 /*
1130  * give summary of interface syntax
1131  */
1132 void doc_interface(void)
1133 {
1134         struct interface_param *ifparam;
1135         
1136         printf("Syntax overview\n");
1137         printf("---------------\n\n");
1138
1139         printf("[<name>]\n");
1140         ifparam = interface_param;
1141         while(ifparam->name)
1142         {
1143                 printf("%s %s\n", ifparam->name, ifparam->usage);
1144                 ifparam++;
1145         }
1146
1147         ifparam = interface_param;
1148         while(ifparam->name)
1149         {
1150                 printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1151                 printf("%s\n", ifparam->help);
1152                 ifparam++;
1153         }
1154 }
1155
1156
1157 /* screen caller id
1158  * out==0: incomming caller id, out==1: outgoing caller id
1159  */
1160 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1161 {
1162         char                    *msn1;
1163         struct interface_msn    *ifmsn;
1164         struct interface_screen *ifscreen;
1165         char suffix[64];
1166
1167         /* screen incoming caller id */
1168         if (!out)
1169         {
1170                 /* check for MSN numbers, use first MSN if no match */
1171                 msn1 = NULL;
1172                 ifmsn = interface->ifmsn;
1173                 while(ifmsn)
1174                 {
1175                         if (!msn1)
1176                                 msn1 = ifmsn->msn;
1177                         if (!strcmp(ifmsn->msn, id))
1178                         {
1179                                 break;
1180                         }
1181                         ifmsn = ifmsn->next;
1182                 }
1183                 if (ifmsn)
1184                 {
1185                         start_trace(0, interface, numberrize_callerinfo(id, *type), NULL, DIRECTION_IN, 0, 0, "SCREEN (fount in MSN list)");
1186                         add_trace("msn", NULL, "%s", id);
1187                         end_trace();
1188                 }
1189                 if (!ifmsn && msn1) // not in list, first msn given
1190                 {
1191                         start_trace(0, interface, numberrize_callerinfo(id, *type), NULL, DIRECTION_IN, 0, 0, "SCREEN (not fount in MSN list)");
1192                         add_trace("msn", "given", "%s", id);
1193                         add_trace("msn", "used", "%s", msn1);
1194                         end_trace();
1195                         UNCPY(id, msn1, idsize);
1196                         id[idsize-1] = '\0';
1197                 }
1198         }
1199
1200         /* check screen list */
1201         if (out)
1202                 ifscreen = interface->ifscreen_out;
1203         else
1204                 ifscreen = interface->ifscreen_in;
1205         while (ifscreen)
1206         {
1207                 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1208                 if (ifscreen->match_present==-1 || ifscreen->match_present==*present)
1209                 {
1210                         if (strchr(ifscreen->match,'%'))
1211                         {
1212                                 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1213                                         break;
1214                         } else
1215                         {
1216                                 if (!strcmp(ifscreen->match, id))
1217                                         break;
1218                         }
1219                 }
1220                 ifscreen = ifscreen->next;
1221         }
1222         if (ifscreen) // match
1223         {
1224                 start_trace(0, interface, numberrize_callerinfo(id, *type), NULL, out?DIRECTION_OUT:DIRECTION_IN, 0, 0, "SCREEN (fount in screen list)");
1225                 switch(*type)
1226                 {
1227                         case INFO_NTYPE_UNKNOWN:
1228                         add_trace("given", "type", "unknown");
1229                         break;
1230                         case INFO_NTYPE_SUBSCRIBER:
1231                         add_trace("given", "type", "subscriber");
1232                         break;
1233                         case INFO_NTYPE_NATIONAL:
1234                         add_trace("given", "type", "national");
1235                         break;
1236                         case INFO_NTYPE_INTERNATIONAL:
1237                         add_trace("given", "type", "international");
1238                         break;
1239                 }
1240                 switch(*present)
1241                 {
1242                         case INFO_PRESENT_ALLOWED:
1243                         add_trace("given", "present", "allowed");
1244                         break;
1245                         case INFO_PRESENT_RESTRICTED:
1246                         add_trace("given", "present", "restricted");
1247                         break;
1248                         case INFO_PRESENT_NOTAVAIL:
1249                         add_trace("given", "present", "not available");
1250                         break;
1251                 }
1252                 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1253                 if (ifscreen->result_type != -1)
1254                 {
1255                         *type = ifscreen->result_type;
1256                         switch(*type)
1257                         {
1258                                 case INFO_NTYPE_UNKNOWN:
1259                                 add_trace("used", "type", "unknown");
1260                                 break;
1261                                 case INFO_NTYPE_SUBSCRIBER:
1262                                 add_trace("used", "type", "subscriber");
1263                                 break;
1264                                 case INFO_NTYPE_NATIONAL:
1265                                 add_trace("used", "type", "national");
1266                                 break;
1267                                 case INFO_NTYPE_INTERNATIONAL:
1268                                 add_trace("used", "type", "international");
1269                                 break;
1270                         }
1271                 }
1272                 if (ifscreen->result_present != -1)
1273                 {
1274                         *present = ifscreen->result_present;
1275                         switch(*present)
1276                         {
1277                                 case INFO_PRESENT_ALLOWED:
1278                                 add_trace("used", "present", "allowed");
1279                                 break;
1280                                 case INFO_PRESENT_RESTRICTED:
1281                                 add_trace("used", "present", "restricted");
1282                                 break;
1283                                 case INFO_PRESENT_NOTAVAIL:
1284                                 add_trace("used", "present", "not available");
1285                                 break;
1286                         }
1287                 }
1288                 if (strchr(ifscreen->match,'%'))
1289                 {
1290                         SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1291                         UNCPY(id, ifscreen->result, idsize);
1292                         id[idsize-1] = '\0';
1293                         if (strchr(id,'%'))
1294                         {
1295                                 *strchr(id,'%') = '\0';
1296                                 UNCAT(id, suffix, idsize);
1297                                 id[idsize-1] = '\0';
1298                         }
1299                 } else
1300                 {
1301                         UNCPY(id, ifscreen->result, idsize);
1302                         id[idsize-1] = '\0';
1303                 }
1304                 add_trace("used", "id", "%s", id[0]?id:"<empty>");
1305                 end_trace();
1306         }
1307 }
1308