/** *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 #include #include 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; }