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