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