a3a33c8c6685c5cfcef9fe23aff9856dec9bdb15
[lcr.git] / port.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** port                                                                      **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include "main.h"
21
22 #define BETTERDELAY
23
24 //#define MIXER_DEBUG /* debug mixer buffer overflow and underrun */
25
26 class Port *port_first = NULL;
27
28 unsigned long port_serial = 1; /* must be 1, because 0== no port */
29
30
31 /* free epointlist relation
32  */
33 void Port::free_epointlist(struct epoint_list *epointlist)
34 {
35         struct epoint_list *temp, **tempp;
36
37         temp = p_epointlist;
38         tempp = &p_epointlist;
39         while(temp)
40         {
41                 if (temp == epointlist)
42                         break;
43
44                 tempp = &temp->next;
45                 temp = temp->next;
46         }
47         if (temp == 0)
48         {
49                 PERROR("SOFTWARE ERROR: epointlist not in port's list.\n");
50                 return;
51         }
52         /* detach */
53         *tempp=temp->next;
54
55         /* free */
56         PDEBUG(DEBUG_EPOINT, "PORT(%d) removed epoint from port\n", p_serial);
57         memset(temp, 0, sizeof(struct epoint_list));
58         free(temp);
59         ememuse--;
60 }
61
62
63 void Port::free_epointid(unsigned long epoint_id)
64 {
65         struct epoint_list *temp, **tempp;
66
67         temp = p_epointlist;
68         tempp = &p_epointlist;
69         while(temp)
70         {
71                 if (temp->epoint_id == epoint_id)
72                         break;
73
74                 tempp = &temp->next;
75                 temp = temp->next;
76         }
77         if (temp == 0)
78         {
79                 PERROR("epoint_id not in port's list, exitting.\n");
80                 return;
81         }
82         /* detach */
83         *tempp=temp->next;
84
85         /* free */
86         PDEBUG(DEBUG_EPOINT, "PORT(%d) removed epoint from port\n", p_serial);
87         memset(temp, 0, sizeof(struct epoint_list));
88         free(temp);
89         ememuse--;
90 }
91
92
93 /* create new epointlist relation
94  */
95 struct epoint_list *Port::epointlist_new(unsigned long epoint_id)
96 {
97         struct epoint_list *epointlist, **epointlistpointer;
98
99         /* epointlist structure */
100         epointlist = (struct epoint_list *)calloc(1, sizeof(struct epoint_list));
101         if (!epointlist)
102         {
103                 PERROR("no mem for allocating epoint_list\n");
104                 return(0);
105         }
106         ememuse++;
107         PDEBUG(DEBUG_EPOINT, "PORT(%d) allocating epoint_list.\n", p_serial);
108         memset(epointlist, 0, sizeof(struct epoint_list));
109
110         /* add epoint_list to chain */
111         epointlist->next = NULL;
112         epointlistpointer = &p_epointlist;
113         while(*epointlistpointer)
114                 epointlistpointer = &((*epointlistpointer)->next);
115         *epointlistpointer = epointlist;
116
117         /* link to epoint */
118         epointlist->epoint_id = epoint_id;
119         epointlist->active = 1;
120
121         return(epointlist);
122 }
123
124
125 /*
126  * port constructor
127  */
128 Port::Port(int type, char *portname, struct port_settings *settings)
129 {
130         class Port *temp, **tempp;
131
132         PDEBUG(DEBUG_PORT, "new port of type %d, name '%s'\n", type, portname);
133
134         /* initialize object */
135         if (settings)
136                 memcpy(&p_settings, settings, sizeof(struct port_settings));
137         else
138         {
139                 memset(&p_settings, 0, sizeof(p_settings));
140                 SCPY(p_settings.tones_dir, options.tones_dir);
141         }
142         SCPY(p_name, portname);
143         SCPY(p_tone_dir, p_settings.tones_dir); // just to be sure
144         p_clock = 0;
145         p_type = type;
146         p_serial = port_serial++;
147         p_debug_nothingtosend = 0;
148         p_tone_fh = -1;
149         p_tone_fetched = NULL;
150         p_tone_name[0] = '\0';
151 //      p_knock_fh = -1;
152 //      p_knock_fetched = NULL;
153         p_state = PORT_STATE_IDLE;
154         p_epointlist = NULL;
155         memset(&p_callerinfo, 0, sizeof(p_callerinfo));
156         memset(&p_dialinginfo, 0, sizeof(p_dialinginfo));
157         memset(&p_connectinfo, 0, sizeof(p_connectinfo));
158         memset(&p_redirinfo, 0, sizeof(p_redirinfo));
159         memset(&p_capainfo, 0, sizeof(p_capainfo));
160         memset(p_mixer_buffer, 0, sizeof(p_mixer_buffer));
161         memset(p_record_buffer, 0, sizeof(p_record_buffer));
162         memset(p_stereo_buffer, 0, sizeof(p_stereo_buffer));
163         p_mixer_rel = NULL;
164         p_mixer_readp = 0;
165         p_echotest = 0;
166         next = NULL;
167         p_record = NULL;
168         p_record_type = 0;
169         p_record_length = 0;
170         p_record_filename[0] = '\0';
171
172         /* append port to chain */
173         temp = port_first;
174         tempp = &port_first;
175         while(temp)
176         {
177                 tempp = &temp->next;
178                 temp = temp->next;
179         }
180         *tempp = this;
181
182         classuse++;
183 }
184
185
186 /*
187  * port destructor
188  */
189 Port::~Port(void)
190 {
191         struct mixer_relation *relation, *rtemp;
192         class Port *temp, **tempp;
193         struct message *message;
194
195         if (p_record)
196                 close_record(0);
197
198         classuse--;
199
200         PDEBUG(DEBUG_PORT, "removing port of type %d, name '%s'\n", p_type, p_name);
201
202         /* free mixer relation chain */
203         relation = p_mixer_rel;
204         while(relation)
205         {
206                 rtemp = relation;
207                 relation = relation->next;
208                 memset(rtemp, 0, sizeof(struct mixer_relation));
209                 free(rtemp);
210                 pmemuse--;
211         }
212         p_mixer_rel = NULL; /* beeing paranoid */
213
214         /* disconnect port from endpoint */
215         while(p_epointlist)
216         {
217                 /* send disconnect */
218                 message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
219                 message->param.disconnectinfo.cause = 16;
220                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
221                 message_put(message);
222                 /* remove endpoint */
223                 free_epointlist(p_epointlist);
224         }
225
226         /* remove port from chain */
227         temp=port_first;
228         tempp=&port_first;
229         while(temp)
230         {
231                 if (temp == this)
232                         break;
233                 tempp = &temp->next;
234                 temp = temp->next;
235         }
236         if (temp == NULL)
237         {
238                 PERROR("PORT(%s) port not in port's list.\n", p_name);
239                 exit(-1);
240         }
241         /* detach */
242         *tempp=this->next;
243
244         /* close open tones file */
245         if (p_tone_fh >= 0)
246         {
247                 close(p_tone_fh);
248                 p_tone_fh = -1;
249                 fhuse--;
250         }
251         p_tone_fetched = NULL;
252 }
253
254 PORT_STATE_NAMES
255
256 /* set new endpoint state
257  */
258 void Port::new_state(int state)
259 {
260         PDEBUG(DEBUG_PORT, "PORT(%s) new state %s --> %s\n", p_name, state_name[p_state], state_name[state]);
261         p_state = state;
262 }
263
264
265 /*
266  * find the port with port_id
267  */ 
268 class Port *find_port_id(unsigned long port_id)
269 {
270         class Port *port = port_first;
271
272         while(port)
273         {
274 //printf("comparing: '%s' with '%s'\n", name, port->name);
275                 if (port->p_serial == port_id)
276                         return(port);
277                 port = port->next;
278         }
279
280         return(NULL);
281 }
282
283
284 /*
285  * set echotest
286  */
287 void Port::set_echotest(int echotest)
288 {
289         p_echotest = echotest;
290 }
291
292
293 /*
294  * set the file in the tone directory with the given name
295  */
296 void Port::set_tone(char *dir, char *name)
297 {
298         int fh;
299         char filename[128];
300
301         if (name == NULL)
302                 name = "";
303
304         /* no counter, no eof, normal speed */
305         p_tone_counter = 0;
306         p_tone_eof = 0;
307         p_tone_speed = 1;
308         p_tone_codec = CODEC_LAW;
309
310         if (p_tone_fh >= 0)
311         {
312                 close(p_tone_fh);
313                 p_tone_fh = -1;
314                 fhuse--;
315         }
316         p_tone_fetched = NULL;
317
318         if (name[0])
319         {
320                 if (name[0] == '/')
321                 {
322                         SPRINT(p_tone_name, "%s", name);
323                         p_tone_dir[0] = '\0';
324                 } else
325                 {
326                         SCPY(p_tone_dir, dir);
327                         SCPY(p_tone_name, name);
328                 }
329         } else
330         {
331                 p_tone_name[0]= '\0';
332                 p_tone_dir[0]= '\0';
333                 return;
334         }
335
336         if (!!strncmp(name,"cause_",6))
337                 return;
338
339         /* now we check if the cause exists, otherwhise we use error tone. */
340         if ((p_tone_fetched=open_tone_fetched(p_tone_dir, p_tone_name, &p_tone_codec, 0, 0)))
341         {
342                 p_tone_fetched = NULL;
343                 return;
344         }
345         SPRINT(filename, "%s_loop", p_tone_name);
346         if ((p_tone_fetched=open_tone_fetched(p_tone_dir, filename, &p_tone_codec, 0, 0)))
347         {
348                 p_tone_fetched = NULL;
349                 return;
350         }
351         SPRINT(filename, "%s/%s/%s", INSTALL_DATA, p_tone_dir, p_tone_name);
352         if ((fh=open_tone(filename, &p_tone_codec, 0, 0)) >= 0)
353         {
354                 close(fh);
355                 return;
356         }
357         SPRINT(filename, "%s/%s/%s_loop", INSTALL_DATA, p_tone_dir, p_tone_name);
358         if ((fh=open_tone(filename, &p_tone_codec, 0, 0)) >= 0)
359         {
360                 close(fh);
361                 return;
362         }
363
364         if (!strcmp(name,"cause_00") || !strcmp(name,"cause_10"))
365         {
366                 PDEBUG(DEBUG_PORT, "PORT(%s) Given Cause 0x%s has no tone, using release tone\n", p_name, name+6);
367                 SPRINT(p_tone_name,"release");
368         } else
369         if (!strcmp(name,"cause_11"))
370         {
371                 PDEBUG(DEBUG_PORT, "PORT(%s) Given Cause 0x%s has no tone, using busy tone\n", p_name, name+6);
372                 SPRINT(p_tone_name,"busy");
373         } else
374         {
375                 PDEBUG(DEBUG_PORT, "PORT(%s) Given Cause 0x%s has no tone, using error tone\n", p_name, name+6);
376                 SPRINT(p_tone_name,"error");
377         }
378 }
379
380
381 /*
382  * set the file in the tone directory for vbox playback
383  * also set the play_eof-flag
384  */
385 void Port::set_vbox_tone(char *dir, char *name)
386 {
387         char filename[256];
388
389         p_tone_speed = 1;
390         p_tone_counter = 0;
391         p_tone_codec = CODEC_LAW;
392         p_tone_eof = 1;
393
394         if (p_tone_fh >= 0)
395         {
396                 close(p_tone_fh);
397                 p_tone_fh = -1;
398                 fhuse--;
399         }
400         p_tone_fetched = NULL;
401
402         SPRINT(p_tone_dir,  dir);
403         SPRINT(p_tone_name,  name);
404
405         /* now we check if the cause exists, otherwhise we use error tone. */
406         if (p_tone_dir[0])
407         {
408                 if ((p_tone_fetched=open_tone_fetched(p_tone_dir, p_tone_name, &p_tone_codec, &p_tone_size, &p_tone_left)))
409                 {
410                         PDEBUG(DEBUG_PORT, "PORT(%s) opening fetched tone: %s\n", p_name, p_tone_name);
411                         return;
412                 }
413                 SPRINT(filename, "%s/%s/%s", INSTALL_DATA, p_tone_dir, p_tone_name);
414                 if ((p_tone_fh=open_tone(filename, &p_tone_codec, &p_tone_size, &p_tone_left)) >= 0)
415                 {
416                         fhuse++;
417                         PDEBUG(DEBUG_PORT, "PORT(%s) opening tone: %s\n", p_name, filename);
418                         return;
419                 }
420         } else
421         {
422                 SPRINT(filename, "%s", p_tone_name);
423                 if ((p_tone_fh=open_tone(filename, &p_tone_codec, &p_tone_size, &p_tone_left)) >= 0)
424                 {
425                         fhuse++;
426                         PDEBUG(DEBUG_PORT, "PORT(%s) opening tone: %s\n", p_name, filename);
427                         return;
428                 }
429         }
430 }
431
432
433 /*
434  * set the file in the given directory for vbox playback
435  * also set the eof-flag
436  * also set the counter-flag
437  */
438 void Port::set_vbox_play(char *name, int offset)
439 {
440         signed long size;
441         struct message *message;
442
443         /* use ser_box_tone() */
444         set_vbox_tone("", name);
445         if (p_tone_fh < 0)
446                 return;
447
448         /* enable counter */
449         p_tone_counter = 1;
450
451         /* seek */
452         if (p_tone_name[0])
453         {
454                 /* send message with counter value */
455                 if (p_tone_size>=0 && ACTIVE_EPOINT(p_epointlist))
456                 {
457                         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TONE_COUNTER);
458                         message->param.counter.current = offset;
459                         message->param.counter.max = size;
460                         message_put(message);
461                 }
462         }
463 }
464
465
466 /*
467  * set the playback speed (for recording playback with different speeds)
468  */
469 void Port::set_vbox_speed(int speed)
470 {
471         /* enable vbox play mode */
472         p_tone_speed = speed;
473 }
474
475 /*
476  * read from the given file as specified in port_set_tone and return sample data
477  */
478 int Port::read_audio(unsigned char *buffer, int length)
479 {
480         int l,len;
481         int readp;
482         int nodata=0; /* to detect 0-length files and avoid endless reopen */
483         char filename[128];
484         int tone_left_before; /* temp variable to determine the change in p_tone_left */
485
486         /* nothing */
487         if (length == 0)
488                 return(0);
489
490         len = length;
491         codec_in = p_tone_codec;
492
493         /* if there is no tone set, use silence */
494         if (p_tone_name[0] == 0)
495         {
496 rest_is_silence:
497                 memset(buffer, (options.law=='a')?0x2a:0xff, len); /* silence */
498                 goto done;
499         }
500
501         /* if the file pointer is not open, we open it */
502         if (p_tone_fh<0 && p_tone_fetched==NULL)
503         {
504                 if (p_tone_dir[0])
505                 {
506                         SPRINT(filename, "%s", p_tone_name);
507                         /* if file does not exist */
508                         if (!(p_tone_fetched=open_tone_fetched(p_tone_dir, filename, &p_tone_codec, &p_tone_size, &p_tone_left)))
509                         {
510                                 SPRINT(filename, "%s/%s/%s", INSTALL_DATA, p_tone_dir, p_tone_name);
511                                 /* if file does not exist */
512                                 if ((p_tone_fh=open_tone(filename, &p_tone_codec, &p_tone_size, &p_tone_left)) < 0)
513                                 {
514                                         PDEBUG(DEBUG_PORT, "PORT(%s) no tone: %s\n", p_name, filename);
515                                         goto try_loop;
516                                 }
517                                 fhuse++;
518                         }
519                 } else
520                 {
521                         SPRINT(filename, "%s", p_tone_name);
522                         /* if file does not exist */
523                         if ((p_tone_fh=open_tone(filename, &p_tone_codec, &p_tone_size, &p_tone_left)) < 0)
524                         {
525                                 PDEBUG(DEBUG_PORT, "PORT(%s) no tone: %s\n", p_name, filename);
526                                 goto try_loop;
527                         }
528                         fhuse++;
529                 }
530                 PDEBUG(DEBUG_PORT, "PORT(%s) opening %stone: %s\n", p_name, p_tone_fetched?"fetched ":"", filename);
531         }
532
533 read_more:
534         /* file descriptor is open read data */
535         tone_left_before = p_tone_left;
536         if (p_tone_fh >= 0)
537         {
538                 l = read_tone(p_tone_fh, buffer, p_tone_codec, len, p_tone_size, &p_tone_left, p_tone_speed);
539                 if (l<0 || l>len) /* paranoia */
540                         l=0;
541                 buffer += l;
542                 len -= l;
543         }
544         if (p_tone_fetched)
545         {
546                 l = read_tone_fetched(&p_tone_fetched, buffer, len, p_tone_size, &p_tone_left, p_tone_speed);
547                 if (l<0 || l>len) /* paranoia */
548                         l=0;
549                 buffer += l;
550                 len -= l;
551         }
552
553         /* if counter is enabled, we check if we have a change */
554         if (p_tone_counter && p_tone_size>=0 && ACTIVE_EPOINT(p_epointlist))
555         {
556                 /* if we jumed to the next second */
557                 if (((p_tone_size-p_tone_left)/8000) != (p_tone_size-tone_left_before)/8000)
558                 {
559 //printf("\nsize=%d left=%d\n\n",p_tone_size,p_tone_left);
560                         struct message *message;
561                         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TONE_COUNTER);
562                         message->param.counter.current = (p_tone_size-p_tone_left)/8000;
563                         message->param.counter.max = -1;
564                         message_put(message);
565                 }
566         }
567
568         if (len==0)
569                 goto done;
570
571         if (p_tone_fh >= 0)
572         {
573                 close(p_tone_fh);
574                 p_tone_fh = -1;
575                 fhuse--;
576         }
577         p_tone_fetched = NULL;
578
579         if (l)
580                 nodata=0;
581
582         /* if the file has 0-length */
583         if (nodata>1)
584         {
585                 PDEBUG(DEBUG_PORT, "PORT(%s) 0-length loop: %s\n", p_name, filename);
586                 p_tone_name[0]=0;
587                 p_tone_dir[0]=0;
588                 goto rest_is_silence;
589         }
590
591         /* if eof is reached, or if the normal file cannot be opened, continue with the loop file if possible */
592 try_loop:
593         if (p_tone_eof && ACTIVE_EPOINT(p_epointlist))
594         {
595                 struct message *message;
596                 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_TONE_EOF);
597                 message_put(message);
598         }
599
600         if (p_tone_dir[0])
601         {
602                 /* if file does not exist */
603                 SPRINT(filename, "%s_loop", p_tone_name);
604                 if (!(p_tone_fetched=open_tone_fetched(p_tone_dir, filename, &p_tone_codec, &p_tone_size, &p_tone_left)))
605                 {
606                         SPRINT(filename, "%s/%s/%s_loop", INSTALL_DATA, p_tone_dir, p_tone_name);
607                         /* if file does not exist */
608                         if ((p_tone_fh=open_tone(filename, &p_tone_codec, &p_tone_size, &p_tone_left)) < 0)
609                         {
610                                 PDEBUG(DEBUG_PORT, "PORT(%s) no tone loop: %s\n",p_name, filename);
611                                 p_tone_dir[0] = '\0';
612                                 p_tone_name[0] = '\0';
613                 //              codec_in = CODEC_LAW;
614                                 goto rest_is_silence;
615                         }
616                         fhuse++;
617                 }
618         } else
619         {
620                 SPRINT(filename, "%s_loop", p_tone_name);
621                 /* if file does not exist */
622                 if ((p_tone_fh=open_tone(filename, &p_tone_codec, &p_tone_size, &p_tone_left)) < 0)
623                 {
624                         PDEBUG(DEBUG_PORT, "PORT(%s) no tone loop: %s\n",p_name, filename);
625                         p_tone_dir[0] = '\0';
626                         p_tone_name[0] = '\0';
627         //              codec_in = CODEC_LAW;
628                         goto rest_is_silence;
629                 }
630                 fhuse++;
631         }
632         nodata++;
633         PDEBUG(DEBUG_PORT, "PORT(%s) opening %stone: %s\n", p_name, p_tone_fetched?"fetched ":"", filename);
634
635         /* now we have opened the loop */
636         goto read_more;
637
638 done:
639         return(length);
640 }
641
642
643 /* port handler:
644  * process transmission clock */
645 int Port::handler(void)
646 {
647         port
648
649         return(0);
650 }
651
652 /* endpoint sends messages to the port
653  * this is called by the message_epoint inherited by child classes
654  * therefor a return=1 means: stop, no more processing
655  */
656 //extern struct message *dddebug;
657 int Port::message_epoint(unsigned long epoint_id, int message_id, union parameter *param)
658 {
659         /* check if we got audio data from one remote port */
660         switch(message_id)
661         {
662                 case MESSAGE_TONE: /* play tone */
663                 PDEBUG(DEBUG_PORT, "PORT(%s) isdn port with (caller id %s) setting tone '%s' dir '%s'\n", p_name, p_callerinfo.id, param->tone.name, param->tone.dir);
664                 set_tone(param->tone.dir,param->tone.name);
665                 return(1);
666
667                 case MESSAGE_DATA:
668 //printf("port=%s, epoint=%d\n",p_cardname, epoint->e_serial);
669                 mixer(param);
670                 return(1);
671
672                 case MESSAGE_VBOX_TONE: /* play tone of answering machine */
673                 PDEBUG(DEBUG_PORT, "PORT(%s) set answering machine tone '%s' '%s'\n", p_name, param->tone.dir, param->tone.name);
674                 set_vbox_tone(param->tone.dir, param->tone.name);
675                 return(1);
676
677                 case MESSAGE_VBOX_PLAY: /* play recording of answering machine */
678                 PDEBUG(DEBUG_PORT, "PORT(%s) set answering machine file to play '%s' (offset %d seconds)\n", p_name, param->play.file, param->play.offset);
679                 set_vbox_play(param->play.file, param->play.offset);
680                 return(1);
681
682                 case MESSAGE_VBOX_PLAY_SPEED: /* set speed of playback (recording of answering machine) */
683                 PDEBUG(DEBUG_PORT, "PORT(%s) set answering machine playback speed %d (times)\n", p_name, param->speed);
684                 set_vbox_speed(param->speed);
685                 return(1);
686
687         }
688
689         return(0);
690 }
691
692
693 /*
694  * special function generate individual isdn debug logs
695  */
696 void Port::printisdn(char *fmt, ...)
697 {
698         char buffer[4096];
699         char name[128];
700         va_list args;
701         FILE *fp;
702
703         va_start(args,fmt);
704         VUNPRINT(buffer,sizeof(buffer)-1,fmt,args);
705         buffer[sizeof(buffer)-1]=0;
706         va_end(args);
707
708         PDEBUG_RUNTIME(NULL, 0, DEBUG_PORT, "PORT(%s serial=%ld): %s\n", p_name, p_serial, buffer);
709         if (options.deb & DEBUG_LOG)
710         {
711                 SPRINT(name, "%s/debug_%s.log", INSTALL_DATA, p_name);
712                 if (!(fp = fopen(name, "a")))
713                         return;
714         
715                 fprintf(fp, "%04d.%02d.%02d %02d:%02d:%02d %s(%ld): %s", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, p_name, p_serial, buffer);
716                 fclose(fp);
717         }
718 }
719
720
721 /* wave header structure */
722 struct fmt {
723         unsigned short  stereo; /* 1 = mono, 2 = stereo */
724         unsigned short  channels; /* number of channels */
725         unsigned long   sample_rate; /* sample rate */
726         unsigned long   data_rate; /* data rate */
727         unsigned short  bytes_sample; /* bytes per sample (all channels) */
728         unsigned short  bits_sample; /* bits per sample (one channel) */
729 };
730
731
732 /*
733  * open record file (actually a wave file with empty header which will be
734  * written before close, because we do not know the size yet)
735  * type=1 record annoucement,  type=0 record audio stream, type=2 record vbox
736  */
737 int Port::open_record(int type, int vbox, int skip, char *terminal, int anon_ignore, char *vbox_email, int vbox_email_file)
738 {
739         /* RIFFxxxxWAVEfmt xxxx(fmt-size)dataxxxx... */
740         char dummyheader[8+4+8+sizeof(fmt)+8];
741         char filename[256];
742
743         if (!terminal)
744         {
745                 PERROR("Port(%d) not a terminal\n", p_serial);
746                 return(0);
747         }
748         SCPY(p_record_extension, terminal);
749         p_record_anon_ignore = anon_ignore;
750         SCPY(p_record_vbox_email, vbox_email);
751         p_record_vbox_email_file = vbox_email_file;
752         
753         if (p_record)
754         {
755                 PERROR("Port(%d) already recording\n", p_serial);
756                 return(0);
757         }
758
759         if (vbox != 0)
760                 SPRINT(filename, "%s/%s/%s/vbox", INSTALL_DATA, options.extensions_dir, p_record_extension);
761         else
762                 SPRINT(filename, "%s/%s/%s/recordings", INSTALL_DATA, options.extensions_dir, p_record_extension);
763         if (mkdir(filename, 0755) < 0)
764         {
765                 if (errno != EEXIST)
766                 {
767                         PERROR("Port(%d) cannot create directory '%s'\n", p_serial, filename);
768                         return(0);
769                 }
770         }
771
772         if (vbox == 1)
773                 UPRINT(strchr(filename,'\0'), "/announcement");
774         else
775                 UPRINT(strchr(filename,'\0'), "/%04d-%02d-%02d_%02d%02d%02d", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
776         if (vbox == 2)
777         {
778                 p_record_vbox_year = now_tm->tm_year;
779                 p_record_vbox_mon = now_tm->tm_mon;
780                 p_record_vbox_mday = now_tm->tm_mday;
781                 p_record_vbox_hour = now_tm->tm_hour;
782                 p_record_vbox_min = now_tm->tm_min;
783         }
784
785         /* check, if file exists (especially when an extension calls the same extension) */
786         if (vbox != 1)
787         if ((p_record = fopen(filename, "r")))
788         {
789                 fclose(p_record);
790                 SCAT(filename, "_2nd");
791         }
792                         
793         p_record = fopen(filename, "w");
794         if (!p_record)
795         {
796                 PERROR("Port(%d) cannot record because file cannot be opened '%s'\n", p_serial, filename);
797                 return(0);
798         }
799         fduse++;
800
801         p_record_type = type;
802         p_record_vbox = vbox;
803         p_record_skip = skip;
804         p_record_length = 0;
805         switch(p_record_type)
806         {
807                 case CODEC_MONO:
808                 case CODEC_STEREO:
809                 case CODEC_8BIT:
810                 fwrite(dummyheader, sizeof(dummyheader), 1, p_record);
811                 break;
812
813                 case CODEC_LAW:
814                 break;
815         }
816         UCPY(p_record_filename, filename);
817
818         PDEBUG(DEBUG_PORT, "Port(%d) recording started with file name '%s'\n", p_serial, filename);
819         return(1);
820 }
821
822
823 /*
824  * close the recoding file, put header in front and rename
825  */
826 void Port::close_record(int beep)
827 {
828         static signed long beep_mono[] = {-10000, 10000, -10000, 10000, -10000, 10000, -10000, 10000, -10000, 10000, -10000, 10000, -10000, 10000, -10000, 10000};
829         static unsigned char beep_8bit[] = {48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208, 48, 208};
830         unsigned long size, wsize;
831         struct fmt fmt;
832         char filename[512], indexname[512];
833         FILE *fp;
834         int i, ii;
835         char number[256], callerid[256];
836         char *p;
837         struct caller_info callerinfo;
838         char *valid_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_.-!$%&/()=+*;~";
839
840         if (!p_record)
841                 return;
842
843         memcpy(&callerinfo, &p_callerinfo, sizeof(struct caller_info));
844         apply_callerid_restriction(p_record_anon_ignore, -1, callerinfo.id, &callerinfo.ntype, &callerinfo.present, &callerinfo.screen, callerinfo.voip, callerinfo.intern, callerinfo.name);
845
846         SCPY(number, p_dialinginfo.number);
847         SCPY(callerid, numberrize_callerinfo(callerinfo.id, callerinfo.ntype));
848         if (callerid[0] == '\0')
849         {
850                 if (callerinfo.present == INFO_PRESENT_RESTRICTED)
851                         UCPY(callerid,"anonymous");
852                 else
853                         UCPY(callerid,"unknown");
854         }
855
856         /* change verboten digits */
857         p = callerid;
858         while((p=strchr(p,'*')))
859                 *(p++) = 'x';
860         p = callerid;
861         while((p=strchr(p,'/')))
862                 *(p++) = 'x';
863         p = number;
864         while((p=strchr(p,'*')))
865                 *(p++) = 'x';
866         p = number;
867         while((p=strchr(p,'/')))
868                 *(p++) = 'x';
869         i = 0;
870         ii = strlen(callerid);
871         while(i < ii)
872         {
873                 if (!strchr(valid_chars, callerid[i]))
874                         callerid[i] = '_';
875                 i++;
876         }
877         i = 0;
878         ii = strlen(number);
879         while(i < ii)
880         {
881                 if (!strchr(valid_chars, number[i]))
882                         number[i] = '_';
883                 i++;
884         }
885
886         /* add beep to the end of recording */
887         if (beep)
888         switch(p_record_type)
889         {
890                 case CODEC_MONO:
891                 i = 0;
892                 while(i < beep)
893                 {
894                         fwrite(beep_mono, sizeof(beep_mono), 1, p_record);
895                         i += sizeof(beep_mono);
896                         p_record_length += sizeof(beep_mono);
897                 }
898                 break;
899                 case CODEC_8BIT:
900                 i = 0;
901                 while(i < beep)
902                 {
903                         fwrite(beep_8bit, sizeof(beep_8bit), 1, p_record);
904                         i += sizeof(beep_8bit);
905                         p_record_length += sizeof(beep_8bit);
906                 }
907                 break;
908 #if 0
909                 case CODEC_LAW:
910                 i = 0;
911                 while(i < beep)
912                 {
913                         fwrite(beep_law, sizeof(beep_law), 1, p_record);
914                         i += sizeof(beep_law);
915                         p_record_length += sizeof(beep_law);
916                 }
917                 break;
918 #endif
919                 default:
920                 PERROR("codec %d not supported for beep adding\n", p_record_type);
921         }
922
923         /* complete header */
924         switch(p_record_type)
925         {
926                 case CODEC_MONO:
927                 case CODEC_STEREO:
928                 case CODEC_8BIT:
929                 /* cue */
930                 fprintf(p_record, "cue %c%c%c%c%c%c%c%c", 4, 0, 0, 0, 0,0,0,0);
931
932                 /* LIST */
933                 fprintf(p_record, "LIST%c%c%c%cadtl", 4, 0, 0, 0);
934
935                 /* go to header */
936                 fseek(p_record, 0, SEEK_SET);
937
938                 /* WAVEfmt xxxx(fmt-size)dataxxxx[data]cue xxxx0000LISTxxxxadtl*/
939                 size = p_record_length;
940                 wsize = 4+8+sizeof(fmt)+8+size+8+4+8+4;
941
942                 /* RIFF */
943                 fprintf(p_record, "RIFF%c%c%c%c", (unsigned char)(wsize&0xff), (unsigned char)((wsize>>8)&0xff), (unsigned char)((wsize>>16)&0xff), (unsigned char)(wsize>>24));
944
945                 /* WAVE */
946                 fprintf(p_record, "WAVE");
947
948                 /* fmt */
949                 fprintf(p_record, "fmt %c%c%c%c", sizeof(fmt), 0, 0, 0);
950                 switch(p_record_type)
951                 {
952                         case CODEC_MONO:
953                         fmt.stereo = 1;
954                         fmt.channels = 1;
955                         fmt.sample_rate = 8000; /* samples/sec */
956                         fmt.data_rate = 16000; /* full data rate */
957                         fmt.bytes_sample = 2; /* all channels */
958                         fmt.bits_sample = 16; /* one channel */
959                         break;
960
961                         case CODEC_STEREO:
962                         fmt.stereo = 1;
963                         fmt.channels = 2;
964                         fmt.sample_rate = 8000; /* samples/sec */
965                         fmt.data_rate = 32000; /* full data rate */
966                         fmt.bytes_sample = 4; /* all channels */
967                         fmt.bits_sample = 16; /* one channel */
968                         break;
969
970                         case CODEC_8BIT:
971                         fmt.stereo = 1;
972                         fmt.channels = 1;
973                         fmt.sample_rate = 8000; /* samples/sec */
974                         fmt.data_rate = 8000; /* full data rate */
975                         fmt.bytes_sample = 1; /* all channels */
976                         fmt.bits_sample = 8; /* one channel */
977                         break;
978                 }
979                 fwrite(&fmt, sizeof(fmt), 1, p_record);
980
981                 /* data */
982                 fprintf(p_record, "data%c%c%c%c", (unsigned char)(size&0xff), (unsigned char)((size>>8)&0xff), (unsigned char)((size>>16)&0xff), (unsigned char)(size>>24));
983
984                 /* rename file */
985                 if (p_record_vbox == 1)
986                         SPRINT(filename, "%s.wav", p_record_filename);
987                 else
988                         SPRINT(filename, "%s_%s-%s.wav", p_record_filename, callerid, number);
989                 break;
990
991                 case CODEC_LAW:
992                 /* rename file */
993                 if (p_record_vbox == 1)
994                         SPRINT(filename, "%s.isdn", p_record_filename);
995                 else
996                         SPRINT(filename, "%s_%s-%s.isdn", p_record_filename, callerid, number);
997                 break;
998
999                 default:
1000                 if (p_record_vbox == 1)
1001                         SPRINT(filename, "%s.unknown", p_record_filename);
1002                 else
1003                         SPRINT(filename, "%s_%s-%s.unknown", p_record_filename, callerid, number);
1004         }
1005
1006         fclose(p_record);
1007         fduse--;
1008         p_record = NULL;
1009
1010         if (rename(p_record_filename, filename) < 0)
1011         {
1012                 PERROR("Port(%d) cannot rename from '%s' to '%s'\n", p_serial, p_record_filename, filename);
1013                 return;
1014         }
1015
1016         PDEBUG(DEBUG_PORT, "Port(%d) recording is written and renamed to '%s' and must have the following size:%lu raw:%lu samples:%lu\n", p_serial, filename, wsize+8, size, size>>1);
1017
1018         if (p_record_vbox == 2)
1019         {
1020                 SPRINT(indexname, "%s/%s/%s/vbox/index", INSTALL_DATA, options.extensions_dir, p_record_extension);
1021                 if ((fp = fopen(indexname,"a")))
1022                 {
1023                         fduse++;
1024
1025                         /* remove path from file name */
1026                         p = filename;
1027                         while(strchr(p, '/'))
1028                                 p = strchr(p, '/')+1;
1029                         fprintf(fp, "%s %d %d %d %d %d %s\n", p, p_record_vbox_year, p_record_vbox_mon, p_record_vbox_mday, p_record_vbox_hour, p_record_vbox_min, callerid);
1030
1031                         fclose(fp);
1032                         fduse--;
1033                 } else
1034                 {
1035                         PERROR("Port(%d) cannot open index file '%s' to append.\n", p_serial, indexname);
1036                 }
1037
1038                 /* send email with sample*/
1039                 if (p_record_vbox_email[0])
1040                 {
1041                         send_mail(p_record_vbox_email_file?filename:(char *)"", callerid, callerinfo.intern, callerinfo.name, p_record_vbox_email, p_record_vbox_year, p_record_vbox_mon, p_record_vbox_mday, p_record_vbox_hour, p_record_vbox_min, p_record_extension);
1042                 }
1043         }
1044 }
1045
1046
1047