- /**
- *This code is developed to handle outboud socket requests from mod_inmate.
- *USE: originate bleg and play prompt for callee on based of callee's reply in ivr either bridge call or hangup.
- * also handle hangup scenarios of bleg and aleg before bridging call.
- *
- * tab : 8
- * indent : 4
- * */
- #include <stdio.h>
- #include <stdlib.h>
- #include <esl.h>
- static void mycallback(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr, void *user_data)
- {
- esl_handle_t handle = {{0}};
- char cmd[512] = "";
- int done = 0;
- int set = 0;
- esl_status_t status;
- time_t exp = 0;
- int prompt_Play = 0; /* flag to check if prompt is played or not on bleg */
- /**
- *Create a child process for each socket connection request
- * */
- if (fork()) {
- return;
- }
- /**
- *GET socket connection handle object
- * */
- if (esl_attach_handle(&handle, client_sock, addr) != ESL_SUCCESS) {
- return;
- }
- esl_log(ESL_LOG_INFO, "Connected! %d\n", handle.sock);
- /**
- *Filter all events for only one channel and get ani number,dst number,channel uuid,
- *max_try,max_call_time and ring timeout values from channel
- * */
- esl_filter(&handle, "unique-id", esl_event_get_header(handle.info_event, "caller-unique-id"));
- const char *ani = esl_event_get_header(handle.info_event, "caller-ani");
- const char *dst = esl_event_get_header(handle.info_event, "caller-destination-number");
- const char *uuid = esl_event_get_header(handle.info_event, "caller-unique-id");
- const char *try = esl_event_get_header(handle.info_event, "variable_max_try");
- const char *call_time = esl_event_get_header(handle.info_event, "variable_max_call_time");
- const char *timeout = esl_event_get_header(handle.info_event, "variable_ring_timeout");
- //esl_log(ESL_LOG_INFO, "HELLOOOOO [%s]::::[%s]::::[%s]\n", ani,dst,uuid);
- esl_events(&handle, ESL_EVENT_TYPE_PLAIN, "SESSION_HEARTBEAT CHANNEL_ANSWER CHANNEL_HANGUP BACKGROUND_JOB CHANNEL_BRIDGE CHANNEL_EXECUTE CHANNEL_EXECUTE_COMPLETE DTMF"); /* select which events we want to get(subscribe) from freeswitch */
- esl_send_recv(&handle, "linger"); /* Do not close socket even if channel is hungup wait till all channel events are completed.*/
- /**
- *Originate bleg using API in background
- * */
- snprintf(cmd,sizeof(cmd),"bgapi call_bridge %s %s %s %s %s \n\n", ani, dst, uuid, try, timeout);
- esl_send_recv(&handle,cmd);
- //printf("%s\n", handle.last_sr_reply);
- esl_execute(&handle, "sleep", "2000", NULL);
- /**
- *recieve timed events (time_period:10sec)
- * */
- while((status = esl_recv_timed(&handle, 10000)) != ESL_FAIL) {
- if (done) {
- if (time(NULL) >= exp) {
- break;
- }
- } else if (status == ESL_SUCCESS) {
- const char *type = esl_event_get_header(handle.last_event, "content-type");
- if (type && !strcasecmp(type, "text/event-plain")) {
- const char *eventname = esl_event_get_header(handle.last_ievent, "event-name");
- esl_log(ESL_LOG_INFO, "########################################################################## %s.\n",eventname);
- /* *
- *Filter channel b events along with channel a events
- * */
- const char *bleg = esl_event_get_header(handle.last_ievent, "variable_bleg_uuid");
- if(set == 0 && bleg){
- esl_filter(&handle, "unique-id", bleg);
- set = 1;
- }
- /**
- *Handle DTMF event from b leg
- *
- *if 1 is pressed check if call_time is less than 120 play prompt on a leg
- *and set bleg_state as BRIDGE_CALL
- * */
- if( eventname && !strcasecmp(eventname, "DTMF")){
- const char *dtmf = esl_event_get_header(handle.last_ievent, "DTMF-Digit");
- if( dtmf && !strcasecmp(dtmf, "1")){
- printf("##################### CALL TIME :::: %s %d\n", call_time,strcmp("120",call_time));
- if(strcmp("120",call_time) >= 0 ){
- esl_execute(&handle, "playback", "/home/inmate_fs_data/sounds/en/less_than_2_min.wav", NULL);
- prompt_Play = 1;
- }
- char bridge[100] = "";
- snprintf(bridge,sizeof(bridge),"api uuid_setvar %s bleg_state BRIDGE_CALL",uuid);
- esl_log(ESL_LOG_CRIT, "&&&&&&& ACCEPTED on bleg %s.\n",bridge);
- esl_send_recv(&handle,bridge);
- printf("%s\n", handle.last_sr_reply);
- if( prompt_Play == 0){ /* If prompt is not played disconnect socket */
- done = 1;
- break;
- }
- }
- }
- /* *
- * if prompt flag is set and prompt playing is over on leg a than disconnect socket
- * */
- if( eventname && !strcasecmp(eventname, "CHANNEL_EXECUTE_COMPLETE") ){
- //esl_log(ESL_LOG_CRIT, "&&&&&&&&&&&&&&&&&&&&&&& PROMPT PLAYING SET %s %d.\n",eventname,prompt_Play);
- const char *playback = esl_event_get_header(handle.last_ievent, "Application-Response");
- const char *leg_owner = esl_event_get_header(handle.last_ievent, "variable_owner");
- esl_log(ESL_LOG_CRIT, "&&&&&&&&&&&&&&&&&&&&&&& PROMPT PLAYING SET %s %s %s.\n",playback,leg_owner,bleg);
- if( playback && !strcasecmp(playback, "FILE PLAYED") && ( prompt_Play == 1) ){
- if( leg_owner && bleg && !strcasecmp(leg_owner, "aleg")){
- done =1;
- break;
- }
- }
- }
- /*
- * Handle Hangup related events and set bleg state if bleg is hungup before bridge with its cause.
- **/
- if( eventname && !strcasecmp(eventname, "CHANNEL_HANGUP")){
- const char *owner = esl_event_get_header(handle.last_ievent, "variable_owner");
- //esl_log(ESL_LOG_INFO, "########################################################################## %s.\n",owner);
- if( owner && bleg && !strcasecmp(owner, "aleg")){ /*if bleg is initiated and aleg is hungup than kill bleg channel*/
- snprintf(cmd,sizeof(cmd),"api uuid_kill %s\n\n", bleg);
- esl_log(ESL_LOG_CRIT, "&&&&&&& HANGUP RECIEVED on aleg %s.\n",cmd);
- esl_send_recv(&handle,cmd);
- printf("%s\n", handle.last_sr_reply);
- }else if(owner && !strcasecmp(owner, "bleg")){ /* Handle bleg hangup cases */
- char *cause = esl_event_get_header(handle.last_ievent, "Hangup-Cause");
- esl_log(ESL_LOG_CRIT, "&&&&&&& HANGUP RECIEVED on bleg. %s\n",cause);
- if(cause && !strcasecmp(cause,"SUCCESS")){
- /* if hangup cause is success check ivr read status if failure/num invalid set bleg-state to NOANSWER */
- const char *read_status = esl_event_get_header(handle.last_ievent, "variable_read_result");
- if( read_status && !strcasecmp(read_status,"failure")){
- esl_log(ESL_LOG_CRIT, "&&&&&&& READ STATUS RECIEVED on bleg %s.\n",read_status);
- cause = "NO_ANSWER";
- }else if ( read_status && !strcasecmp(read_status,"success")){
- const char *inv_num = esl_event_get_header(handle.last_ievent, "variable_num_invalid");
- esl_log(ESL_LOG_CRIT, "&&&&&&& READ STATUS RECIEVED on bleg %s %s.\n",read_status,inv_num);
- if( inv_num ){
- esl_log(ESL_LOG_CRIT, "&&&&&&& READ STATUS INV RECIEVED on bleg %s.\n",read_status);
- cause = "NO_ANSWER";
- }
- }
- }
- char state[100] = "";
- snprintf(state,sizeof(state),"api uuid_setvar %s bleg_state %s",uuid,cause);
- esl_log(ESL_LOG_CRIT, "&&&&&&& HANGUP RECIEVED on bleg %s.\n",state);
- esl_send_recv(&handle,state);
- printf("%s\n", handle.last_sr_reply);
- done = 1;
- break;
- }
- }
- }
- }
- }
- esl_log(ESL_LOG_INFO, "Disconnected! %d\n", handle.sock);
- esl_disconnect(&handle);
- }
- static esl_socket_t server_sock = ESL_SOCK_INVALID;
- static void handle_sig(int sig)
- {
- shutdown(server_sock, 2);
- }
- int main(void)
- {
- signal(SIGINT, handle_sig);
- signal(SIGCHLD, SIG_IGN);
- esl_global_set_default_logger(7);
- esl_listen("localhost", 8040, mycallback, NULL, &server_sock);
- return 0;
- }