added filter options (gain, pipeline, blowfish) to interface configuration.
[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 static int inter_filter(struct interface *interface, char *filename, int line, char *parameter, char *value)
655 {
656         char *p, *q;
657
658         /* seperate parameter from filter */
659         p = value;
660         while(*p > 32)
661                 p++;
662         if (*p)
663         {
664                 *p++ = 0;
665                 while(*p > 0 && *p <= 32)
666                         p++;
667         }
668
669         if (!strcasecmp(value, "gain"))
670         {
671                 q = p;
672                 while(*q > 32)
673                         q++;
674                 if (*q)
675                 {
676                         *q++ = 0;
677                         while(*q > 0 && *q <= 32)
678                                 q++;
679                 }
680                 if (*p == 0 || *q == 0)
681                 {
682                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects two gain values.\n", filename, line, parameter, value);
683                         return(-1);
684                 }
685                 if (atoi(p)<-8 || atoi(p)>8 || atoi(q)<-8 || atoi(q)>8)
686                 {
687                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' gain values not in range. (-8...8)\n", filename, line, parameter, value);
688                         return(-1);
689                 }
690                 interface->gain_tx = atoi(p);
691                 interface->gain_rx = atoi(q);
692         } else
693         if (!strcasecmp(value, "pipeline"))
694         {
695                 if (*p == 0)
696                 {
697                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects pipeline string.\n", filename, line, parameter, value);
698                         return(-1);
699                 }
700                 SCPY(interface->pipeline, p);
701         } else
702         if (!strcasecmp(value, "blowfish"))
703         {
704                 unsigned char key[56];
705                 int l;
706                 
707                 if (!!strncmp(p, "0x", 2))
708                 {
709                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' expects blowfish key starting with '0x'.\n", filename, line, parameter, value);
710                         return(-1);
711                 }
712                 p += 2;
713                 l = 0; 
714                 while(*p)
715                 {
716                         if (l == 56)
717                         {
718                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key too long.\n", filename, line, parameter, value);
719                                 return(-1);
720                         }
721                         if (*p >= '0' && *p <= '9')
722                                 key[l] = (*p-'0')<<4;
723                         else if (*p >= 'a' && *p <= 'f')
724                                 key[l] = (*p-'a'+10)<<4;
725                         else if (*p >= 'A' && *p <= 'F')
726                                 key[l] = (*p-'A'+10)<<4;
727                         else
728                         {
729                                 digout:
730                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key has digits out of range. (0...9, a...f)\n", filename, line, parameter, value);
731                                 return(-1);
732                         }
733                         p++;
734                         if (*p == 0)
735                         {
736                                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key must end on an 8 bit boundary (two character boundary).\n", filename, line, parameter, value);
737                                 return(-1);
738                         }
739                         if (*p >= '0' && *p <= '9')
740                                 key[l] = (*p-'0')<<4;
741                         else if (*p >= 'a' && *p <= 'f')
742                                 key[l] = (*p-'a'+10)<<4;
743                         else if (*p >= 'A' && *p <= 'F')
744                                 key[l] = (*p-'A'+10)<<4;
745                         else
746                                 goto digout;
747                         p++;
748                         l++;
749                 }
750                 if (l < 4)
751                 {
752                         SPRINT(interface_error, "Error in %s (line %d): parameter '%s %s' key must be at least 4 bytes (8 characters).\n", filename, line, parameter, value);
753                         return(-1);
754                 }
755                 memcpy(interface->bf_key, key, l);
756                 interface->bf_len = l;
757         } else
758         {
759                 SPRINT(interface_error, "Error in %s (line %d): parameter '%s' has unknown filter '%s'.\n", filename, line, parameter, value);
760                 return(-1);
761         }
762         return(0);
763 }
764
765
766 /*
767  * structure of parameters
768  */
769 struct interface_param interface_param[] = {
770         { "extension", &inter_extension, "",
771         "If keyword is given, calls to interface are handled as internal extensions."},
772         {"tones", &inter_tones, "yes | no",
773         "Interface generates tones during call setup and release, or not.\nBy default only NT-mode ports generate tones."},
774
775         {"earlyb", &inter_earlyb, "yes | no",
776         "Interface receives and bridges tones during call setup and release, or not.\nBy default only TE-mode ports receive tones."},
777
778         {"hunt", &inter_hunt, "linear | roundrobin",
779         "Select the algorithm for selecting port with free channel."},
780
781         {"port", &inter_port, "<number>",
782         "Give exactly one port for this interface.\nTo give multiple ports, add more lines with port parameters."},
783
784         {"block", &inter_block, "",
785         "If keyword is given, calls on this interface are blocked.\n"
786         "This parameter must follow a 'port' parameter."},
787
788         {"ptp", &inter_ptp, "",
789         "The given port above is opened as point-to-point.\n"
790         "This is required on NT-mode ports that are multipoint by default.\n"
791         "This parameter must follow a 'port' parameter."},
792
793         {"ptmp", &inter_ptmp, "",
794         "The given port above is opened as point-to-multipoint.\n"
795         "This is required on PRI NT-mode ports that are point-to-point by default.\n"
796         "This parameter must follow a 'port' parameter."},
797         {"nt", &inter_nt, "",
798         "The given port above is opened in NT-mode.\n"
799 #ifdef SOCKET_MISDN
800         "This is required on interfaces that support both NT-mode and TE-mode.\n"
801 #else
802         "This parameter is only required for socket based mISDN driver.\n"
803 #endif
804         "This parameter must follow a 'port' parameter."},
805
806         {"channel-out", &inter_channel_out, "[force,][<number>][,...][,free][,any][,no]",
807         "Channel selection list for all outgoing calls to the interface.\n"
808         "A free channels is searched in order of appearance.\n"
809         "This parameter must follow a 'port' parameter.\n"
810         " force - Forces the selected port with no acceptable alternative (see DSS1).\n"
811         " <number>[,...] - List of channels to search.\n"
812         " free - Select any free channel\n"
813         " any - On outgoing calls, signal 'any channel acceptable'. (see DSS1)\n"
814         " no - Signal 'no channel available' aka 'call waiting'. (see DSS1)"},
815
816         {"channel-in", &inter_channel_in, "[<number>][,...][,free]",
817         "Channel selection list for all incomming calls from the interface.\n"
818         "A free channels is accepted if in the list.\n"
819         "If any channel was requested, the first free channel found is selected.\n"
820         "This parameter must follow a 'port' parameter.\n"
821         " <number>[,...] - List of channels to accept.\n"
822         " free - Accept any free channel"},
823
824         {"msn", &inter_msn, "<default MSN>,[<additional MSN>[,...]]",
825         "Incomming caller ID is checked against given MSN numbers.\n"
826         "If the caller ID is not found in this list, it is overwritten by the first MSN"},
827
828         {"screen-in", &inter_screen_in, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
829         "Adds an entry for incomming calls to the caller ID screen list.\n"
830         "If the given 'old caller ID' matches, it is replaced by the 'new caller ID'\n"
831         "If '%' is given after old caller ID, it matches even if caller ID has\n"
832         "additional digits.\n"
833         "If '%' is given after mew caller ID, additinal digits of the 'old caller ID'\n"
834         "are added.\n"
835         "Options can be:\n"
836         " unknown | subsciber | national | international - Change caller ID type.\n"
837         " present | restrict - Change presentation of caller ID."},
838                 
839         {"screen-out", &inter_screen_out, "[options] <old caller ID>[%] [options] <new caller ID>[%]",
840         "Adds an entry for outgoing calls to the caller ID screen list.\n"
841         "See 'screen-in' for help."},
842
843         {"nodtmf", &inter_nodtmf, "",
844         "Disables DTMF detection for this interface.\n"
845         "This parameter must follow a 'port' parameter."},
846
847 #if 0
848         {"layer2keep", &inter_layer2keep, "yes | no",
849         "By default, layer 2 is establised and kept up on PTP interfaces.\n"
850         ".\n"
851         "This parameter must follow a 'port' parameter."},
852 #endif
853
854         {"filter", &inter_filter, "<filter> <parameters>",
855         "Adds/appends a filter. Filters are ordered in transmit direction.\n"
856         "gain <tx-volume> <rx-volume> - Changes volume (-8 .. 8)\n"
857         "pipeline <string> - Sets echo cancelation pipeline.\n"
858         "blowfish <key> - Adds encryption. Key must be 4-56 bytes (8-112 hex characters."},
859
860         {NULL, NULL, NULL, NULL}
861 };
862
863 /* read interfaces
864  *
865  * read settings from interface.conf
866  */
867 char interface_error[256];
868 struct interface *read_interfaces(void)
869 {
870         FILE                    *fp = NULL;
871         char                    filename[128];
872         char                    *p;
873         unsigned int            line, i;
874         char                    buffer[256];
875         struct interface        *interface = NULL, /* in case no interface */
876                                 **interfacep = &interface_newlist;
877         char                    parameter[128];
878         char                    value[256];
879         int                     expecting = 1; /* expecting new interface */
880         struct interface_param  *ifparam;
881
882         if (interface_newlist != NULL)
883                 FATAL("list is not empty.\n");
884         interface_error[0] = '\0';
885         SPRINT(filename, "%s/interface.conf", INSTALL_DATA);
886
887         if (!(fp = fopen(filename,"r")))
888         {
889                 SPRINT(interface_error, "Cannot open '%s'\n", filename);
890                 goto error;
891         }
892
893         line=0;
894         while((fgets(buffer,sizeof(buffer),fp)))
895         {
896                 buffer[sizeof(buffer)-1]=0;
897                 if (buffer[0]) buffer[strlen(buffer)-1]=0;
898                 p=buffer;
899                 line++;
900
901                 while(*p <= 32) /* skip spaces */
902                 {
903                         if (*p == 0)
904                                 break;
905                         p++;
906                 }
907                 if (*p==0 || *p=='#') /* ignore comments and empty line */
908                         continue;
909
910                 parameter[0]=0;
911                 value[0]=0;
912                 i=0; /* read parameter */
913                 while(*p > 32)
914                 {
915                         if (i+1 >= sizeof(parameter))
916                         {
917                                 SPRINT(interface_error, "Error in %s (line %d): parameter name too long.\n",filename,line);
918                                 goto error;
919                         }
920                         parameter[i+1] = '\0';
921                         parameter[i++] = *p++;
922                 }
923
924                 while(*p <= 32) /* skip spaces */
925                 {
926                         if (*p == 0)
927                                 break;
928                         p++;
929                 }
930
931                 if (*p!=0 && *p!='#') /* missing name */
932                 {
933                         i=0; /* read until end */
934                         while(*p!=0 && *p!='#')
935                         {
936                                 if (i+1 >= sizeof(value))
937                                 {
938                                         SPRINT(interface_error, "Error in %s (line %d): value too long.\n", filename, line);
939                                         goto error;
940                                 }
941                                 value[i+1] = '\0';
942                                 value[i++] = *p++;
943                         }
944
945                         /* remove trailing spaces from value */
946                         while(i)
947                         {
948                                 if (value[i-1]==0 || value[i-1]>32)
949                                         break;
950                                 value[i-1] = '\0';
951                                 i--;
952                         }
953                 }
954
955                 /* check for interface name as first statement */
956                 if (expecting && parameter[0]!='[')
957                 {
958                         SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
959                         goto error;
960                 }
961                 expecting = 0;
962
963                 /* check for new interface */
964                 if (parameter[0] == '[')
965                 {
966                         if (parameter[strlen(parameter)-1] != ']')
967                         {
968                                 SPRINT(interface_error, "Error in %s (line %d): expecting interface name inside [ and ], but got: '%s'.\n", filename, line, parameter);
969                                 goto error;
970                         }
971                         parameter[strlen(parameter)-1] = '\0';
972
973                         /* check if interface name already exists */
974                         interface = interface_newlist;
975                         while(interface)
976                         {
977                                 if (!strcasecmp(interface->name, parameter+1))
978                                 {
979                                         SPRINT(interface_error, "Error in %s (line %d): interface name '%s' already defined above.\n", filename, line, parameter+1);
980                                         goto error;
981                                 }
982                                 interface = interface->next;
983                         }
984
985                         /* append interface to new list */
986                         interface = (struct interface *)MALLOC(sizeof(struct interface));
987                         memuse++;
988
989                         /* name interface */
990                         SCPY(interface->name, parameter+1);
991
992                         /* attach */
993                         *interfacep = interface;
994                         interfacep = &interface->next;
995
996                         continue;
997                 }
998
999                 ifparam = interface_param;
1000                 while(ifparam->name)
1001                 {
1002                         if (!strcasecmp(parameter, ifparam->name))
1003                         {
1004                                 if (ifparam->func(interface, filename, line, parameter, value))
1005                                         goto error;
1006                                 break;
1007                         }
1008                         ifparam++;
1009                 }
1010                 if (ifparam->name)
1011                         continue;
1012
1013                 SPRINT(interface_error, "Error in %s (line %d): unknown parameter: '%s'.\n", filename, line, parameter);
1014                 goto error;
1015         }
1016
1017         if (fp) fclose(fp);
1018         return(interface_newlist);
1019 error:
1020         PERROR_RUNTIME("%s", interface_error);
1021         if (fp) fclose(fp);
1022         free_interfaces(interface_newlist);
1023         interface_newlist = NULL;
1024         return(NULL);
1025 }
1026
1027
1028 /*
1029  * freeing chain of interfaces
1030  */
1031 void free_interfaces(struct interface *interface)
1032 {
1033         void *temp;
1034         struct interface_port *ifport;
1035         struct select_channel *selchannel;
1036         struct interface_msn *ifmsn;
1037         struct interface_screen *ifscreen;
1038
1039         while(interface)
1040         {
1041                 ifport = interface->ifport;
1042                 while(ifport)
1043                 {
1044                         selchannel = ifport->in_channel;
1045                         while(selchannel)
1046                         {
1047                                 temp = selchannel;
1048                                 selchannel = selchannel->next;
1049                                 FREE(temp, sizeof(struct select_channel));
1050                                 memuse--;
1051                         }
1052                         selchannel = ifport->out_channel;
1053                         while(selchannel)
1054                         {
1055                                 temp = selchannel;
1056                                 selchannel = selchannel->next;
1057                                 FREE(temp, sizeof(struct select_channel));
1058                                 memuse--;
1059                         }
1060                         temp = ifport;
1061                         ifport = ifport->next;
1062                         FREE(temp, sizeof(struct interface_port));
1063                         memuse--;
1064                 }
1065                 ifmsn = interface->ifmsn;
1066                 while(ifmsn)
1067                 {
1068                         temp = ifmsn;
1069                         ifmsn = ifmsn->next;
1070                         FREE(temp, sizeof(struct interface_msn));
1071                         memuse--;
1072                 }
1073                 ifscreen = interface->ifscreen_in;
1074                 while(ifscreen)
1075                 {
1076                         temp = ifscreen;
1077                         ifscreen = ifscreen->next;
1078                         FREE(temp, sizeof(struct interface_screen));
1079                         memuse--;
1080                 }
1081                 ifscreen = interface->ifscreen_out;
1082                 while(ifscreen)
1083                 {
1084                         temp = ifscreen;
1085                         ifscreen = ifscreen->next;
1086                         FREE(temp, sizeof(struct interface_screen));
1087                         memuse--;
1088                 }
1089                 temp = interface;
1090                 interface = interface->next;
1091                 FREE(temp, sizeof(struct interface));
1092                 memuse--;
1093         }
1094 }
1095
1096 /*
1097  * defaults of ports if not specified by config
1098  */
1099 static void set_defaults(struct interface_port *ifport)
1100 {
1101         /* default channel selection list */
1102         if (!ifport->out_channel)
1103                 default_out_channel(ifport);
1104         if (!ifport->in_channel)
1105                 default_in_channel(ifport);
1106         /* default is_tones */
1107         if (ifport->interface->is_tones)
1108                 ifport->mISDNport->tones = (ifport->interface->is_tones==IS_YES);
1109         else
1110                 ifport->mISDNport->tones = (ifport->mISDNport->ntmode)?1:0;
1111         /* default is_earlyb */
1112         if (ifport->interface->is_earlyb)
1113                 ifport->mISDNport->earlyb = (ifport->interface->is_earlyb==IS_YES);
1114         else
1115                 ifport->mISDNport->earlyb = (ifport->mISDNport->ntmode)?0:1;
1116         /* set locally flag */
1117         if (ifport->interface->extension)
1118                 ifport->mISDNport->locally = 1;
1119         else
1120                 ifport->mISDNport->locally = 0;
1121 }
1122
1123
1124 /*
1125  * all links between mISDNport and interface are made
1126  * unused mISDNports are closed, new mISDNports are opened
1127  * also set default select_channel lists
1128  */
1129 void relink_interfaces(void)
1130 {
1131         struct mISDNport *mISDNport;
1132         struct interface *interface;
1133         struct interface_port *ifport;
1134
1135         /* unlink all mISDNports */
1136         mISDNport = mISDNport_first;
1137         while(mISDNport)
1138         {
1139                 mISDNport->ifport = NULL;
1140                 mISDNport = mISDNport->next;
1141         }
1142
1143         /* relink existing mISDNports */
1144         interface = interface_newlist;
1145         while(interface)
1146         {
1147                 ifport = interface->ifport;
1148                 while(ifport)
1149                 {
1150                         mISDNport = mISDNport_first;
1151                         while(mISDNport)
1152                         {
1153                                 if (mISDNport->portnum == ifport->portnum)
1154                                 {
1155                                         ifport->mISDNport = mISDNport;
1156                                         mISDNport->ifport = ifport;
1157                                         set_defaults(ifport);
1158                                 }
1159                                 mISDNport = mISDNport->next;
1160                         }
1161                         ifport = ifport->next;
1162                 }
1163                 interface = interface->next;
1164         }
1165
1166         /* close unused mISDNports */
1167         closeagain:
1168         mISDNport = mISDNport_first;
1169         while(mISDNport)
1170         {
1171                 if (mISDNport->ifport == NULL)
1172                 {
1173                         PDEBUG(DEBUG_ISDN, "Port %d is not used anymore and will be closed\n", mISDNport->portnum);
1174                         /* remove all port objects and destroy port */
1175                         mISDNport_close(mISDNport);
1176                         goto closeagain;
1177                 }
1178                 mISDNport = mISDNport->next;
1179         }
1180
1181         /* open and link new mISDNports */
1182         interface = interface_newlist;
1183         while(interface)
1184         {
1185                 ifport = interface->ifport;
1186                 while(ifport)
1187                 {
1188                         if (!ifport->mISDNport)
1189                         {
1190                                 load_port(ifport);
1191                         }
1192                         ifport = ifport->next;
1193                 }
1194                 interface = interface->next;
1195         }
1196
1197 }
1198
1199
1200 /*
1201  * load port
1202  */
1203 void load_port(struct interface_port *ifport)
1204 {
1205         struct mISDNport *mISDNport;
1206
1207         /* open new port */
1208         mISDNport = mISDNport_open(ifport->portnum, ifport->ptp, ifport->ptmp, ifport->nt, ifport->interface);
1209         if (mISDNport)
1210         {
1211                 /* link port */
1212                 ifport->mISDNport = mISDNport;
1213                 mISDNport->ifport = ifport;
1214                 set_defaults(ifport);
1215         } else
1216         {
1217                 ifport->block = 2; /* not available */
1218         }
1219 }
1220
1221 /*
1222  * give summary of interface syntax
1223  */
1224 void doc_interface(void)
1225 {
1226         struct interface_param *ifparam;
1227         
1228         printf("Syntax overview\n");
1229         printf("---------------\n\n");
1230
1231         printf("[<name>]\n");
1232         ifparam = interface_param;
1233         while(ifparam->name)
1234         {
1235                 printf("%s %s\n", ifparam->name, ifparam->usage);
1236                 ifparam++;
1237         }
1238
1239         ifparam = interface_param;
1240         while(ifparam->name)
1241         {
1242                 printf("\nParameter: %s %s\n", ifparam->name, ifparam->usage);
1243                 printf("%s\n", ifparam->help);
1244                 ifparam++;
1245         }
1246 }
1247
1248
1249 /* screen caller id
1250  * out==0: incomming caller id, out==1: outgoing caller id
1251  */
1252 void do_screen(int out, char *id, int idsize, int *type, int *present, struct interface *interface)
1253 {
1254         char                    *msn1;
1255         struct interface_msn    *ifmsn;
1256         struct interface_screen *ifscreen;
1257         char suffix[64];
1258
1259         /* screen incoming caller id */
1260         if (!out)
1261         {
1262                 /* check for MSN numbers, use first MSN if no match */
1263                 msn1 = NULL;
1264                 ifmsn = interface->ifmsn;
1265                 while(ifmsn)
1266                 {
1267                         if (!msn1)
1268                                 msn1 = ifmsn->msn;
1269                         if (!strcmp(ifmsn->msn, id))
1270                         {
1271                                 break;
1272                         }
1273                         ifmsn = ifmsn->next;
1274                 }
1275                 if (ifmsn)
1276                 {
1277                         start_trace(0, interface, numberrize_callerinfo(id, *type), NULL, DIRECTION_IN, 0, 0, "SCREEN (fount in MSN list)");
1278                         add_trace("msn", NULL, "%s", id);
1279                         end_trace();
1280                 }
1281                 if (!ifmsn && msn1) // not in list, first msn given
1282                 {
1283                         start_trace(0, interface, numberrize_callerinfo(id, *type), NULL, DIRECTION_IN, 0, 0, "SCREEN (not fount in MSN list)");
1284                         add_trace("msn", "given", "%s", id);
1285                         add_trace("msn", "used", "%s", msn1);
1286                         end_trace();
1287                         UNCPY(id, msn1, idsize);
1288                         id[idsize-1] = '\0';
1289                 }
1290         }
1291
1292         /* check screen list */
1293         if (out)
1294                 ifscreen = interface->ifscreen_out;
1295         else
1296                 ifscreen = interface->ifscreen_in;
1297         while (ifscreen)
1298         {
1299                 if (ifscreen->match_type==-1 || ifscreen->match_type==*type)
1300                 if (ifscreen->match_present==-1 || ifscreen->match_present==*present)
1301                 {
1302                         if (strchr(ifscreen->match,'%'))
1303                         {
1304                                 if (!strncmp(ifscreen->match, id, strchr(ifscreen->match,'%')-ifscreen->match))
1305                                         break;
1306                         } else
1307                         {
1308                                 if (!strcmp(ifscreen->match, id))
1309                                         break;
1310                         }
1311                 }
1312                 ifscreen = ifscreen->next;
1313         }
1314         if (ifscreen) // match
1315         {
1316                 start_trace(0, interface, numberrize_callerinfo(id, *type), NULL, out?DIRECTION_OUT:DIRECTION_IN, 0, 0, "SCREEN (fount in screen list)");
1317                 switch(*type)
1318                 {
1319                         case INFO_NTYPE_UNKNOWN:
1320                         add_trace("given", "type", "unknown");
1321                         break;
1322                         case INFO_NTYPE_SUBSCRIBER:
1323                         add_trace("given", "type", "subscriber");
1324                         break;
1325                         case INFO_NTYPE_NATIONAL:
1326                         add_trace("given", "type", "national");
1327                         break;
1328                         case INFO_NTYPE_INTERNATIONAL:
1329                         add_trace("given", "type", "international");
1330                         break;
1331                 }
1332                 switch(*present)
1333                 {
1334                         case INFO_PRESENT_ALLOWED:
1335                         add_trace("given", "present", "allowed");
1336                         break;
1337                         case INFO_PRESENT_RESTRICTED:
1338                         add_trace("given", "present", "restricted");
1339                         break;
1340                         case INFO_PRESENT_NOTAVAIL:
1341                         add_trace("given", "present", "not available");
1342                         break;
1343                 }
1344                 add_trace("given", "id", "%s", id[0]?id:"<empty>");
1345                 if (ifscreen->result_type != -1)
1346                 {
1347                         *type = ifscreen->result_type;
1348                         switch(*type)
1349                         {
1350                                 case INFO_NTYPE_UNKNOWN:
1351                                 add_trace("used", "type", "unknown");
1352                                 break;
1353                                 case INFO_NTYPE_SUBSCRIBER:
1354                                 add_trace("used", "type", "subscriber");
1355                                 break;
1356                                 case INFO_NTYPE_NATIONAL:
1357                                 add_trace("used", "type", "national");
1358                                 break;
1359                                 case INFO_NTYPE_INTERNATIONAL:
1360                                 add_trace("used", "type", "international");
1361                                 break;
1362                         }
1363                 }
1364                 if (ifscreen->result_present != -1)
1365                 {
1366                         *present = ifscreen->result_present;
1367                         switch(*present)
1368                         {
1369                                 case INFO_PRESENT_ALLOWED:
1370                                 add_trace("used", "present", "allowed");
1371                                 break;
1372                                 case INFO_PRESENT_RESTRICTED:
1373                                 add_trace("used", "present", "restricted");
1374                                 break;
1375                                 case INFO_PRESENT_NOTAVAIL:
1376                                 add_trace("used", "present", "not available");
1377                                 break;
1378                         }
1379                 }
1380                 if (strchr(ifscreen->match,'%'))
1381                 {
1382                         SCPY(suffix, strchr(ifscreen->match,'%') - ifscreen->match + id);
1383                         UNCPY(id, ifscreen->result, idsize);
1384                         id[idsize-1] = '\0';
1385                         if (strchr(id,'%'))
1386                         {
1387                                 *strchr(id,'%') = '\0';
1388                                 UNCAT(id, suffix, idsize);
1389                                 id[idsize-1] = '\0';
1390                         }
1391                 } else
1392                 {
1393                         UNCPY(id, ifscreen->result, idsize);
1394                         id[idsize-1] = '\0';
1395                 }
1396                 add_trace("used", "id", "%s", id[0]?id:"<empty>");
1397                 end_trace();
1398         }
1399 }
1400