void handle_agent_reject(struct cc_call* call, int from_customer, int pickup_time) { str un, fid, aid; str out; //update_stat( stg_aban_incalls, 1); /*abandon from agent */ update_stat( call->agent->st_aban_incalls, 1); call->no_rejections++; /* put call back into queue */ call->state = CC_CALL_QUEUED; call->setup_time = -1; lock_get( data->lock ); /* prepare CDR */ prepare_cdr( call, &un, &fid , &aid); call->agent->state = CC_AGENT_WRAPUP; call->agent->last_call_end = get_ticks(); /* update last call_end for agent */ cc_db_update_agent_end_call(call->agent); call->agent->ref_cnt--; call->agent = NULL; cc_queue_push_call( data, call, 1/*top*/); if(from_customer || call->prev_state != CC_CALL_QUEUED) { out.len = OUT_BUF_LEN(call->flow->recordings[AUDIO_QUEUE].len); out.s = out_buf; memcpy( out.s, call->flow->recordings[AUDIO_QUEUE].s, out.len); } lock_release( data->lock ); if(from_customer || call->prev_state != CC_CALL_QUEUED) { /* send call to queue */ if (set_call_leg( NULL, call, &out)< 0 ) { LM_ERR("failed to set new destination for call\n"); } LM_DBG("onhold++: agent rejected [%p]\n", call); if(from_customer) { update_stat( stg_onhold_calls, 1); update_stat( call->flow->st_onhold_calls, 1); } } /* write CDR */ cc_write_cdr( &un, &fid, &aid, -2, call->recv_time, get_ticks() - call->recv_time, 0 , pickup_time, call->no_rejections-1, call->fst_flags, call->id); cc_db_update_call(call); }
/* this function must be call under * 1) general data lock as it accesses diverent data to calculate the next state * 2) call lock as it is changing the call state */ int cc_call_state_machine(struct cc_data *data, struct cc_call *call, str *leg) { struct cc_agent *agent; str *out = NULL; int state =0; switch (call->state) { case CC_CALL_NONE: /* next should be welcome msg if any */ if ( call->flow->recordings[ AUDIO_WELCOME ].len ) { LM_DBG("selecting WELCOME\n"); out = &(call->flow->recordings[ AUDIO_WELCOME ]); state = CC_CALL_WELCOME; break; } /* no Welcome message -> got for queue/agent */ case CC_CALL_WELCOME: case CC_CALL_QUEUED: /* search for an available agent */ agent = get_free_agent_by_skill( data, call->flow->skill); if (agent) { /* send it to agent */ LM_DBG("selecting AGENT %p (%.*s)\n",agent, agent->id.len, agent->id.s); state = CC_CALL_TOAGENT; out = &agent->location; LM_DBG("moved to TOAGENT from %d, out=%p\n", call->state, out); /* mark agent as used */ agent->state = CC_AGENT_INCALL; call->agent = agent; call->agent->ref_cnt++; update_stat( stg_dist_incalls, 1); update_stat( call->flow->st_dist_incalls, 1); call->fst_flags |= FSTAT_DIST; update_stat( call->agent->st_dist_incalls, +1); break; } else { /* put it into queue */ LM_DBG("selecting QUEUE\n"); out = &(call->flow->recordings[AUDIO_QUEUE]); state = CC_CALL_QUEUED; if(call->state == CC_CALL_QUEUED) { LM_DBG("State is already queued %p\n", call); break; } /* add it to queue */ cc_queue_push_call( data, call, 0); } break; case CC_CALL_TOAGENT: case CC_CALL_ENDED: LM_DBG("selecting END\n"); call->state = CC_CALL_ENDED; return 0; default: LM_CRIT("Bogus state [%p] [%d]\n", call, call->state); } if (out) { leg->s = (char*)pkg_malloc( out->len ); if (leg->s) { leg->len = out->len; memcpy(leg->s,out->s,out->len); call->prev_state = call->state; call->state = state; return 0; } } leg->s = NULL; leg->len = 0; return -1; }