SIP: Register, STUN and authentication support...
[lcr.git] / extension.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** reading and writing files for extensions                                  **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 /* extension */
15
16 const char *ext_rights[] = {
17         "none",
18         "internal",
19         "local",
20         "national",
21         "international",
22         NULL
23 };
24
25 const char *ext_yesno[] = {
26         "no",
27         "yes",
28         NULL
29 };
30
31
32 /* read extension
33  *
34  * reads extension from given extension number and fills structure
35  */
36 int read_extension(struct extension *ext, char *num)
37 {
38         FILE *fp=NULL;
39         char number[32];
40         char filename[256];
41         char *p;
42         char option[32];
43         char param[256],param2[256];
44         unsigned int line,i;
45         char buffer[1024];
46         int last_in_count = 0, last_out_count = 0;
47
48         /* save number, so &ext and ext.number can be given as parameters - without overwriting itself */
49         SCPY(number, num);
50         
51         if (number[0] == '\0')
52                 return(0);
53
54         SPRINT(filename, "%s/%s/settings", EXTENSION_DATA, number);
55
56         if (!(fp = fopen(filename, "r"))) {
57                 printf("the given extension doesn't exist: \"%s\"\n", filename);
58                 PDEBUG(DEBUG_CONFIG, "the given extension doesn't exist: \"%s\"\n", filename);
59                 return(0);
60         }
61
62         /* default values */
63         memset(ext, 0, sizeof(struct extension));
64         SCPY(ext->number, number);
65 //      ********** NOTE: also change value in apppbx constructor
66         ext->rights = 4; /* international */
67         ext->cfnr_delay = 20;
68         ext->vbox_codec = CODEC_MONO;
69
70         line=0;
71         while((GETLINE(buffer, fp))) {
72                 line++;
73                 p = buffer;
74
75                 while(*p <= 32) { /* skip spaces */
76                         if (*p == 0)
77                                 break;
78                         p++;
79                 }
80                 if (*p==0 || *p=='#') /* ignore comments and empty line */
81                         continue;
82
83                 option[0]=0;
84                 i=0; /* read option */
85                 while(*p > 32) {
86                         if (i+1 >= sizeof(option)) {
87                                 PERROR_RUNTIME("Error in %s (line %d): option too long.\n",filename,line);
88                                 break;
89                         }
90                         option[i+1] = '\0';
91                         option[i++] = *p++;
92                 }
93
94                 while(*p <= 32) { /* skip spaces */
95                         if (*p == 0)
96                                 break;
97                         p++;
98                 }
99
100                 param[0]=0;
101                 param2[0]=0;
102                 if (*p!=0 && *p!='#') { /* param */
103                         i=0; /* read param */
104                         while(*p > 32) {
105                                 if (i+1 >= sizeof(param)) {
106                                         PERROR_RUNTIME("Error in %s (line %d): param too long.\n",filename,line);
107                                         break;
108                                 }
109                                 param[i+1] = '\0';
110                                 param[i++] = *p++;
111                         }
112
113                         while(*p <= 32) { /* skip spaces */
114                                 if (*p == 0)
115                                         break;
116                                 p++;
117                         }
118
119                         if (*p!=0 && *p!='#') { /* param2 */
120                                 i=0; /* read param2 */
121                                 while(*p >= 32) {
122                                         if (i+1 >= sizeof(param2)) {
123                                                 PERROR_RUNTIME("Error in %s (line %d): param too long.\n",filename,line);
124                                                 break;
125                                         }
126                                         param2[i+1] = '\0';
127                                         param2[i++] = *p++;
128                                 }
129                         }
130                 }
131
132                 /* at this point we have option and param */
133
134                 /* check option */
135                 if (!strcmp(option,"name")) {
136                         SCPY(ext->name, param);
137                         if (param2[0]) {
138                                 SCAT(ext->name, (char *)" ");
139                                 SCAT(ext->name, param2);
140                         }
141
142                         PDEBUG(DEBUG_CONFIG, "name of extension: %s\n",param);
143                 } else
144                 if (!strcmp(option,"prefix")) {
145                         SCPY(ext->prefix, param);
146
147                         PDEBUG(DEBUG_CONFIG, "dial prefix on pickup: %s\n",param);
148                 } else
149                 if (!strcmp(option,"next")) {
150                         SCPY(ext->next, param);
151
152                         PDEBUG(DEBUG_CONFIG, "dial next on pickup: %s\n",param);
153                 } else
154                 if (!strcmp(option,"alarm")) {
155                         SCPY(ext->alarm, param);
156
157                         PDEBUG(DEBUG_CONFIG, "alarm message (if prefix): %s\n",param);
158                 } else
159                 if (!strcmp(option,"cfu")) {
160                         SCPY(ext->cfu, param);
161
162                         PDEBUG(DEBUG_CONFIG, "call forward unconditional: %s\n",param);
163                 } else
164                 if (!strcmp(option,"cfb")) {
165                         SCPY(ext->cfb, param);
166
167                         PDEBUG(DEBUG_CONFIG, "call forward when busy: %s\n",param);
168                 } else
169                 if (!strcmp(option,"cfnr")) {
170                         SCPY(ext->cfnr, param);
171
172                         PDEBUG(DEBUG_CONFIG, "call forward on no response: %s\n",param);
173                 } else
174                 if (!strcmp(option,"cfnr_delay")) {
175                         ext->cfnr_delay = atoi(param);
176                         if (ext->cfnr_delay < 0)
177                                 ext->cfnr_delay = 1;
178
179                         PDEBUG(DEBUG_CONFIG, "call forward no response delay: %d\n",ext->cfnr_delay);
180                 } else
181                 if (!strcmp(option,"cfp")) {
182                         SCPY(ext->cfp, param);
183
184                         PDEBUG(DEBUG_CONFIG, "call forward parallel: %s\n",param);
185                 } else
186                 if (!strcmp(option,"change_forward")) {
187                         i=0;
188                         while(ext_yesno[i]) {
189                                 if (!strcasecmp(param,ext_yesno[i]))
190                                         break;
191                                 i++;
192                         }
193                         if (ext_yesno[i]) {
194                                 ext->change_forward = i;
195                                 PDEBUG(DEBUG_CONFIG, "allow the change of forwarding: %s\n", ext_yesno[i]);
196                         } else {
197                                 PDEBUG(DEBUG_CONFIG, "unknown parameter for change_forward: %s\n", param);
198                         }
199                 } else
200                 if (!strcmp(option,"interfaces")) {
201                         SCPY(ext->interfaces, param);
202
203                         PDEBUG(DEBUG_CONFIG, "interfaces to ring calls to extension: %s %s\n",param,param2);
204                 } else
205                 if (!strcmp(option,"callerid")) {
206                         ext->callerid_present = INFO_PRESENT_ALLOWED;
207                         if (!strncasecmp(param2, "anonymous", 9))
208                                 ext->callerid_present = INFO_PRESENT_RESTRICTED;
209                         if (!strncasecmp(param, "non", 3)) {
210                                 ext->callerid[0] = '\0';
211                                 ext->callerid_present = INFO_PRESENT_NOTAVAIL;
212                                 ext->callerid_type = INFO_NTYPE_UNKNOWN;
213                                 PDEBUG(DEBUG_CONFIG, "caller id: ID NOT AVAILABLE\n");
214                         } else
215                         switch(param[0]) {
216                                 case 'i':
217                                 case 'I':
218                                 ext->callerid_type = INFO_NTYPE_INTERNATIONAL;
219                                 SCPY(ext->callerid, param+1);
220                                 PDEBUG(DEBUG_CONFIG, "caller id: %s INTERNATIONAL\n",param+1);
221                                 break;
222                                 case 'n':
223                                 case 'N':
224                                 ext->callerid_type = INFO_NTYPE_NATIONAL;
225                                 SCPY(ext->callerid, param+1);
226                                 PDEBUG(DEBUG_CONFIG, "caller id: %s NATIONAL\n",param+1);
227                                 break;
228                                 case 's':
229                                 case 'S':
230                                 ext->callerid_type = INFO_NTYPE_SUBSCRIBER;
231                                 SCPY(ext->callerid, param+1);
232                                 PDEBUG(DEBUG_CONFIG, "caller id: %s SUBSCRIBER\n",param+1);
233                                 break;
234                                 default:
235                                 ext->callerid_type = INFO_NTYPE_UNKNOWN;
236                                 SCPY(ext->callerid, param);
237                                 PDEBUG(DEBUG_CONFIG, "caller id: %s UNKNOWN\n",param);
238                         }
239                         ext->callerid[sizeof(ext->callerid)-1] = 0;
240                 } else
241                 if (!strcmp(option,"id_next_call")) {
242                         ext->id_next_call_present = INFO_PRESENT_ALLOWED;
243                         if (!strncasecmp(param2, "anonymous", 9))
244                                 ext->id_next_call_present = INFO_PRESENT_RESTRICTED;
245                         if (param[0] == '\0') {
246                                 ext->id_next_call_present = -1;
247                                 PDEBUG(DEBUG_CONFIG, "id next call: no id for next call\n");
248                         } else
249                         if (!strncasecmp(param, "none", 3)) {
250                                 ext->id_next_call[0] = '\0';
251                                 ext->id_next_call_present = INFO_PRESENT_NOTAVAIL;
252                                 ext->id_next_call_type = INFO_NTYPE_UNKNOWN;
253                                 PDEBUG(DEBUG_CONFIG, "id next call: ID NOT AVAILABLE\n");
254                         } else
255                         switch(param[0]) {
256                                 case 'i':
257                                 case 'I':
258                                 ext->id_next_call_type = INFO_NTYPE_INTERNATIONAL;
259                                 SCPY(ext->id_next_call, param+1);
260                                 PDEBUG(DEBUG_CONFIG, "id next call: %s INTERNATIONAL\n",param+1);
261                                 break;
262                                 case 'n':
263                                 case 'N':
264                                 ext->id_next_call_type = INFO_NTYPE_NATIONAL;
265                                 SCPY(ext->id_next_call, param+1);
266                                 PDEBUG(DEBUG_CONFIG, "id next call: %s NATIONAL\n",param+1);
267                                 break;
268                                 case 's':
269                                 case 'S':
270                                 ext->id_next_call_type = INFO_NTYPE_SUBSCRIBER;
271                                 SCPY(ext->id_next_call, param+1);
272                                 PDEBUG(DEBUG_CONFIG, "id next call: %s SUBSCRIBER\n",param+1);
273                                 break;
274                                 default:
275                                 ext->id_next_call_type = INFO_NTYPE_UNKNOWN;
276                                 SCPY(ext->id_next_call, param);
277                                 PDEBUG(DEBUG_CONFIG, "id next call: %s UNKNOWN\n",param);
278                         }
279
280
281
282                 } else
283                 if (!strcmp(option,"change_callerid")) {
284                         i=0;
285                         while(ext_yesno[i]) {
286                                 if (!strcasecmp(param,ext_yesno[i]))
287                                         break;
288                                 i++;
289                         }
290                         if (ext_yesno[i]) {
291                                 ext->change_callerid = i;
292                                 PDEBUG(DEBUG_CONFIG, "allow the change of caller id: %s\n", ext_yesno[i]);
293                         } else {
294                                 PDEBUG(DEBUG_CONFIG, "unknown parameter for change_callerid: %s\n", param);
295                         }
296                 } else
297                 if (!strcmp(option,"anon-ignore")) {
298                         i=0;
299                         while(ext_yesno[i]) {
300                                 if (!strcasecmp(param,ext_yesno[i]))
301                                         break;
302                                 i++;
303                         }
304                         if (ext_yesno[i]) {
305                                 ext->anon_ignore = i;
306                                 PDEBUG(DEBUG_CONFIG, "ignore restriction of CLIP & COLP %s\n", ext_yesno[i]);
307                         } else {
308                                 PDEBUG(DEBUG_CONFIG, "unknown parameter given anon-ignore: %s\n", param);
309                         }
310                 } else
311                 if (!strcmp(option,"clip")) {
312                         if (!strcasecmp(param, "hide"))
313                                 ext->clip = CLIP_HIDE;
314                         else
315                                 ext->clip = CLIP_ASIS;
316
317                         PDEBUG(DEBUG_CONFIG, "clip: %d\n",ext->clip);
318                 } else
319                 if (!strcmp(option,"colp")) {
320                         if (!strcasecmp(param, "hide"))
321                                 ext->colp = COLP_HIDE;
322                         else if (!strcasecmp(param, "force"))
323                                 ext->colp = COLP_FORCE;
324                         else
325                                 ext->colp = COLP_ASIS;
326
327                         PDEBUG(DEBUG_CONFIG, "colp: %d\n",ext->colp);
328                 } else
329                 if (!strcmp(option,"clip_prefix")) {
330                         SCPY(ext->clip_prefix, param);
331
332                         PDEBUG(DEBUG_CONFIG, "clip prefix: %s\n",param);
333                 } else
334                 if (!strcmp(option,"keypad")) {
335                         i=0;
336                         while(ext_yesno[i]) {
337                                 if (!strcasecmp(param,ext_yesno[i]))
338                                         break;
339                                 i++;
340                         }
341                         if (ext_yesno[i]) {
342                                 ext->keypad = i;
343                                 PDEBUG(DEBUG_CONFIG, "use keypad to do call control %s\n", ext_yesno[i]);
344                         } else {
345                                 PDEBUG(DEBUG_CONFIG, "unknown parameter given keypad: %s\n", param);
346                         }
347                 } else
348                 if (!strcmp(option,"rights")) {
349                         i=0;
350                         while(ext_rights[i]) {
351                                 if (!strcasecmp(param,ext_rights[i]))
352                                         break;
353                                 i++;
354                         }
355                         if (ext_rights[i]) {
356                                 ext->rights = i;
357                                 PDEBUG(DEBUG_CONFIG, "rights to dial: %s\n", ext_rights[i]);
358                         } else {
359                                 PDEBUG(DEBUG_CONFIG, "given rights unknown: %s\n", param);
360                         }
361                 } else
362                 if (!strcmp(option,"delete_ext")) {
363                         i=0;
364                         while(ext_yesno[i]) {
365                                 if (!strcasecmp(param,ext_yesno[i]))
366                                         break;
367                                 i++;
368                         }
369                         if (ext_yesno[i]) {
370                                 ext->delete_ext = i;
371                                 PDEBUG(DEBUG_CONFIG, "enables the delete key function for external calls: %s\n", ext_yesno[i]);
372                         } else {
373                                 PDEBUG(DEBUG_CONFIG, "unknown parameter given delete: %s\n", param);
374                         }
375                 } else
376                 if (!strcmp(option,"noknocking")) {
377                         i=0;
378                         while(ext_yesno[i]) {
379                                 if (!strcasecmp(param,ext_yesno[i]))
380                                         break;
381                                 i++;
382                         }
383                         if (ext_yesno[i]) {
384                                 ext->noknocking = i;
385                                 PDEBUG(DEBUG_CONFIG, "noknocking %s\n", ext_yesno[i]);
386                         } else {
387                                 PDEBUG(DEBUG_CONFIG, "given noknocking param unknown: %s\n", param);
388                         }
389                 } else
390                 if (!strcmp(option,"rx_gain")
391                  || !strcmp(option,"rxvol")) {
392                         ext->rx_gain = atoi(param);
393                         if (ext->rx_gain<-8 || ext->rx_gain>8)
394                                 ext->rx_gain = 0;
395
396                         PDEBUG(DEBUG_CONFIG, "receive volume: %d\n",ext->rx_gain);
397                 } else
398                 if (!strcmp(option,"tx_gain")
399                  || !strcmp(option,"txvol")) {
400                         ext->tx_gain = atoi(param);
401                         if (ext->tx_gain<-8 || ext->tx_gain>8)
402                                 ext->tx_gain = 0;
403
404                         PDEBUG(DEBUG_CONFIG, "transmit volume: %d\n",ext->tx_gain);
405                 } else
406                 if (!strcmp(option,"own_setup")) {
407                         i=0;
408                         while(ext_yesno[i]) {
409                                 if (!strcasecmp(param,ext_yesno[i]))
410                                         break;
411                                 i++;
412                         }
413                         if (ext_yesno[i]) {
414                                 ext->own_setup = i;
415                                 PDEBUG(DEBUG_CONFIG, "own_setup %s\n", ext_yesno[i]);
416                         } else {
417                                 PDEBUG(DEBUG_CONFIG, "given own_setup param unknown: %s\n", param);
418                         }
419                 } else
420                 if (!strcmp(option,"own_proceeding")) {
421                         i=0;
422                         while(ext_yesno[i]) {
423                                 if (!strcasecmp(param,ext_yesno[i]))
424                                         break;
425                                 i++;
426                         }
427                         if (ext_yesno[i]) {
428                                 ext->own_proceeding = i;
429                                 PDEBUG(DEBUG_CONFIG, "own_proceeding %s\n", ext_yesno[i]);
430                         } else {
431                                 PDEBUG(DEBUG_CONFIG, "given own_proceeding param unknown: %s\n", param);
432                         }
433                 } else
434                 if (!strcmp(option,"own_alerting")) {
435                         i=0;
436                         while(ext_yesno[i]) {
437                                 if (!strcasecmp(param,ext_yesno[i]))
438                                         break;
439                                 i++;
440                         }
441                         if (ext_yesno[i]) {
442                                 ext->own_alerting = i;
443                                 PDEBUG(DEBUG_CONFIG, "own_alerting %s\n", ext_yesno[i]);
444                         } else {
445                                 PDEBUG(DEBUG_CONFIG, "given own_alerting param unknown: %s\n", param);
446                         }
447                 } else
448                 if (!strcmp(option,"own_cause")) {
449                         i=0;
450                         while(ext_yesno[i]) {
451                                 if (!strcasecmp(param,ext_yesno[i]))
452                                         break;
453                                 i++;
454                         }
455                         if (ext_yesno[i]) {
456                                 ext->own_cause = i;
457                                 PDEBUG(DEBUG_CONFIG, "own_cause %s\n", ext_yesno[i]);
458                         } else {
459                                 PDEBUG(DEBUG_CONFIG, "given own_cause param unknown: %s\n", param);
460                         }
461                 } else
462                 if (!strcmp(option,"facility")) {
463                         i=0;
464                         while(ext_yesno[i]) {
465                                 if (!strcasecmp(param,ext_yesno[i]))
466                                         break;
467                                 i++;
468                         }
469                         if (ext_yesno[i]) {
470                                 ext->facility = i;
471                                 PDEBUG(DEBUG_CONFIG, "facility %s\n", ext_yesno[i]);
472                         } else {
473                                 PDEBUG(DEBUG_CONFIG, "given facility param unknown: %s\n", param);
474                         }
475                 } else
476                 if (!strcmp(option,"display_cause")) {
477                         if (!strcasecmp(param, "german"))
478                                 ext->display_cause = DISPLAY_CAUSE_GERMAN;
479                         else if (!strcasecmp(param, "english"))
480                                 ext->display_cause = DISPLAY_CAUSE_ENGLISH;
481                         else if (!strcasecmp(param, "german-location"))
482                                 ext->display_cause = DISPLAY_LOCATION_GERMAN;
483                         else if (!strcasecmp(param, "english-location"))
484                                 ext->display_cause = DISPLAY_LOCATION_ENGLISH;
485                         else if (!strcasecmp(param, "number"))
486                                 ext->display_cause = DISPLAY_CAUSE_NUMBER;
487                         else
488                                 ext->display_cause = DISPLAY_CAUSE_NONE;
489
490                         PDEBUG(DEBUG_CONFIG, "display cause: %d\n",ext->display_cause);
491                 } else
492 #if 0
493                 if (!strcmp(option,"display_ext")) {
494                         if (!strcasecmp(param, "number"))
495                                 ext->display_ext = DISPLAY_CID_NUMBER;
496                         else if (!strcasecmp(param, "abbrev"))
497                                 ext->display_ext = DISPLAY_CID_ABBREVIATION;
498                         else if (!strcasecmp(param, "name"))
499                                 ext->display_ext = DISPLAY_CID_NAME;
500                         else if (!strcasecmp(param, "number-name"))
501                                 ext->display_ext = DISPLAY_CID_NUMBER_NAME;
502                         else if (!strcasecmp(param, "name-number"))
503                                 ext->display_ext = DISPLAY_CID_NAME_NUMBER;
504                         else if (!strcasecmp(param, "abbrev-number"))
505                                 ext->display_ext = DISPLAY_CID_ABBREV_NUMBER;
506                         else if (!strcasecmp(param, "abbrev-name"))
507                                 ext->display_ext = DISPLAY_CID_ABBREV_NAME;
508                         else if (!strcasecmp(param, "abbrev-name-number"))
509                                 ext->display_ext = DISPLAY_CID_ABBREV_NAME_NUMBER;
510                         else if (!strcasecmp(param, "abbrev-number-name"))
511                                 ext->display_ext = DISPLAY_CID_ABBREV_NUMBER_NAME;
512                         else
513                                 ext->display_ext = DISPLAY_CID_ASIS;
514
515                         PDEBUG(DEBUG_CONFIG, "display ext: %d\n",ext->display_ext);
516                 } else
517 #endif
518                 if (!strcmp(option,"display_ext")) {
519                         i=0;
520                         while(ext_yesno[i]) {
521                                 if (!strcasecmp(param,ext_yesno[i]))
522                                         break;
523                                 i++;
524                         }
525                         if (ext_yesno[i]) {
526                                 ext->display_ext = i;
527                                 PDEBUG(DEBUG_CONFIG, "display ext %s\n", ext_yesno[i]);
528                         } else {
529                                 PDEBUG(DEBUG_CONFIG, "given display_ext param unknown: %s\n", param);
530                         }
531                 } else
532                 if (!strcmp(option,"display_int")) {
533                         i=0;
534                         while(ext_yesno[i]) {
535                                 if (!strcasecmp(param,ext_yesno[i]))
536                                         break;
537                                 i++;
538                         }
539                         if (ext_yesno[i]) {
540                                 ext->display_int = i;
541                                 PDEBUG(DEBUG_CONFIG, "display int %s\n", ext_yesno[i]);
542                         } else {
543                                 PDEBUG(DEBUG_CONFIG, "given display_int param unknown: %s\n", param);
544                         }
545                 } else
546                 if (!strcmp(option,"display_fake")) {
547                         i=0;
548                         while(ext_yesno[i]) {
549                                 if (!strcasecmp(param,ext_yesno[i]))
550                                         break;
551                                 i++;
552                         }
553                         if (ext_yesno[i]) {
554                                 ext->display_fake = i;
555                                 PDEBUG(DEBUG_CONFIG, "display fake caller ids %s\n", ext_yesno[i]);
556                         } else {
557                                 PDEBUG(DEBUG_CONFIG, "given display_fake param unknown: %s\n", param);
558                         }
559                 } else
560                 if (!strcmp(option,"display_anon")) {
561                         i=0;
562                         while(ext_yesno[i]) {
563                                 if (!strcasecmp(param,ext_yesno[i]))
564                                         break;
565                                 i++;
566                         }
567                         if (ext_yesno[i]) {
568                                 ext->display_anon = i;
569                                 PDEBUG(DEBUG_CONFIG, "display anonymouse ids %s\n", ext_yesno[i]);
570                         } else {
571                                 PDEBUG(DEBUG_CONFIG, "given display_anon param unknown: %s\n", param);
572                         }
573                 } else
574                 if (!strcmp(option,"display_menu")) {
575                         i=0;
576                         while(ext_yesno[i]) {
577                                 if (!strcasecmp(param,ext_yesno[i]))
578                                         break;
579                                 i++;
580                         }
581                         if (ext_yesno[i]) {
582                                 ext->display_menu = i;
583                                 PDEBUG(DEBUG_CONFIG, "display menu %s\n", ext_yesno[i]);
584                         } else {
585                                 PDEBUG(DEBUG_CONFIG, "given display_menu param unknown: %s\n", param);
586                         }
587                 } else
588                 if (!strcmp(option,"display_dialing")) {
589                         i=0;
590                         while(ext_yesno[i]) {
591                                 if (!strcasecmp(param,ext_yesno[i]))
592                                         break;
593                                 i++;
594                         }
595                         if (ext_yesno[i]) {
596                                 ext->display_dialing = i;
597                                 PDEBUG(DEBUG_CONFIG, "display dialing %s\n", ext_yesno[i]);
598                         } else {
599                                 PDEBUG(DEBUG_CONFIG, "given display_dialing param unknown: %s\n", param);
600                         }
601                 } else
602                 if (!strcmp(option,"display_name")) {
603                         i=0;
604                         while(ext_yesno[i]) {
605                                 if (!strcasecmp(param,ext_yesno[i]))
606                                         break;
607                                 i++;
608                         }
609                         if (ext_yesno[i]) {
610                                 ext->display_name = i;
611                                 PDEBUG(DEBUG_CONFIG, "display name %s\n", ext_yesno[i]);
612                         } else {
613                                 PDEBUG(DEBUG_CONFIG, "given display_name param unknown: %s\n", param);
614                         }
615                 } else
616                 if (!strcmp(option,"tones_dir")) {
617                         if (param[strlen(param)-1] == '/')
618                                 param[strlen(param)-1]=0;
619                         SCPY(ext->tones_dir, param);
620
621                         PDEBUG(DEBUG_CONFIG, "directory of tones: %s\n",param);
622                 } else
623                 if (!strcmp(option,"record")) {
624                         if (!strcasecmp(param, "mono"))
625                                 ext->record = CODEC_MONO;
626                         else if (!strcasecmp(param, "stereo"))
627                                 ext->record = CODEC_STEREO;
628                         else if (!strcasecmp(param, "8bit"))
629                                 ext->record = CODEC_8BIT;
630                         else if (!strcasecmp(param, "law"))
631                                 ext->record = CODEC_LAW;
632                         else
633                                 ext->record = CODEC_OFF;
634                         PDEBUG(DEBUG_CONFIG, "given record param: %s\n", param);
635                 } else
636                 if (!strcmp(option,"password")) {
637                         SCPY(ext->password, param);
638
639                         PDEBUG(DEBUG_CONFIG, "password: %s\n",param);
640                 } else
641                 if (!strcmp(option,"vbox_mode")) {
642                         if (!strcasecmp(param, "parallel"))
643                                 ext->vbox_mode = VBOX_MODE_PARALLEL;
644                         else if (!strcasecmp(param, "announcement"))
645                                 ext->vbox_mode = VBOX_MODE_ANNOUNCEMENT;
646                         else
647                                 ext->vbox_mode = VBOX_MODE_NORMAL;
648                         PDEBUG(DEBUG_CONFIG, "given vbox mode: %s\n", param);
649                 } else
650                 if (!strcmp(option,"vbox_codec")) {
651                         if (!strcasecmp(param, "stereo"))
652                                 ext->vbox_codec = CODEC_STEREO;
653                         else if (!strcasecmp(param, "8bit"))
654                                 ext->vbox_codec = CODEC_8BIT;
655                         else if (!strcasecmp(param, "law"))
656                                 ext->vbox_codec = CODEC_LAW;
657                         else
658                                 ext->vbox_codec = CODEC_MONO;
659                         PDEBUG(DEBUG_CONFIG, "given record param: %s\n", param);
660                 } else
661                 if (!strcmp(option,"vbox_time")) {
662                         ext->vbox_time = atoi(param);
663                         if (ext->vbox_time < 0)
664                                 ext->vbox_time = 0;
665
666                         PDEBUG(DEBUG_CONFIG, "vbox time to record: %d\n",ext->vbox_time);
667                 } else
668                 if (!strcmp(option,"vbox_display")) {
669                         if (!strcasecmp(param, "detailed")
670                          || !strcasecmp(param, "detailled"))
671                                 ext->vbox_display = VBOX_DISPLAY_DETAILED;
672                         else if (!strcasecmp(param, "off"))
673                                 ext->vbox_display = VBOX_DISPLAY_OFF;
674                         else
675                                 ext->vbox_display = VBOX_DISPLAY_BRIEF;
676                         PDEBUG(DEBUG_CONFIG, "given vbox mode: %s\n", param);
677                 } else
678                 if (!strcmp(option,"vbox_language")) {
679                         if (!strcasecmp(param, "german"))
680                                 ext->vbox_language = VBOX_LANGUAGE_GERMAN;
681                         else
682                                 ext->vbox_language = VBOX_LANGUAGE_ENGLISH;
683                         PDEBUG(DEBUG_CONFIG, "given vbox mode: %s\n", param);
684                 } else
685                 if (!strcmp(option,"vbox_email")) {
686                         SCPY(ext->vbox_email, param);
687                         PDEBUG(DEBUG_CONFIG, "given vbox email: %s\n", param);
688                 } else
689                 if (!strcmp(option,"vbox_email_file")) {
690                         i=0;
691                         while(ext_yesno[i]) {
692                                 if (!strcasecmp(param,ext_yesno[i]))
693                                         break;
694                                 i++;
695                         }
696                         if (ext_yesno[i]) {
697                                 ext->vbox_email_file = i;
698                                 PDEBUG(DEBUG_CONFIG, "attach audio file %s\n", ext_yesno[i]);
699                         } else {
700                                 PDEBUG(DEBUG_CONFIG, "given vbox_email_file param unknown: %s\n", param);
701                         }
702                 } else
703                 if (!strcmp(option,"vbox_free")) {
704                         i=0;
705                         while(ext_yesno[i]) {
706                                 if (!strcasecmp(param,ext_yesno[i]))
707                                         break;
708                                 i++;
709                         }
710                         if (ext_yesno[i]) {
711                                 ext->vbox_free = i;
712                                 PDEBUG(DEBUG_CONFIG, "vbox_free %s\n", ext_yesno[i]);
713                         } else {
714                                 PDEBUG(DEBUG_CONFIG, "given vbox_free param unknown: %s\n", param);
715                         }
716                 } else
717                 if (!strcmp(option,"last_in")) {
718                         if (param[0] && last_in_count<MAX_REMEMBER) {
719                                 SCPY(ext->last_in[last_in_count], param);
720                                 last_in_count++;
721                         }
722                         PDEBUG(DEBUG_CONFIG, "last_in dialed number: %s\n",param);
723                 } else
724                 if (!strcmp(option,"last_out")) {
725                         if (param[0] && last_out_count<MAX_REMEMBER) {
726                                 SCPY(ext->last_out[last_out_count], param);
727                                 last_out_count++;
728                         }
729                         PDEBUG(DEBUG_CONFIG, "last_out dialed number: %s\n",param);
730                 } else
731                 if (!strcmp(option,"datacall")) {
732                         i=0;
733                         while(ext_yesno[i]) {
734                                 if (!strcasecmp(param,ext_yesno[i]))
735                                         break;
736                                 i++;
737                         }
738                         if (ext_yesno[i]) {
739                                 ext->datacall = i;
740                                 PDEBUG(DEBUG_CONFIG, "datacall %s\n", ext_yesno[i]);
741                         } else {
742                                 PDEBUG(DEBUG_CONFIG, "given datacall param unknown: %s\n", param);
743                         }
744                 } else
745                 if (!strcmp(option,"seconds")) {
746                         i=0;
747                         while(ext_yesno[i]) {
748                                 if (!strcasecmp(param,ext_yesno[i]))
749                                         break;
750                                 i++;
751                         }
752                         if (ext_yesno[i]) {
753                                 ext->no_seconds = 1-i;
754                                 PDEBUG(DEBUG_CONFIG, "seconds %s\n", ext_yesno[i]);
755                         } else {
756                                 PDEBUG(DEBUG_CONFIG, "unknown param for seconds: %s\n", param);
757                         }
758                 } else
759                 if (!strcmp(option,"otp-ident")) {
760                         SCPY(ext->otp_ident, param);
761                         PDEBUG(DEBUG_CONFIG, "otp-ident: %s\n",param);
762                 } else
763                 if (!strcmp(option,"dov_ident")) {
764                         if (param[0]) {
765                                 SCPY(ext->dov_ident, param);
766                                 PDEBUG(DEBUG_CONFIG, "dov_ident string: %s\n",param);
767                         }
768                 } else
769                 if (!strcmp(option,"dov_log")) {
770                         if (param[0]) {
771                                 SCPY(ext->dov_log, param);
772                                 PDEBUG(DEBUG_CONFIG, "dov_log filename: %s\n",param);
773                         }
774                 } else
775                 if (!strcmp(option,"dov_type")) {
776                         if (!strcasecmp(param, "pcm"))
777                                 ext->dov_type = DOV_TYPE_PCM;
778                         else
779                                 ext->dov_type = DOV_TYPE_PWM;
780                         PDEBUG(DEBUG_CONFIG, "given dov type: %s\n", param);
781                 } else
782                 if (!strcmp(option,"dov_level")) {
783                         if (atoi(param)) {
784                                 ext->dov_level = atoi(param);
785                                 PDEBUG(DEBUG_CONFIG, "dov_level: %s\n",param);
786                         }
787                 } else {
788                         PERROR_RUNTIME("Error in %s (line %d): wrong option keyword %s.\n",filename,line,option);
789                 }
790         }
791
792         if (fp) fclose(fp);
793         return(1);
794 }
795
796
797 /* write extension
798  *
799  * writes extension for given extension number from structure
800  */
801 int write_extension(struct extension *ext, char *number)
802 {
803         FILE *fp=NULL;
804         char filename[256];
805         int i;
806
807         if (number[0] == '\0')
808                 return(0);
809
810         SPRINT(filename, "%s/%s/settings", EXTENSION_DATA, number);
811
812         if (!(fp = fopen(filename, "w"))) {
813                 PERROR("Cannot open settings: \"%s\"\n", filename);
814                 return(0);
815         }
816
817         fprintf(fp,"# Settings of extension %s\n\n", number);
818
819         fprintf(fp,"# Name of extension:\n");
820         fprintf(fp,"name            %s\n\n",ext->name);
821
822         fprintf(fp,"# Predialed prefix after pick-up of the phone\n");
823         fprintf(fp,"prefix          %s\n\n",ext->prefix);
824
825         fprintf(fp,"# Next prefix to dial pick-up of the phone\n");
826         fprintf(fp,"# This will be cleared on hangup.\n");
827         fprintf(fp,"next            %s\n\n",ext->next);
828
829 //      fprintf(fp,"# Set up alarm message after prefix is dialed and connection is established\n");
830 //      fprintf(fp,"alarm           %s\n\n",ext->alarm);
831
832         fprintf(fp,"# Interface(s) to ring on calls to extension (as named in interface.conf)\n");
833         fprintf(fp,"# Seperate multiple interfaces by using komma without spaces\n");
834         fprintf(fp,"# Example: Int would ring on the interface with the name \"Int\"\n");
835         fprintf(fp,"#          Int1,Int2 would ring incoming calls on both interfaces Int1 and Int2.\n");
836         fprintf(fp,"interfaces      %s\n\n",ext->interfaces);
837
838         fprintf(fp,"# Call Forward Unconditional (CFU)\n");
839         fprintf(fp,"# No port will be called, CFB, CFNR and CFP is ignored.\n");
840         fprintf(fp,"# Use keyword \"vbox\" to forward call directly to answering machine.\n");
841         fprintf(fp,"cfu             %s\n\n",ext->cfu);
842
843         fprintf(fp,"# Call Forward when Busy (CFB)\n");
844         fprintf(fp,"# If the extension is in use at least once, this forward is done.\n");
845         fprintf(fp,"# In case of busy line, CFNR and CFP is ignored.\n");
846         fprintf(fp,"# Use keyword \"vbox\" to forward call to answering machine when busy.\n");
847         fprintf(fp,"cfb             %s\n\n",ext->cfb);
848
849         fprintf(fp,"# Call Forward on No Response (CFNR)\n");
850         fprintf(fp,"# If noone answers, the call is forwarded, ports and CFP will be released.\n");
851         fprintf(fp,"# The default delay is 20 seconds.\n");
852         fprintf(fp,"# Use keyword \"vbox\" to forward call to answering machine on no response.\n");
853         fprintf(fp,"cfnr            %s\n",ext->cfnr);
854         fprintf(fp,"cfnr_delay      %d\n\n",ext->cfnr_delay);
855
856         fprintf(fp,"# Call Forward Parallel (CFP)\n");
857         fprintf(fp,"# Call will ring on the forwarded number, simulaniousely with the ports.\n");
858         fprintf(fp,"cfp             %s\n\n",ext->cfp);
859
860         fprintf(fp,"# Allow user to change call forwarding.\n");
861         fprintf(fp,"change_forward  %s\n\n", ext_yesno[ext->change_forward]);
862
863         fprintf(fp,"# Caller id\n# This must be one of the following:\n");
864         fprintf(fp,"# <number> (as dialed from your local area)\n");
865         fprintf(fp,"# <number> anonymous (will only be shown to emergency phones)\n");
866         fprintf(fp,"# none (no number available at all)\n");
867         fprintf(fp,"# by default the number is of type UNKNOWN (for MULTIPOINT lines)\n");
868         fprintf(fp,"# if your caller id is not screened on outgoing calls use one of the following:\n");
869         fprintf(fp,"# use prefix 'i' for TYPE INTERNATIONAL (i<county code><areacode+number>)\n");
870         fprintf(fp,"# use prefix 'n' for TYPE NATIONAL (n<areacode+number>)\n");
871         fprintf(fp,"# use prefix 's' for TYPE SUBSCRIBER (s<local number>)\n");
872         if (ext->callerid_present == INFO_PRESENT_NOTAVAIL)
873                 fprintf(fp,"callerid        none\n\n");
874         else {
875                 switch(ext->callerid_type) {
876                         case INFO_NTYPE_INTERNATIONAL:
877                         fprintf(fp,"callerid        i%s%s\n\n",ext->callerid, (ext->callerid_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
878                         break;
879                         case INFO_NTYPE_NATIONAL:
880                         fprintf(fp,"callerid        n%s%s\n\n",ext->callerid, (ext->callerid_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
881                         break;
882                         case INFO_NTYPE_SUBSCRIBER:
883                         fprintf(fp,"callerid        s%s%s\n\n",ext->callerid, (ext->callerid_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
884                         break;
885                         default:
886                         fprintf(fp,"callerid        %s%s\n\n",ext->callerid, (ext->callerid_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
887                 }
888         }
889
890         fprintf(fp,"# Caller id for next call (see caller id)\n");
891         if (ext->id_next_call_present < 0)
892                 fprintf(fp,"id_next_call    \n\n");
893         else if (ext->id_next_call_present == INFO_PRESENT_NOTAVAIL)
894                 fprintf(fp,"id_next_call    none\n\n");
895         else {
896                 switch(ext->id_next_call_type) {
897                         case INFO_NTYPE_INTERNATIONAL:
898                         fprintf(fp,"id_next_call    i%s%s\n\n",ext->id_next_call, (ext->id_next_call_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
899                         break;
900                         case INFO_NTYPE_NATIONAL:
901                         fprintf(fp,"id_next_call    n%s%s\n\n",ext->id_next_call, (ext->id_next_call_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
902                         break;
903                         case INFO_NTYPE_SUBSCRIBER:
904                         fprintf(fp,"id_next_call    s%s%s\n\n",ext->id_next_call, (ext->id_next_call_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
905                         break;
906                         default:
907                         fprintf(fp,"id_next_call    %s%s\n\n",ext->id_next_call, (ext->id_next_call_present==INFO_PRESENT_RESTRICTED)?" anonymous":"");
908                 }
909         }
910
911         fprintf(fp,"# Allow user to change caller ID.\n");
912         fprintf(fp,"change_callerid %s\n\n", ext_yesno[ext->change_callerid]);
913
914         fprintf(fp,"# Caller Line Identification Presentation (CLIP)\n");
915         fprintf(fp,"# clip (asis|hide)\n");
916         fprintf(fp,"# asis: On forwarded calls the CLIP is used as presented by the calling party.\n");
917         fprintf(fp,"# hide: Always use extension's caller id, even on forwared calls.\n");
918         switch(ext->clip) {
919                 case CLIP_HIDE:
920                 fprintf(fp,"clip            hide\n\n");
921                 break;
922                 default:
923                 fprintf(fp,"clip            asis\n\n");
924         }
925
926         fprintf(fp,"# Connected Line Identification Presentation (COLP)\n");
927         fprintf(fp,"# colp (asis|hide|force)\n");
928         fprintf(fp,"# asis: Provides colp as defined by the extension's caller id.\n");
929         fprintf(fp,"#       On forwarded calls the COLP is used as presented by the called party.\n");
930         fprintf(fp,"# hide: Always use extension's caller id, even on forwared calls.\n");
931         fprintf(fp,"# force: If COLP is not presented by forwarded calls the dialed number is used.\n");
932         switch(ext->colp) {
933                 case COLP_HIDE:
934                 fprintf(fp,"colp            hide\n\n");
935                 break;
936                 case COLP_FORCE:
937                 fprintf(fp,"colp            force\n\n");
938                 break;
939                 default:
940                 fprintf(fp,"colp            asis\n\n");
941         }
942
943         fprintf(fp,"# CLIP Prefix\n");
944         fprintf(fp,"# Adds a prefix to incoming caller IDs, so telephones will be able to respond\n");
945         fprintf(fp,"# to unanswered calls from their list. The prefix must be the digit(s) to get\n");
946         fprintf(fp,"# an external line. The caller ID will then be extendet so that they can be\n");
947         fprintf(fp,"# dialed from internal telephones. Many telephones have this feature, but some\n");
948         fprintf(fp,"# don't.\n");
949         fprintf(fp,"clip_prefix     %s\n\n",ext->clip_prefix);
950
951         fprintf(fp,"# Keypad control\n");
952         fprintf(fp,"# If supported by telephone, pressing a key on the keypad will not result in\n");
953         fprintf(fp,"# DTMF tone, but the digit is transmitted via D-channel diaing info.\n");
954         fprintf(fp,"keypad          %s\n\n",(ext->keypad)?"yes":"no");
955
956         fprintf(fp,"# Ignore restriction of COLP and CLIP\n");
957         fprintf(fp,"# In this case even restricted numbers are presented to this extension.\n");
958         fprintf(fp,"# This also works for incoming external anonymous calls IF:\n");
959         fprintf(fp,"# You have the CLIRIGN feature like POLICE or equivalent.\n");
960         fprintf(fp,"anon-ignore     %s\n\n",(ext->anon_ignore)?"yes":"no");
961
962         fprintf(fp,"# Dialing rights (none|internal|local|national|international)\n");
963         fprintf(fp,"rights          %s\n\n",ext_rights[ext->rights]);
964
965         fprintf(fp,"# Delete function for external calls. '*' will delete the last digit, '#' will\n");
966         fprintf(fp,"# delete the complete number. Also enable 'display_dialing' to see on the\n");
967         fprintf(fp,"# display what actually happens.\n");
968         fprintf(fp,"delete_ext      %s\n\n",ext_yesno[ext->delete_ext]);
969
970         fprintf(fp,"# If noknocking is enabled, the caller will get a busy message when the\n");
971         fprintf(fp,"# extension is doing at least one call.\n");
972         fprintf(fp,"noknocking      %s\n\n",ext_yesno[ext->noknocking]);
973
974         fprintf(fp,"# Transmit volume (-8 .. 8)\n");
975         fprintf(fp,"# 0 = normal\n");
976         fprintf(fp,"# 1 = double, 2 = quadrupel, 8 = 256 times (amplitude)\n");
977         fprintf(fp,"# -1 = half, -2 = quarter, 8 = 1/256th (amplitude)\n");
978         fprintf(fp,"# Audio data is limited to the maximum value when exceeds limit.\n");
979         fprintf(fp,"tx_gain          %d\n\n",ext->tx_gain);
980
981         fprintf(fp,"# Receive volume (-8 .. 8)\n");
982         fprintf(fp,"# (see tx_gain)\n");
983         fprintf(fp,"rx_gain          %d\n\n",ext->rx_gain);
984
985
986         fprintf(fp,"# Force to use tones and announcements generated by the pbx.\n");
987         fprintf(fp,"# For internal calls always own tones are used. You may specify own tones for\n");
988         fprintf(fp,"# different call states:\n");
989         fprintf(fp,"# own_setup (dialtone and during dialing)\n");
990         fprintf(fp,"# own_proceeding (call in poceeding state)\n");
991         fprintf(fp,"# own_alerting (call is ringing)\n");
992         fprintf(fp,"# own_cause (when the call gets disconnected or failed to be completed)\n");
993         fprintf(fp,"own_setup       %s\n",ext_yesno[ext->own_setup]);
994         fprintf(fp,"own_proceeding  %s\n",ext_yesno[ext->own_proceeding]);
995         fprintf(fp,"own_alerting    %s\n",ext_yesno[ext->own_alerting]);
996         fprintf(fp,"own_cause       %s\n\n",ext_yesno[ext->own_cause]);
997
998         fprintf(fp,"# Allow facility information to be transfered to the telephone.\n");
999         fprintf(fp,"# This is required to receive advice of charge.\n");
1000         fprintf(fp,"facility        %s\n\n",ext_yesno[ext->facility]);
1001
1002         fprintf(fp,"# Display clear causes using display messages (Q.850)\n# This must be one of the following:\n");
1003         fprintf(fp,"# none (no displaying of clear causes)\n");
1004         fprintf(fp,"# english (display cause text in english)\n");
1005         fprintf(fp,"# german (display cause text in german)\n");
1006         fprintf(fp,"# number (display cause number only)\n");
1007         fprintf(fp,"# english-location (display cause text in english and location)\n");
1008         fprintf(fp,"# german-location (display cause text in german and location)\n");
1009         switch(ext->display_cause) {
1010                 case DISPLAY_CAUSE_ENGLISH:
1011                 fprintf(fp,"display_cause   english\n\n");
1012                 break;
1013                 case DISPLAY_CAUSE_GERMAN:
1014                 fprintf(fp,"display_cause   german\n\n");
1015                 break;
1016                 case DISPLAY_LOCATION_ENGLISH:
1017                 fprintf(fp,"display_cause   english-location\n\n");
1018                 break;
1019                 case DISPLAY_LOCATION_GERMAN:
1020                 fprintf(fp,"display_cause   german-location\n\n");
1021                 break;
1022                 case DISPLAY_CAUSE_NUMBER:
1023                 fprintf(fp,"display_cause   number\n\n");
1024                 break;
1025                 default:
1026                 fprintf(fp,"display_cause   none\n\n");
1027         }
1028
1029         fprintf(fp,"# Display external caller ids using display override (yes or no)\n");
1030         fprintf(fp,"# example: \"15551212\"\n");
1031         fprintf(fp,"display_ext     %s\n\n",(ext->display_ext)?"yes":"no");
1032
1033         fprintf(fp,"# Display internal caller ids using display override (yes or no)\n");
1034         fprintf(fp,"# example: \"200 (int)\"\n");
1035         fprintf(fp,"display_int     %s\n\n",(ext->display_int)?"yes":"no");
1036
1037         fprintf(fp,"# Display if calls are anonymous using display override (yes or no)\n");
1038         fprintf(fp,"# This makes only sense if the anon-ignore feature is enabled.\n");
1039         fprintf(fp,"# example: \"15551212 anon\"\n");
1040         fprintf(fp,"display_anon    %s\n\n",(ext->display_anon)?"yes":"no");
1041
1042         fprintf(fp,"# Display fake caller ids using display override (yes or no)\n");
1043         fprintf(fp,"# If the caller uses \"clip no screening\", you will see if the number is\n");
1044         fprintf(fp,"# real or fake\n");
1045         fprintf(fp,"# example: \"15551212 fake\"\n");
1046         fprintf(fp,"display_fake    %s\n\n",(ext->display_fake)?"yes":"no");
1047
1048         fprintf(fp,"# Display caller's name if available. (yes or no)\n");
1049         fprintf(fp,"# example: \"15551212 Axel\"\n");
1050         fprintf(fp,"display_name    %s\n\n",(ext->display_name)?"yes":"no");
1051
1052         fprintf(fp,"# Display menu when '*' and '#' is pressed. The menu shows all prefixes for\n");
1053         fprintf(fp,"# internal dialing by pressing '*' for previous prefix and '#' for next prefix.\n");
1054         fprintf(fp,"# Also the dialed prefix is show on display. (yes or no)\n");
1055         fprintf(fp,"display_menu    %s\n\n",(ext->display_menu)?"yes":"no");
1056
1057         fprintf(fp,"# Display digits as they are interpreted by pbx. (yes or no)\n");
1058         fprintf(fp,"display_dialing %s\n\n",(ext->display_dialing)?"yes":"no");
1059
1060         fprintf(fp,"# Tones directory for announcements and patterns\n");
1061         fprintf(fp,"# Enter nothing for default tones as selected by options.conf or interface.conf.\n");
1062         fprintf(fp,"tones_dir       %s\n\n",ext->tones_dir);
1063
1064         fprintf(fp,"# Record calls to extension's directory. The file is written as wave.\n");
1065         fprintf(fp,"# This must be one of the following:\n");
1066         fprintf(fp,"# off (no recording)\n");
1067         fprintf(fp,"# mono (records wave 16 bit mono, 128kbits/s)\n");
1068         fprintf(fp,"# stereo (records wave 32 bit stereo, 256kbits/s)\n");
1069         fprintf(fp,"# 8bit (records wave 8 bit mono, 64kbits/s)\n");
1070         fprintf(fp,"# law (records xLaw encoded, as specified in options.conf, 64kbps/s)\n");
1071         switch(ext->record) {
1072                 case CODEC_MONO:
1073                 fprintf(fp,"record          mono\n\n");
1074                 break;
1075                 case CODEC_STEREO:
1076                 fprintf(fp,"record          stereo\n\n");
1077                 break;
1078                 case CODEC_8BIT:
1079                 fprintf(fp,"record          8bit\n\n");
1080                 break;
1081                 case CODEC_LAW:
1082                 fprintf(fp,"record          law\n\n");
1083                 break;
1084                 default:
1085                 fprintf(fp,"record          off\n\n");
1086         }
1087
1088         fprintf(fp,"# Password for callback and login\n");
1089         fprintf(fp,"# Enter nothing if callback and login should not be possible.\n");
1090         fprintf(fp,"password        %s\n\n",ext->password);
1091
1092         fprintf(fp,"# The Answering Machine. Enter the mode of answering machine.\n");
1093         fprintf(fp,"# This must be one of the following:\n");
1094         fprintf(fp,"# normal (plays announcement and records after that)\n");
1095         fprintf(fp,"# parallel (plays announcement and records also DURING announcement.)\n");
1096         fprintf(fp,"# announcement (just plays announcement and hangs up)\n");
1097         switch(ext->vbox_mode) {
1098                 case VBOX_MODE_PARALLEL:
1099                 fprintf(fp,"vbox_mode       parallel\n\n");
1100                 break;
1101                 case VBOX_MODE_ANNOUNCEMENT:
1102                 fprintf(fp,"vbox_mode       announcement\n\n");
1103                 break;
1104                 default:
1105                 fprintf(fp,"vbox_mode       normal\n\n");
1106         }
1107
1108         fprintf(fp,"# The Answering Machine. Enter the type of codec for recording.\n");
1109         fprintf(fp,"# This must be one of the following:\n");
1110         fprintf(fp,"# law (alaw/ulas codec, as specified in options.conf)\n");
1111         fprintf(fp,"# mono (16 bit mono wave file)\n");
1112         fprintf(fp,"# stereo (16 bit stereo wave file)\n");
1113         fprintf(fp,"# 8bit (8 bit mono wave file)\n");
1114         switch(ext->vbox_codec) {
1115                 case CODEC_LAW:
1116                 fprintf(fp,"vbox_codec      law\n\n");
1117                 break;
1118                 case CODEC_STEREO:
1119                 fprintf(fp,"vbox_codec      stereo\n\n");
1120                 break;
1121                 case CODEC_8BIT:
1122                 fprintf(fp,"vbox_codec      8bit\n\n");
1123                 break;
1124                 default:
1125                 fprintf(fp,"vbox_codec      mono\n\n");
1126         }
1127
1128         fprintf(fp,"# The Answering Machine. Enter maximum time to record after announcement.\n");
1129         fprintf(fp,"# Leave empty, enter \"infinite\" or give time in seconds.\n");
1130         fprintf(fp,"# Enter nothing if callback and login should not be possible.\n");
1131         if (ext->vbox_time)
1132                 fprintf(fp,"vbox_time       %d\n\n",ext->vbox_time);
1133         else
1134                 fprintf(fp,"vbox_time       infinite\n\n");
1135
1136         fprintf(fp,"# The Answering Machine. Enter mode for display current state.\n");
1137         fprintf(fp,"# This must be one of the following:\n");
1138         fprintf(fp,"# brief (displays brief information, for small displays)\n");
1139         fprintf(fp,"# detailed (displays detailed information, for larger displays)\n");
1140         fprintf(fp,"# off (don't display anything)\n");
1141         switch(ext->vbox_display) {
1142                 case VBOX_DISPLAY_OFF:
1143                 fprintf(fp,"vbox_display    off\n\n");
1144                 break;
1145                 case VBOX_DISPLAY_DETAILED:
1146                 fprintf(fp,"vbox_display    detailed\n\n");
1147                 break;
1148                 default:
1149                 fprintf(fp,"vbox_display    brief\n\n");
1150         }
1151
1152         fprintf(fp,"# The Answering Machine. Enter type of language: \"english\" or \"german\"\n");
1153         fprintf(fp,"# Display information of the menu, will be provided as specified.\n");
1154         fprintf(fp,"# The menu's voice is located in \"vbox_english\" and \"vbox_german\".\n");
1155         if (ext->vbox_language)
1156                 fprintf(fp,"vbox_language   german\n\n");
1157         else
1158                 fprintf(fp,"vbox_language   english\n\n");
1159
1160         fprintf(fp,"# The Answering Machine. Enter email to send incoming messages to:\n");
1161         fprintf(fp,"# All incoming message will be send to the given address.\n");
1162         fprintf(fp,"# The audio file is attached if \"vbox_email_file\" is 'yes'\n");
1163         fprintf(fp,"vbox_email      %s\n", ext->vbox_email);
1164         fprintf(fp,"vbox_email_file %s\n\n",ext_yesno[ext->vbox_email_file]);
1165
1166         fprintf(fp,"# If audio path is connected prior answering of a call, say 'yes'\n");
1167         fprintf(fp,"# will cause the call to be billed after playing the announcement. (yes or no)\n");
1168         fprintf(fp,"vbox_free       %s\n\n",(ext->vbox_free)?"yes":"no");
1169
1170         fprintf(fp,"# Accept incoming data calls as it would be an audio call.\n");
1171         fprintf(fp,"datacall        %s\n\n",ext_yesno[ext->datacall]);
1172
1173         fprintf(fp,"# Include seconds (time) in the connect message. (Should be always enabled.)\n");
1174         fprintf(fp,"seconds         %s\n\n",ext_yesno[1-ext->no_seconds]);
1175
1176         fprintf(fp,"# Identity string for VoOTP encryption\n");
1177         fprintf(fp,"otp-ident       %s\n\n", ext->otp_ident);
1178
1179         fprintf(fp,"# Last outgoing and incoming numbers (including prefix)\n");
1180         i = 0;
1181         while(i < MAX_REMEMBER) {
1182                 if (ext->last_out[i][0])
1183                         fprintf(fp,"last_out        %s\n",ext->last_out[i]);
1184                 i++;
1185         }
1186         i = 0;
1187         while(i < MAX_REMEMBER) {
1188                 if (ext->last_in[i][0])
1189                         fprintf(fp,"last_in         %s\n",ext->last_in[i]);
1190                 i++;
1191         }
1192         fprintf(fp,"\n");
1193
1194         fprintf(fp,"# Identify to/from remove via Data-Over-Voice feature.\n");
1195         fprintf(fp,"dov_ident       %s\n", ext->dov_ident);
1196         fprintf(fp,"dov_log         %s\n", ext->dov_log);
1197         switch(ext->dov_type) {
1198                 case DOV_TYPE_PWM:
1199                 fprintf(fp,"dov_type        pwm\n");
1200                 break;
1201                 case DOV_TYPE_PCM:
1202                 fprintf(fp,"dov_type        pcm\n");
1203                 break;
1204         }
1205         fprintf(fp,"dov_level       %d\n\n", ext->dov_level);
1206
1207         if (fp) fclose(fp);
1208         return(1);
1209 }
1210
1211
1212 /* write log for extension
1213  *
1214  */
1215 int write_log(char *number, char *callerid, char *calledid, time_t start, time_t stop, int aoce, int cause, int location)
1216 {
1217         const char *mon[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
1218         FILE *fp=NULL;
1219         char filename[256];
1220         struct tm *tm;
1221
1222         if (callerid[0] == '\0')
1223                 callerid = (char *)"<unknown>";
1224
1225         SPRINT(filename, "%s/%s/log", EXTENSION_DATA, number);
1226
1227         if (!(fp = fopen(filename, "a"))) {
1228                 PERROR("Cannot open log: \"%s\"\n", filename);
1229                 return(0);
1230         }
1231
1232         tm = localtime(&start);
1233         fprintf(fp,"%s %2d %04d %02d:%02d:%02d %s", mon[tm->tm_mon], tm->tm_mday, tm->tm_year+1900, tm->tm_hour, tm->tm_min, tm->tm_sec, number);
1234         if (stop)
1235                 fprintf(fp," %2ld:%02d:%02d", (stop-start)/3600, (((unsigned int)(stop-start))/60)%60, ((unsigned int)(stop-start))%60);
1236         else
1237                 fprintf(fp," --:--:--");
1238         fprintf(fp," %s -> %s", callerid, calledid);
1239         if (cause >= 1 && cause <=127 && location>=0 && location<=15)
1240                 fprintf(fp," (cause=%d '%s' location=%d '%s')", cause, isdn_cause[cause].german, location, isdn_location[location].german);
1241         fprintf(fp,"\n");
1242
1243         if (fp) fclose(fp);
1244         return(1);
1245 }
1246
1247
1248 /* parse phonebook
1249  *
1250  * reads phone book of extextension and compares the given elements which
1251  * are: abreviation, phone number, name (name is not compared)
1252  * on success a 1 is returned and the pointers of elements are set to the
1253  * result.
1254  */
1255 int parse_phonebook(char *number, char **abbrev_pointer, char **phone_pointer, char **name_pointer)
1256 {
1257         FILE *fp=NULL;
1258         char filename[256];
1259         char *p;
1260         static char abbrev[32], phone[256], name[256];
1261         unsigned int line,i;
1262         char buffer[1024];
1263         int found = 0, found_if_more_digits = 0;
1264
1265         SPRINT(filename, "%s/%s/phonebook", EXTENSION_DATA, number);
1266
1267         if (!(fp = fopen(filename, "r"))) {
1268                 PERROR("Cannot open phonebook: \"%s\"\n", filename);
1269                 return(0);
1270         }
1271
1272         line=0;
1273         while((GETLINE(buffer, fp))) {
1274                 line++;
1275                 p = buffer;
1276
1277                 while(*p <= 32) { /* skip spaces */
1278                         if (*p == 0)
1279                                 break;
1280                         p++;
1281                 }
1282                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1283                         continue;
1284
1285                 abbrev[0]=0;
1286                 phone[0]=0;
1287                 name[0]=0;
1288
1289                 i=0; /* read abbrev */
1290                 while(*p > 32) {
1291                         if (i+1 >= sizeof(abbrev)) {
1292                                 PERROR_RUNTIME("Error in %s (line %d): abbrev too long.\n",filename,line);
1293                                 break;
1294                         }
1295                         abbrev[i+1] = '\0';
1296                         abbrev[i++] = *p++;
1297                 }
1298
1299                 while(*p <= 32) { /* skip spaces */
1300                         if (*p == 0)
1301                                 break;
1302                         p++;
1303                 }
1304
1305                 if (*p!=0 && *p!='#') { /* phone */
1306                         i=0; /* read phone */
1307                         while(*p > 32) {
1308                                 if (i+1 >= sizeof(phone)) {
1309                                         PERROR_RUNTIME("Error in %s (line %d): phone too long.\n",filename,line);
1310                                         break;
1311                                 }
1312                                 phone[i+1] = '\0';
1313                                 phone[i++] = *p++;
1314                         }
1315                         while(*p <= 32) { /* skip spaces */
1316                                 if (*p == 0)
1317                                         break;
1318                                 p++;
1319                         }
1320                 }
1321
1322                 if (*p!=0 && *p!='#') { /* name */
1323                         i=0; /* read name */
1324                         while(*p > 0) {
1325                                 if (i+1 >= sizeof(name)) {
1326                                         PERROR_RUNTIME("Error in %s (line %d): name too long.\n",filename,line);
1327                                         break;
1328                                 }
1329                                 name[i+1] = '\0';
1330                                 name[i++] = *p++;
1331                         }
1332                 }
1333
1334                 if (*abbrev_pointer) {
1335                         if (!strncmp(*abbrev_pointer, abbrev, strlen(*abbrev_pointer))) {
1336                                 /* may match if abbreviation is longer */
1337                                 found_if_more_digits = 1;
1338                         }
1339                         if (!!strcasecmp(*abbrev_pointer, abbrev))
1340                                 continue;
1341                 }
1342                 if (*phone_pointer)
1343                         if (!!strcasecmp(*phone_pointer, phone))
1344                                 continue;
1345                 if (*name_pointer)
1346                         if (!!strcasecmp(*name_pointer, name))
1347                                 continue;
1348
1349                 found = 1;
1350                 break; /* found entry */
1351         }
1352
1353         if (fp) fclose(fp);
1354
1355         if (found) {
1356                 *abbrev_pointer = abbrev;
1357                 *phone_pointer = phone;
1358                 *name_pointer = name;
1359         }
1360
1361         if (found == 0) {
1362                 if (found_if_more_digits)
1363                         found = -1;
1364         }
1365         return(found);
1366 }
1367
1368 /* parsing secrets file
1369  *
1370  * 'number' specifies the externsion number, not the caller id
1371  * 'remote_id' specifies the dialed number, or the caller id for incoming calls
1372  * the result is the auth, crypt and key string, and 1 is returned.
1373  * on failure or not matching number, the 0 is returned
1374  */
1375 int parse_secrets(char *number, char *remote_id, char **auth_pointer, char **crypt_pointer, char **key_pointer)
1376 {
1377         FILE *fp=NULL;
1378         char filename[256];
1379         char *p;
1380         char remote[128];
1381         static char auth[64], crypt[64], key[4096];
1382         unsigned int line,i;
1383         char buffer[4096];
1384         int found = 0;
1385
1386         SPRINT(filename, "%s/%s/secrets", EXTENSION_DATA, number);
1387
1388         if (!(fp = fopen(filename, "r"))) {
1389                 PERROR("Cannot open secrets: \"%s\"\n", filename);
1390                 return(0);
1391         }
1392
1393         line=0;
1394         while((GETLINE(buffer, fp))) {
1395                 line++;
1396                 p = buffer;
1397
1398                 while(*p <= 32) { /* skip spaces */
1399                         if (*p == 0)
1400                                 break;
1401                         p++;
1402                 }
1403                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1404                         continue;
1405
1406                 remote[0]=0;
1407                 auth[0]=0;
1408                 crypt[0]=0;
1409                 key[0]=0;
1410
1411                 i=0; /* read auth */
1412                 while(*p > 32) {
1413                         if (i+1 >= sizeof(remote)) {
1414                                 PERROR_RUNTIME("Error in %s (line %d): remote too long.\n",filename,line);
1415                                 break;
1416                         }
1417                         remote[i+1] = '\0';
1418                         remote[i++] = *p++;
1419                 }
1420
1421                 while(*p <= 32) { /* skip spaces */
1422                         if (*p == 0)
1423                                 break;
1424                         p++;
1425                 }
1426
1427                 if (*p!=0 && *p!='#') { /* auth */
1428                         i=0; /* read auth */
1429                         while(*p > 32) {
1430                                 if (i+1 >= sizeof(auth)) {
1431                                         PERROR_RUNTIME("Error in %s (line %d): auth too long.\n",filename,line);
1432                                         break;
1433                                 }
1434                                 auth[i+1] = '\0';
1435                                 auth[i++] = *p++;
1436                         }
1437                         while(*p <= 32) { /* skip spaces */
1438                                 if (*p == 0)
1439                                         break;
1440                                 p++;
1441                         }
1442                 }
1443
1444                 if (*p!=0 && *p!='#') { /* crypt */
1445                         i=0; /* read crypt */
1446                         while(*p > 32) {
1447                                 if (i+1 >= sizeof(crypt)) {
1448                                         PERROR_RUNTIME("Error in %s (line %d): crypt too long.\n",filename,line);
1449                                         break;
1450                                 }
1451                                 crypt[i+1] = '\0';
1452                                 crypt[i++] = *p++;
1453                         }
1454                         while(*p <= 32) { /* skip spaces */
1455                                 if (*p == 0)
1456                                         break;
1457                                 p++;
1458                         }
1459                 }
1460
1461                 if (*p!=0 && *p!='#') { /* key */
1462                         i=0; /* read key */
1463                         while(*p > 0) {
1464                                 if (i+1 >= sizeof(key)) {
1465                                         PERROR_RUNTIME("Error in %s (line %d): key too long.\n",filename,line);
1466                                         break;
1467                                 }
1468                                 key[i+1] = '\0';
1469                                 key[i++] = *p++;
1470                         }
1471                 }
1472 //printf("COMPARING: '%s' with '%s' %s %s %s\n", remote_id, remote, auth, crypt, key);
1473
1474                 if (!!strcasecmp(remote, remote_id))
1475                         continue;
1476
1477                 found = 1;
1478                 break; /* found entry */
1479         }
1480
1481         if (fp) fclose(fp);
1482
1483         if (found) {
1484                 *auth_pointer = auth;
1485                 *crypt_pointer = crypt;
1486                 *key_pointer = key;
1487         }
1488
1489         return(found);
1490 }
1491
1492 /* parse directory
1493  *
1494  * the caller id is given and the name is returned. if the name is not found,
1495  * NULL is returned.
1496  * on success a 1 is returned and the pointers of elements are set to the
1497  * result.
1498  */
1499 char *parse_directory(char *number, int type)
1500 {
1501         FILE *fp=NULL;
1502         char filename[256];
1503         char *p;
1504         static char phone[32], name[64];
1505         unsigned int line,i;
1506         char buffer[256];
1507         int found = 0;
1508
1509         SPRINT(filename, "%s/directory.list", CONFIG_DATA);
1510
1511         if (!(fp = fopen(filename, "r"))) {
1512                 PERROR("Cannot open directory: \"%s\"\n", filename);
1513                 return(NULL);
1514         }
1515
1516         line=0;
1517         while((GETLINE(buffer, fp))) {
1518                 line++;
1519                 p = buffer;
1520
1521                 while(*p <= 32) { /* skip spaces */
1522                         if (*p == 0)
1523                                 break;
1524                         p++;
1525                 }
1526                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1527                         continue;
1528
1529                 phone[0]=0;
1530                 name[0]=0;
1531
1532                 i=0; /* read number */
1533                 while(*p > 32) {
1534                         if (i+1 >= sizeof(phone)) {
1535                                 PERROR_RUNTIME("Error in %s (line %d): number too long.\n",filename,line);
1536                                 break;
1537                         }
1538                         phone[i+1] = '\0';
1539                         phone[i++] = *p++;
1540                 }
1541
1542                 while(*p <= 32) { /* skip spaces */
1543                         if (*p == 0)
1544                                 break;
1545                         p++;
1546                 }
1547
1548                 i=0; /* read name */
1549                 while(*p >= 32) {
1550                         if (i+1 >= sizeof(name)) {
1551                                 PERROR_RUNTIME("Error in %s (line %d): name too long.\n",filename,line);
1552                                 break;
1553                         }
1554                         name[i+1] = '\0';
1555                         name[i++] = *p++;
1556                 }
1557
1558                 if (phone[0] == 'i') {
1559                         if (type != INFO_NTYPE_INTERNATIONAL)
1560                                 continue;
1561                         if (!strcmp(number, phone+1)) {
1562                                 found = 1;
1563                                 break;
1564                         }
1565                         continue;
1566                 }
1567                 if (phone[0] == 'n') {
1568                         if (type != INFO_NTYPE_NATIONAL)
1569                                 continue;
1570                         if (!strcmp(number, phone+1)) {
1571                                 found = 1;
1572                                 break;
1573                         }
1574                         continue;
1575                 }
1576                 if (phone[0] == 's') {
1577                         if (type==INFO_NTYPE_NATIONAL || type==INFO_NTYPE_INTERNATIONAL)
1578                                 continue;
1579                         if (!strcmp(number, phone+1)) {
1580                                 found = 1;
1581                                 break;
1582                         }
1583                         continue;
1584                 }
1585                 if (!strncmp(phone, options.international, strlen(options.international))) {
1586                         if (type != INFO_NTYPE_INTERNATIONAL)
1587                                 continue;
1588                         if (!strcmp(number, phone+strlen(options.international))) {
1589                                 found = 1;
1590                                 break;
1591                         }
1592                         continue;
1593                 }
1594                 if (!options.national[0]) { /* no national prefix */
1595                         if (type == INFO_NTYPE_INTERNATIONAL)
1596                                 continue;
1597                         if (!strcmp(number, phone)) {
1598                                 found = 1;
1599                                 break;
1600                         }
1601                         continue;
1602                 }
1603                 if (!strncmp(phone, options.national, strlen(options.national))) {
1604                         if (type != INFO_NTYPE_NATIONAL)
1605                                 continue;
1606                         if (!strcmp(number, phone+strlen(options.national))) {
1607                                 found = 1;
1608                                 break;
1609                         }
1610                         continue;
1611                 }
1612                 if (type==INFO_NTYPE_NATIONAL || type==INFO_NTYPE_INTERNATIONAL)
1613                         continue;
1614                 if (!strcmp(number, phone)) {
1615                         found = 1;
1616                         break;
1617                 }
1618         }
1619
1620         if (fp) fclose(fp);
1621
1622         if (found)
1623                 return(name);
1624         else
1625                 return(NULL);
1626 }
1627
1628 /* parse callbackauth
1629  *
1630  * searches for the given caller id and returns 1 == true or 0 == false
1631  */
1632 int parse_callbackauth(char *number, struct caller_info *callerinfo)
1633 {
1634         FILE *fp = NULL;
1635         char filename[256];
1636         char *p;
1637         unsigned int line,i;
1638         char buffer[256];
1639         static char caller_type[32], caller_id[64];
1640         int found = 0;
1641
1642         SPRINT(filename, "%s/%s/callbackauth", EXTENSION_DATA, number);
1643
1644         if (!(fp = fopen(filename, "r"))) {
1645                 PDEBUG(DEBUG_EPOINT, "Cannot open callbackauth: \"%s\"\n", filename);
1646                 return(0);
1647         }
1648
1649         line=0;
1650         while((GETLINE(buffer, fp))) {
1651                 line++;
1652                 p = buffer;
1653
1654                 while(*p <= 32) { /* skip spaces */
1655                         if (*p == 0)
1656                                 break;
1657                         p++;
1658                 }
1659                 if (*p==0 || *p=='#') /* ignore comments and empty line */
1660                         continue;
1661
1662                 caller_type[0]=0;
1663                 caller_id[0]=0;
1664
1665                 i=0; /* read caller_type */
1666                 while(*p > 32) {
1667                         if (i+1 >= sizeof(caller_type)) {
1668                                 PERROR_RUNTIME("Error in %s (line %d): caller_type too long.\n",filename,line);
1669                                 break;
1670                         }
1671                         caller_type[i+1] = '\0';
1672                         caller_type[i++] = *p++;
1673                 }
1674
1675                 while(*p <= 32) { /* skip spaces */
1676                         if (*p == 0)
1677                                 break;
1678                         p++;
1679                 }
1680
1681                 if (*p!=0 && *p!='#') { /* caller_id */
1682                         i=0; /* read caller_id */
1683                         while(*p > 32) {
1684                                 if (i+1 >= sizeof(caller_id)) {
1685                                         PERROR_RUNTIME("Error in %s (line %d): caller_id too long.\n",filename,line);
1686                                         break;
1687                                 }
1688                                 caller_id[i+1] = '\0';
1689                                 caller_id[i++] = *p++;
1690                         }
1691                         // ignoring more
1692                 }
1693
1694                 if (caller_type[0]=='\0' && caller_id[0]=='\0')
1695                         continue;
1696
1697                 if (atoi(caller_type) != callerinfo->ntype)
1698                         continue;
1699
1700                 if (!!strcmp(caller_id, callerinfo->id))
1701                         continue;
1702
1703                 found = 1;
1704                 break; /* found entry */
1705         }
1706
1707         if (fp) fclose(fp);
1708
1709         if (found)
1710                 return(1);
1711         return(0);
1712 }
1713
1714
1715 /* append line to callbackauth
1716  *
1717  */
1718 void append_callbackauth(char *number, struct caller_info *callerinfo)
1719 {
1720         FILE *fp = NULL;
1721         char filename[256];
1722
1723         SPRINT(filename, "%s/%s/callbackauth", EXTENSION_DATA, number);
1724
1725         if (callerinfo->id[0]=='\0') {
1726                 PERROR("caller has no id.\n");
1727                 return;
1728         }
1729         if (!(fp = fopen(filename, "a"))) {
1730                 PERROR("Cannot open callbackauth: \"%s\"\n", filename);
1731                 return;
1732         }
1733
1734         fprintf(fp, "%6d  %s\n", callerinfo->ntype, callerinfo->id);
1735
1736         fclose(fp);
1737
1738 }
1739
1740