Fixed buffer overflow bug at pickup feature
[lcr.git] / action_vbox.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** PBX4Linux                                                                 **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** dialing for answering machine is processed here                           **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14
15 // note: the given display message (e_vbox_display) may include "%s" for the counter
16
17 /*
18  * these are the state, the vbox is in. if the current tone has been played,
19  * an action will be calles as defined in vbox_message_eof(), which is called 
20  * from Epoint:handler().
21  * also this state is used to determine the correct processing of the current key press
22  */
23 enum {
24         VBOX_STATE_MENU,                /* tell the menu */
25 VBOX_STATE_CALLINFO_BEGIN, /* this value defines the start of callinfo */
26         VBOX_STATE_CALLINFO_INTRO,      /* tell that the "call is received at" */
27         VBOX_STATE_CALLINFO_MONTH,      /* tell the month */
28         VBOX_STATE_CALLINFO_DAY,        /* tell the day */
29         VBOX_STATE_CALLINFO_HOUR,       /* tell the hour */
30         VBOX_STATE_CALLINFO_OCLOCK,     /* tell the word "o'clock" */
31         VBOX_STATE_CALLINFO_MIN,        /* tell the minute */
32         VBOX_STATE_CALLINFO_MINUTES,    /* tell the word "minutes" */
33         VBOX_STATE_CALLINFO_DIGIT,      /* tell the digits */
34 VBOX_STATE_CALLINFO_END, /* this value defines the end of callingo */
35         VBOX_STATE_NOTHING,             /* tells that no calls are recorded */
36         VBOX_STATE_PLAY,                /* play the current recording */
37         VBOX_STATE_PAUSE,               /* tell that the recording is paused */
38         VBOX_STATE_RECORD_ASK,  /* ask for recording */ 
39         VBOX_STATE_RECORD_PLAY, /* play recording */    
40         VBOX_STATE_RECORD_RECORD,       /* record recording */  
41         VBOX_STATE_STORE_ASK,   /* ask for store */
42         VBOX_STATE_DELETE_ASK,  /* ask for delete */
43         VBOX_STATE_STORE_DONE,  /* tell that message is store */
44         VBOX_STATE_DELETE_DONE, /* tell that message is delete */
45 };
46
47 const char *months_english[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
48 const char *months_german[] = {"Jan","Feb","Maer","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"};
49
50 struct vbox_menu {
51         const char digit;
52         const char *english;
53         const char *german;
54 } vbox_menu[] = {
55         {'1', "<< previous", "<< zurueck"},
56         {'2', "-> play", "-> anhoeren"},
57         {'3', ">> next", ">> vor"},
58         {'4', "<  rewind", "<  rueckspulen"},
59         {'5', "[] stop", "[] stop"},
60         {'6', ">  wind", ">  vorspulen"},
61         {'7', "() record", "() Aufnahme"},
62         {'8', "=  store", "=  speichern"},
63         {'9', "X  delete", "X  loeschen"},
64         {'0', "*  call", "*  anrufen"},
65         {'\0', NULL, NULL}
66 };
67
68 /*
69  * initialize the vbox. this is called at process_dialing(), when the VBOX_PLAY
70  * action has been selected by the caller
71  */
72 void EndpointAppPBX::action_init_vbox_play(void)
73 {
74         int                     language = e_ext.vbox_language;
75         struct route_param      *rparam;
76         struct lcr_msg          *message;
77         struct port_list        *portlist = ea_endpoint->ep_portlist;
78
79         /* get extension */
80         SCPY(e_vbox, e_ext.number);
81         if ((rparam = routeparam(e_action, PARAM_EXTENSION)))
82                 SCPY(e_vbox, rparam->string_value);
83         if (e_vbox[0] == '\0') {
84                 /* facility rejected */
85                 message_disconnect_port(portlist, CAUSE_FACILITYREJECTED, LOCATION_PRIVATE_LOCAL, "");
86                 new_state(EPOINT_STATE_OUT_DISCONNECT);
87                 set_tone(portlist,"cause_22");
88                 return;
89         }
90
91         /* connect, but still accept more digits */
92         new_state(EPOINT_STATE_IN_OVERLAP);
93         if (e_ext.number[0])
94                 e_dtmf = 1;
95         message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_CONNECT);
96         message_put(message);
97         logmessage(message->type, &message->param, portlist->port_id, DIRECTION_OUT);
98
99         /* initialize the vbox */
100         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) initializing answering vbox state\n", ea_endpoint->ep_serial);
101
102         e_vbox_state = VBOX_STATE_MENU;
103         SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
104         schedule_timer(&e_vbox_refresh, 0, 0);
105         set_tone_vbox("menu");
106
107         e_vbox_menu = -1;
108         e_vbox_play = 0;
109         vbox_index_read(e_vbox_play);
110         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) number of calls: %d\n", ea_endpoint->ep_serial, e_vbox_index_num);
111
112         if (e_vbox_index_num == 0) {
113                 e_vbox_state = VBOX_STATE_NOTHING;
114                 SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
115                 schedule_timer(&e_vbox_refresh, 0, 0);
116                 set_tone_vbox("nothing");
117         }
118 }
119
120 /*
121  * read index list, and fill the index variables with the given position
122  * if the index is empty (or doesn't exist), the variables are not filled.
123  * but alway the e_vbox_index_num is given.
124  */
125 void EndpointAppPBX::vbox_index_read(int num)
126 {
127         FILE *fp;
128         char filename[256];
129         char buffer[256];
130         char name[sizeof(buffer)];
131         char callerid[sizeof(buffer)];
132         int year, mon, mday, hour, min;
133         int i;
134
135         e_vbox_index_num = 0;
136
137         SPRINT(filename, "%s/%s/vbox/index", EXTENSION_DATA, e_vbox);
138         if (!(fp = fopen(filename, "r"))) {
139                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) no files in index\n", ea_endpoint->ep_serial);
140                 return;
141         }
142         fduse++;
143
144         i = 0;
145         while((GETLINE(buffer, fp))) {
146                 name[0] = callerid[0] = '\0';
147                 mon = mday = hour = min = 0;
148                 sscanf(buffer, "%s %d %d %d %d %d %s", name, &year, &mon, &mday, &hour, &min, callerid);
149
150                 if (name[0]=='\0' || name[0]=='#')
151                         continue;
152
153                 /* the selected entry */
154                 if (i == num) {
155                         SCPY(e_vbox_index_file, name);
156                         e_vbox_index_year = year;
157                         e_vbox_index_mon = mon;
158                         e_vbox_index_mday = mday;
159                         e_vbox_index_hour = hour;
160                         e_vbox_index_min = min;
161                         SCPY(e_vbox_index_callerid, callerid);
162                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) read entry #%d: '%s', %02d:%02d %02d:%02d cid='%s'\n", ea_endpoint->ep_serial, i, name, mon+1, mday, hour, min, callerid);
163                 }
164
165                 i++;
166         }
167
168         e_vbox_index_num = i;
169
170         fclose(fp);
171         fduse--;
172 }
173
174
175 /*
176  * removes given index from list
177  * after removing, the list should be reread, since e_vbox_index_num
178  * and the current variabled do not change
179  */
180 void EndpointAppPBX::vbox_index_remove(int num)
181 {
182         FILE *fpr, *fpw;
183         char buffer[256];
184         int i;
185         char filename1[256], filename2[256];
186
187         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) removing entrie #%d\n", ea_endpoint->ep_serial, num);
188
189         SPRINT(filename1, "%s/%s/vbox/index", EXTENSION_DATA, e_vbox);
190         SPRINT(filename2, "%s/%s/vbox/index-temp", EXTENSION_DATA, e_vbox);
191         if (!(fpr = fopen(filename1, "r"))) {
192                 return;
193         }
194         if (!(fpw = fopen(filename2, "w"))) {
195                 fclose(fpr);
196                 return;
197         }
198         fduse += 2;
199
200         i = 0;
201         while((fgets(buffer,sizeof(buffer),fpr))) {
202                 buffer[sizeof(buffer)-1] = '\0';
203                 if (buffer[0]) buffer[strlen(buffer)-1] = '\0';
204
205                 if (buffer[0]=='\0' || buffer[0]=='#') {
206                         fprintf(fpw, "%s\n", buffer);
207                         continue;       
208                 }
209
210                 /* the selected entry will not be written */
211                 if (i != num) {
212                         fprintf(fpw, "%s\n", buffer);
213                 }
214
215                 i++;
216         }
217
218         fclose(fpr);
219         fclose(fpw);
220         fduse -= 2;
221
222         rename(filename2, filename1);
223 }
224
225
226 /*
227  * process dialing of vbox_play (actually the menu)
228  * it is depended by the state, which action is performed
229  */
230 void EndpointAppPBX::action_dialing_vbox_play(void)
231 {
232         int language = e_ext.vbox_language;
233         struct port_list *portlist;
234         class Port *port;
235         time_t current_time;
236         struct tm *current_tm;
237         
238         portlist = ea_endpoint->ep_portlist;
239
240         if (e_extdialing[0] == '\0') {
241                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) called with no digit\n", ea_endpoint->ep_serial);
242                 return;
243         }
244
245         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) dialing digit: %c\n", ea_endpoint->ep_serial, e_extdialing[0]);
246
247         schedule_timer(&e_vbox_refresh, 0, 0);
248
249         if (e_vbox_state == VBOX_STATE_RECORD_RECORD) {
250                 if (e_extdialing[0] == '1' || e_extdialing[0] == '0') {
251                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) stopping recording of announcement.\n", ea_endpoint->ep_serial);
252
253                         port = find_port_id(portlist->port_id);
254                         if (port)
255                                 port->close_record((e_extdialing[0]=='1')?6000:0, 2000); /* append beep */
256                         goto record_ask;
257                 }
258                 goto done;
259         }
260
261         if (e_vbox_state == VBOX_STATE_RECORD_PLAY) {
262                 if (e_extdialing[0] == '1') {
263                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) stopping playback of announcement.\n", ea_endpoint->ep_serial);
264
265                         goto record_ask;
266                 }
267                 goto done;
268         }
269
270         if (e_vbox_state == VBOX_STATE_RECORD_ASK) {
271                 switch(e_extdialing[0]) {
272                         case '3':
273                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) quit recoding menu.\n", ea_endpoint->ep_serial);
274                         ask_abort:
275                         /* abort */
276                         e_vbox_state = VBOX_STATE_MENU;
277                         SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
278                         set_tone_vbox("menu");
279                         break;
280
281                         case '2':
282                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play recoding.\n", ea_endpoint->ep_serial);
283                         /* play announcement */
284                         e_vbox_counter = 0;
285                         e_vbox_counter_max = 0;
286                         e_vbox_speed = 1;
287                         e_vbox_state = VBOX_STATE_RECORD_PLAY;
288                         schedule_timer(&e_vbox_refresh, 0, 0);
289                         if (e_ext.vbox_language)
290                                 SCPY(e_vbox_display, "Wied., 1=stop %s");
291                         else
292                                 SCPY(e_vbox_display, "play, 1=stop %s");
293                         if (e_ext.vbox_display == VBOX_DISPLAY_BRIEF)
294                                 SCPY(e_vbox_display, "1=stop %s");
295                         set_play_vbox("announcement", 0);
296                         break;
297
298                         case '1':
299                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) record announcement.\n", ea_endpoint->ep_serial);
300                         /* close recording if already recording */
301                         port = find_port_id(portlist->port_id);
302                         if (port) {
303                                 port->close_record(0,0); 
304                                 port->open_record(CODEC_MONO, 1, 4000, e_ext.number, 0, "", 0); /* record announcement, skip the first 4000 samples */
305                         }
306                         e_vbox_state = VBOX_STATE_RECORD_RECORD;
307                         if (e_ext.vbox_language)
308                                 SCPY(e_vbox_display, "Aufnahme, 1=stop");
309                         else
310                                 SCPY(e_vbox_display, "recording, 1=stop");
311                         set_tone_vbox(NULL);
312                         break;
313
314                         default:
315                         ;
316                 }
317                 goto done;
318         }
319
320         if (e_vbox_state==VBOX_STATE_STORE_ASK || e_vbox_state==VBOX_STATE_DELETE_ASK) {
321                 char filename[256], filename2[256];
322
323                 switch(e_extdialing[0]) {
324                         case '3':
325                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) quit store/delete menu.\n", ea_endpoint->ep_serial);
326                         goto ask_abort;
327
328                         case '1':
329                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) do store/delete.\n", ea_endpoint->ep_serial);
330                         SPRINT(filename, "%s/%s/vbox/%s", EXTENSION_DATA, e_vbox, e_vbox_index_file);
331
332                         /* move file */
333                         if (e_vbox_state == VBOX_STATE_STORE_ASK) {
334                                 SPRINT(filename, "%s/%s/recordings", EXTENSION_DATA, e_vbox);
335                                 if (mkdir(filename, 0755) < 0) {
336                                         if (errno != EEXIST) {
337                                                 PERROR("EPOINT(%d) cannot create directory '%s'\n", ea_endpoint->ep_serial, filename);
338                                                 goto done;
339                                         }
340                                 }
341                                 SPRINT(filename2, "%s/%s/recordings/%s", EXTENSION_DATA, e_vbox, e_vbox_index_file);
342                                 rename(filename, filename2);
343                                 e_vbox_state = VBOX_STATE_STORE_DONE;
344                                 if (e_ext.vbox_language)
345                                         SCPY(e_vbox_display, "Nachricht gespeichert!");
346                                 else
347                                         SCPY(e_vbox_display, "Message stored!");
348                                 set_tone_vbox("store_done");
349                         }
350
351                         /* remove file */
352                         if (e_vbox_state == VBOX_STATE_DELETE_ASK) {
353                                 remove(filename);
354                                 e_vbox_state = VBOX_STATE_DELETE_DONE;
355                                 if (e_ext.vbox_language)
356                                         SCPY(e_vbox_display, "Nachricht geloescht!");
357                                 else
358                                         SCPY(e_vbox_display, "Message deleted!");
359                                 set_tone_vbox("delete_done");
360                         }
361
362                         /* remove from list */
363                         vbox_index_remove(e_vbox_play);
364                         vbox_index_read(e_vbox_play);
365                         /* stay at the last message+1, so we always get "no messages" */
366                         if (e_vbox_play>e_vbox_index_num && e_vbox_play) {
367                                 e_vbox_play = e_vbox_index_num-1;
368                         }
369                         default:
370                         ;
371                 }
372                 goto done;
373         }
374
375         /* dialing during menu */
376         switch(e_extdialing[0]) {
377                 /* process the vbox functions */
378                 case '1': /* previous */
379                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) previous call is selected.\n", ea_endpoint->ep_serial);
380                 if (e_vbox_index_num == 0) { /* nothing to play */
381                         no_calls:
382                         e_vbox_state = VBOX_STATE_MENU;
383                         SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
384                         set_tone_vbox("nothing");
385                         break;
386                 }
387                 e_vbox_play--;
388                 if (e_vbox_play < 0) {
389                         e_vbox_play = 0;
390
391                         e_vbox_state = VBOX_STATE_MENU;
392                         SCPY(e_vbox_display, (char *)((language)?"kein vorheriger Anruf":"no previous call"));
393                         set_tone_vbox("nothing");
394                         break;
395                 }
396                 /* announce call */
397                 announce_call:
398                 e_vbox_state = VBOX_STATE_CALLINFO_INTRO;
399                 SPRINT(e_vbox_display, "#%d", e_vbox_play+1);
400                 vbox_index_read(e_vbox_play);
401                 time(&current_time);
402                 current_tm = localtime(&current_time);
403                 if (e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) {
404                         UPRINT(strchr(e_vbox_display,'\0'), " %s", (language)?months_german[e_vbox_index_mon]:months_english[e_vbox_index_mon]);
405                 }
406                 if (e_vbox_index_mday!=current_tm->tm_mday || e_vbox_index_mon!=current_tm->tm_mon || e_vbox_index_year!=current_tm->tm_year) {
407                         UPRINT(strchr(e_vbox_display,'\0'), " %d", e_vbox_index_mday);
408                 }
409                 UPRINT(strchr(e_vbox_display,'\0'), " %02d:%02d", e_vbox_index_hour, e_vbox_index_min);
410                 if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
411                         UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
412                 set_tone_vbox("intro");
413                 break;
414
415                 case '2': /* play */
416                 if (e_vbox_play >= e_vbox_index_num)
417                         goto no_messages;
418                 if (e_vbox_index_num == 0) { /* nothing to play */
419                         goto no_calls;
420                 }
421                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d.\n", ea_endpoint->ep_serial, e_vbox_play+1);
422                 if (e_vbox_state>VBOX_STATE_CALLINFO_BEGIN && e_vbox_state<VBOX_STATE_CALLINFO_END) {
423                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. abborting announcement and starting with playback\n", ea_endpoint->ep_serial, e_vbox_play+1);
424                         /* the callinfo is played, so we start with the call */
425                         e_vbox_counter = 0;
426                         e_vbox_counter_max = 0;
427                         e_vbox_speed = 1;
428                         e_vbox_state = VBOX_STATE_PLAY;
429                         schedule_timer(&e_vbox_refresh, 0, 0);
430                         SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1);
431                         if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
432                                 UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
433                         set_play_vbox(e_vbox_index_file, 0);
434                         break;
435                 } else
436                 if (e_vbox_state==VBOX_STATE_PLAY && e_vbox_speed!=1) {
437                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. play speed is different from 1, so we play now with normal speed\n", ea_endpoint->ep_serial, e_vbox_play+1);
438                         /* we set play speed to normal */
439                         e_vbox_speed = 1;
440                         set_play_speed(e_vbox_speed);
441                 } else
442                 if (e_vbox_state == VBOX_STATE_PLAY) {
443                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. play speed is equals 1, so we pause\n", ea_endpoint->ep_serial, e_vbox_play+1);
444                         /* we pause the current play */
445                         e_vbox_state = VBOX_STATE_PAUSE;
446                         SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
447                         set_tone_vbox("pause");
448                 } else
449                 if (e_vbox_state == VBOX_STATE_PAUSE) {
450                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. currently pause, so we continue play\n", ea_endpoint->ep_serial, e_vbox_play+1);
451                         /* we continue the current play */
452                         e_vbox_state = VBOX_STATE_PLAY;
453                         SPRINT(e_vbox_display, "#%d %%s", e_vbox_play+1);
454                         if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
455                                 UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
456                         set_play_vbox(e_vbox_index_file, e_vbox_counter);
457                 } else {
458                         /* now we have something else going on, so we announce the call */
459                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) play call #%d. announcing call during any other state\n", ea_endpoint->ep_serial, e_vbox_play+1);
460                         goto announce_call;
461                 }
462                 break;
463
464                 case '3': /* next */
465                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) next call is selected.\n", ea_endpoint->ep_serial);
466                 if (e_vbox_index_num == 0) { /* nothing to play */
467                         goto no_calls;
468                 }
469                 e_vbox_play++;
470                 if (e_vbox_play >= e_vbox_index_num) {
471                         no_messages:
472                         e_vbox_play = e_vbox_index_num;
473
474                         e_vbox_state = VBOX_STATE_MENU;
475                         SCPY(e_vbox_display, (char *)((language)?"kein weiterer Anruf":"no next call"));
476                         set_tone_vbox("nothing");
477                         break;
478                 }
479                 /* announce call */
480                 goto announce_call;
481                 break;
482
483                 case '4': /* rewind */
484                 if (e_vbox_state==VBOX_STATE_PLAY) {
485                         if (e_vbox_speed >= -1)
486                                 e_vbox_speed = -1;
487                         e_vbox_speed = e_vbox_speed * 2;
488                         set_play_speed(e_vbox_speed);
489                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) rewind speed has been changed to: %d\n", ea_endpoint->ep_serial, e_vbox_speed);
490                 } 
491                 break;
492
493                 case '5': /* stop */
494                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) stop is pressed, so we hear the menu\n", ea_endpoint->ep_serial);
495                 e_vbox_state = VBOX_STATE_MENU;
496                 SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
497                 set_tone_vbox("menu");
498                 break;
499
500                 case '6': /* wind */
501                 if (e_vbox_state==VBOX_STATE_PLAY) {
502                         if (e_vbox_speed <= 1)
503                                 e_vbox_speed = 1;
504                         e_vbox_speed = e_vbox_speed * 2;
505                         set_play_speed(e_vbox_speed);
506                         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) wind speed has been changed to: %d\n", ea_endpoint->ep_serial, e_vbox_speed);
507                 } 
508                 break;
509
510                 case '7': /* record announcement */
511                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) entering the record announcement menu\n", ea_endpoint->ep_serial);
512                 record_ask:
513                 e_vbox_state = VBOX_STATE_RECORD_ASK;
514                 SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=back"));
515                 set_tone_vbox("record_ask");
516                 break;
517
518                 case '8': /* store file */
519                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) entering the store menu\n", ea_endpoint->ep_serial);
520                 if (e_vbox_play >= e_vbox_index_num)
521                         goto no_messages;
522                 if (e_vbox_index_num == 0) { /* nothing to play */
523                         goto no_calls;
524                 }
525                 e_vbox_state = VBOX_STATE_STORE_ASK;
526                 SCPY(e_vbox_display, (char *)((language)?"speichern 1=ja 3=nein":"store 1=yes 3=back"));
527                 set_tone_vbox("store_ask");
528                 break;
529
530                 case '9': /* delete file */
531                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) entering the delete menu\n", ea_endpoint->ep_serial);
532                 if (e_vbox_play >= e_vbox_index_num)
533                         goto no_messages;
534                 if (e_vbox_index_num == 0) { /* nothing to play */
535                         goto no_calls;
536                 }
537                 e_vbox_state = VBOX_STATE_DELETE_ASK;
538                 SCPY(e_vbox_display, (char *)((language)?"loeschen 1=ja 3=nein":"delete 1=yes 3=back"));
539                 set_tone_vbox("delete_ask");
540                 break;
541
542
543                 /* process the menu */
544                 case '#':
545                 if (e_vbox_menu < 0)
546                         e_vbox_menu = 0;
547                 else
548                         e_vbox_menu++;
549                 if (vbox_menu[e_vbox_menu].english == NULL)
550                         e_vbox_menu = 0;
551                 /* show menu */
552                 show_menu:
553                 SPRINT(e_vbox_display, "%c: %s", vbox_menu[e_vbox_menu].digit, (language)?vbox_menu[e_vbox_menu].german:vbox_menu[e_vbox_menu].english);
554                 break;
555
556                 case '0':
557                 if (e_vbox_menu < 0) { /* only if menu selection is pressed before*/
558                         /* call if phonenumber is given */
559                         if (e_vbox_index_num)
560                         if (e_vbox_index_callerid[0]!='\0' && !!strcmp(e_vbox_index_callerid,"anonymous") && !!strcmp(e_vbox_index_callerid,"unknown")) {
561                                 set_tone(portlist, "dialing");
562                                 SPRINT(e_dialinginfo.id, "extern:%s", e_vbox_index_callerid);
563                                 e_extdialing = e_dialinginfo.id;
564                                 e_action = NULL;
565                                 process_dialing(0);
566                                 return;
567                         }
568                         break;
569                 }
570                 e_extdialing[0] = vbox_menu[e_vbox_menu].digit;
571                 e_extdialing[1] = '\0';
572                 e_vbox_menu = -1;
573                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) executing selected menu:%d\n", e_extdialing[0]);
574                 action_dialing_vbox_play(); /* redo this method using the digit */
575                 return;
576
577                 case '*':
578                 if (e_vbox_menu < 0)
579                         e_vbox_menu = 0;
580                 else
581                         e_vbox_menu--;
582                 if (e_vbox_menu < 0)
583                         while(vbox_menu[e_vbox_menu+1].english) /* jump to the end */
584                                 e_vbox_menu++;
585                 /* show menu */
586                 goto show_menu;
587                 break;
588
589                 default:
590                 PDEBUG(DEBUG_EPOINT, "EPOINT(%d) unsupported digit '%c'\n", ea_endpoint->ep_serial, e_extdialing);
591         }
592
593         done:
594         /* reset menu after dialing a function */
595         if (e_extdialing[0]!='*' && e_extdialing[0]!='#')
596                 e_vbox_menu = -1;
597
598
599         e_extdialing[0] = '\0';
600
601 }
602
603
604 /*
605  * this handler is called by Epoint::handler(), whenever the action is NUMB_ACTION_VBOX_PLAY
606  */
607 int vbox_refresh(struct lcr_timer *timer, void *instance, int index)
608 {
609         class EndpointAppPBX *ea = (class EndpointAppPBX *)instance;
610
611         /* no display */
612         if (ea->e_ext.vbox_display == VBOX_DISPLAY_OFF)
613                 return 0;
614
615         /* refresh display */
616         char counter[32];
617         struct lcr_msg *message;
618
619         SPRINT(counter, "%02d:%02d", ea->e_vbox_counter/60, ea->e_vbox_counter%60);
620         if (ea->e_vbox_counter_max)
621                 UPRINT(strchr(counter,'\0'), " of %02d:%02d", ea->e_vbox_counter_max/60, ea->e_vbox_counter_max%60);
622
623         message = message_create(ea->ea_endpoint->ep_serial, ea->ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_NOTIFY);
624         SPRINT(message->param.notifyinfo.display, ea->e_vbox_display, counter);
625         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s pending display:%s\n", ea->ea_endpoint->ep_serial, ea->e_ext.number, message->param.notifyinfo.display);
626         message_put(message);
627         ea->logmessage(message->type, &message->param, ea->ea_endpoint->ep_portlist->port_id, DIRECTION_OUT);
628
629         /* not playing anymore */
630         if (!ea->e_vbox_state==VBOX_STATE_PLAY && !ea->e_vbox_state==VBOX_STATE_RECORD_PLAY)
631                 return 0;
632         
633         schedule_timer(&ea->e_vbox_refresh, 1, 0);
634
635         return 0;
636 }
637
638
639 /*
640  * the audio file has ended
641  * this is called by Endpoint::message_port(), whenever an audio of has been received
642  */
643 void EndpointAppPBX::vbox_message_eof(void)
644 {
645         char buffer[32];
646         int language = e_ext.vbox_language;
647         time_t current_time;
648         struct tm *current_tm;
649
650         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s end of file during state: %d\n", ea_endpoint->ep_serial, e_ext.number, e_vbox_state);
651
652         switch(e_vbox_state) {
653                 case VBOX_STATE_MENU:
654                 case VBOX_STATE_NOTHING:
655                 e_vbox_state = VBOX_STATE_MENU;
656                 SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
657                 schedule_timer(&e_vbox_refresh, 0, 0);
658                 set_tone_vbox("menu");
659                 break;
660
661                 case VBOX_STATE_PLAY:
662                 if (e_vbox_speed > 0) {
663                         e_vbox_state = VBOX_STATE_MENU;
664                         SCPY(e_vbox_display, (char *)((language)?"druecke 3 f. Naechste":"press 3 for next"));
665                 schedule_timer(&e_vbox_refresh, 0, 0);
666                         set_tone_vbox("menu");
667                 } else {
668                         /* if we have endoffile because we were playing backwards, we continue to play forward */
669                         e_vbox_speed = 1;
670                         e_vbox_counter = 1;
671                         set_play_vbox(e_vbox_index_file, e_vbox_counter);
672                 }
673                 break;
674
675                 case VBOX_STATE_PAUSE:
676                 SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. weiterspielen":"press 2 to continue"));
677                 schedule_timer(&e_vbox_refresh, 0, 0);
678                 break;
679
680                 case VBOX_STATE_CALLINFO_INTRO:
681                 time(&current_time);
682                 current_tm = localtime(&current_time);
683                 if (e_vbox_index_mday==current_tm->tm_mday && e_vbox_index_mon==current_tm->tm_mon && e_vbox_index_year==current_tm->tm_year)
684                         goto skip_day_month;
685                 e_vbox_state = VBOX_STATE_CALLINFO_MONTH; //german day
686                 if (e_ext.vbox_language)
687                         /* german starts with day */
688                         SPRINT(buffer, "day_%02d", e_vbox_index_mday);
689                 else
690                         /* english starts with month */
691                         SPRINT(buffer, "month_%02d", e_vbox_index_mon+1);
692                 set_tone_vbox(buffer);
693                 break;
694
695                 case VBOX_STATE_CALLINFO_MONTH:
696                 e_vbox_state = VBOX_STATE_CALLINFO_DAY; //german month
697                 if (e_ext.vbox_language) {
698                         /* done with month, so we send the month*/
699                         SPRINT(buffer, "month_%02d", e_vbox_index_mon+1);
700                 } else {
701                         /* done with day, so we send the day */
702                         SPRINT(buffer, "day_%02d", e_vbox_index_mday);
703                 }
704                 set_tone_vbox(buffer);
705                 break;
706
707                 case VBOX_STATE_CALLINFO_DAY: //german month
708                 skip_day_month:
709                 e_vbox_state = VBOX_STATE_CALLINFO_HOUR;
710                 if (e_ext.vbox_language) {
711                         if (e_vbox_index_hour == 1)
712                                 SCPY(buffer, "number_ein");
713                         else
714                                 SPRINT(buffer, "number_%02d", e_vbox_index_hour); /* 1-23 hours */
715                 } else {
716                         SPRINT(buffer, "number_%02d", ((e_vbox_index_hour+11)%12)+1); /* 12 hours am/pm */
717                 }
718                 set_tone_vbox(buffer);
719                 break;
720
721                 case VBOX_STATE_CALLINFO_HOUR:
722                 e_vbox_state = VBOX_STATE_CALLINFO_OCLOCK;
723                 if (e_ext.vbox_language) {
724                         set_tone_vbox("oclock");
725                 } else {
726                         if (e_vbox_index_hour >= 12)
727                                 set_tone_vbox("oclock_pm");
728                         else
729                                 set_tone_vbox("oclock_am");
730                 }
731                 break;
732
733                 case VBOX_STATE_CALLINFO_OCLOCK:
734                 e_vbox_state = VBOX_STATE_CALLINFO_MIN;
735                 if (e_ext.vbox_language) {
736 // german says "zwölfuhr und eins"
737 //                      if (e_vbox_index_min == 1)
738 //                              SCPY(buffer, "number_eine");
739 //                      else
740                                 SPRINT(buffer, "number_%02d", e_vbox_index_min); /* 1-59 minutes */
741                 } else {
742                         SPRINT(buffer, "number_%02d", e_vbox_index_min);
743                 }
744                 set_tone_vbox(buffer);
745                 break;
746
747                 case VBOX_STATE_CALLINFO_MIN:
748                 if (e_ext.vbox_language)
749                         goto start_digits;
750                 e_vbox_state = VBOX_STATE_CALLINFO_MINUTES;
751                 if (e_vbox_index_mday == 1)
752                         set_tone_vbox("minute");
753                 else
754                         set_tone_vbox("minutes");
755                 break;
756
757                 case VBOX_STATE_CALLINFO_MINUTES:
758                 start_digits:
759                 e_vbox_state = VBOX_STATE_CALLINFO_DIGIT;
760                 if (e_vbox_index_callerid[0]=='\0' || !strcmp(e_vbox_index_callerid,"anonymous") || !strcmp(e_vbox_index_callerid,"unknown")) {
761                         set_tone_vbox("call_anonymous");
762                         e_vbox_index_callerid_index = strlen(e_vbox_index_callerid);
763                 } else {
764                         set_tone_vbox("call_from");
765                         e_vbox_index_callerid_index = 0;
766                 }
767                 break;
768
769                 case VBOX_STATE_CALLINFO_DIGIT:
770                 while (e_vbox_index_callerid[e_vbox_index_callerid_index] && (e_vbox_index_callerid[e_vbox_index_callerid_index]<'0' || e_vbox_index_callerid[e_vbox_index_callerid_index]>'9'))
771                         e_vbox_index_callerid_index++;
772                 if (e_vbox_index_callerid[e_vbox_index_callerid_index]) {
773                         SPRINT(buffer, "number_%02d", e_vbox_index_callerid[e_vbox_index_callerid_index]-'0');
774                         set_tone_vbox(buffer);
775                         e_vbox_index_callerid_index ++;
776                 } else {
777                         /* the callinfo is played, so we start with the call */
778                         e_vbox_counter = 0;
779                         e_vbox_counter_max = 0;
780                         e_vbox_speed = 1;
781                         e_vbox_state = VBOX_STATE_PLAY;
782                         schedule_timer(&e_vbox_refresh, 0, 0);
783                         SPRINT(e_vbox_display, "#%d %%s", e_vbox_play);
784                         if (e_ext.vbox_display == VBOX_DISPLAY_DETAILED)
785                                 UPRINT(strchr(e_vbox_display,'\0'), " (%s)", e_vbox_index_callerid);
786                         schedule_timer(&e_vbox_refresh, 0, 0);
787                         set_play_vbox(e_vbox_index_file, 0);
788                 }
789                 break;
790
791                 case VBOX_STATE_RECORD_ASK:
792                 set_tone_vbox("record_ask");
793                 schedule_timer(&e_vbox_refresh, 0, 0);
794                 break;
795
796                 case VBOX_STATE_STORE_ASK:
797                 set_tone_vbox("store_ask");
798                 schedule_timer(&e_vbox_refresh, 0, 0);
799                 break;
800
801                 case VBOX_STATE_DELETE_ASK:
802                 set_tone_vbox("delete_ask");
803                 schedule_timer(&e_vbox_refresh, 0, 0);
804                 break;
805
806                 case VBOX_STATE_RECORD_PLAY:
807                 e_vbox_state = VBOX_STATE_RECORD_ASK;
808                 SCPY(e_vbox_display, (char *)((language)?"1=Aufn. 2=Wied. 3=nein":"1=record 2=play 3=no"));
809                 schedule_timer(&e_vbox_refresh, 0, 0);
810                 set_tone_vbox("record_ask");
811                 break;
812
813                 case VBOX_STATE_STORE_DONE:
814                 case VBOX_STATE_DELETE_DONE:
815                 if (e_vbox_index_num == 0) { /* nothing to play */
816                         e_vbox_state = VBOX_STATE_MENU;
817                         SCPY(e_vbox_display, (char *)((language)?"keine Anrufe":"no calls"));
818                 schedule_timer(&e_vbox_refresh, 0, 0);
819                         set_tone_vbox("nothing");
820                 } else {
821                         e_vbox_state = VBOX_STATE_MENU;
822                         SCPY(e_vbox_display, (char *)((language)?"druecke 2 f. wiedergabe":"press 2 to play"));
823                 schedule_timer(&e_vbox_refresh, 0, 0);
824                         set_tone_vbox("menu");
825                 }
826                 break;
827
828                 default:
829                 PERROR("vbox_message_eof(ep%d): terminal %s unknown state: %d\n", ea_endpoint->ep_serial, e_ext.number, e_vbox_state);
830         }
831 }
832
833
834
835 /*
836  * set the given vbox-tone with full path (without appending)
837  * the tone is played and after eof, a message is received
838  */
839 void EndpointAppPBX::set_tone_vbox(const char *tone)
840 {
841         struct lcr_msg *message;
842
843         if (tone == NULL)
844                 tone = "";
845
846         if (!ea_endpoint->ep_portlist) {
847                 PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
848         }
849         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_TONE);
850         SCPY(message->param.tone.dir, ((e_ext.vbox_language) ? "vbox_german" : "vbox_english"));
851         SCPY(message->param.tone.name, tone);
852         message_put(message);
853
854         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set tone '%s'\n", ea_endpoint->ep_serial, e_ext.number, tone);
855 }
856
857
858 /*
859  * set the given recording file
860  * the appendix is removed
861  * the file is played and after eof, a message is received
862  * the current counter value is also received by a message
863  * set the offset in seconds of the current recording
864  */
865 void EndpointAppPBX::set_play_vbox(const char *file, int offset)
866 {
867         char filename[256];
868         struct lcr_msg *message;
869
870         SPRINT(filename, "%s/%s/vbox/%s", EXTENSION_DATA, e_vbox, file);
871         
872         /* remove .wav */
873         if (!strcmp(filename+strlen(filename)-4, ".wav")) /* filename is always more than 4 digits long */
874                 filename[strlen(filename)-4] = '\0';
875         else // to not check twice
876         /* remove .isdn */
877         if (!strcmp(filename+strlen(filename)-5, ".isdn")) /* filename is always more than 5 digits long */
878                 filename[strlen(filename)-5] = '\0';
879
880         if (!ea_endpoint->ep_portlist) {
881                 PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
882         }
883         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_PLAY);
884         SCPY(message->param.play.file, filename);
885         message->param.play.offset = offset;
886         message_put(message);
887
888         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set play '%s'\n", ea_endpoint->ep_serial, e_ext.number, filename);
889 }
890
891
892 /*
893  * change speed of the recording file, the default is 1
894  * negative values cause negative speed
895  */
896 void EndpointAppPBX::set_play_speed(int speed)
897 {
898         struct lcr_msg *message;
899
900         if (!ea_endpoint->ep_portlist) {
901                 PERROR("EPOINT(%d) no portlist\n", ea_endpoint->ep_serial);
902         }
903         message = message_create(ea_endpoint->ep_serial, ea_endpoint->ep_portlist->port_id, EPOINT_TO_PORT, MESSAGE_VBOX_PLAY_SPEED);
904         message->param.speed = speed;
905         message_put(message);
906
907         PDEBUG(DEBUG_EPOINT, "EPOINT(%d) terminal %s set speed '%d'\n", ea_endpoint->ep_serial, e_ext.number, speed);
908 }
909
910
911