int add_cc_agent( struct cc_data *data, str *id, str *location, str *skills, unsigned int logstate, unsigned int last_call_end) { struct cc_agent *agent, *prev_agent= 0; struct sip_uri uri; str skill; char *p; unsigned int n,skill_id; #ifdef STATISTICS char *name; str s; #endif /* is the agent a new one? - search by ID */ agent = get_agent_by_name( data, id, &prev_agent); if (agent==NULL) { /* new agent -> create and populate one */ agent = (struct cc_agent*)shm_malloc(sizeof(struct cc_agent)+id->len); if (agent==NULL) { LM_ERR("not enough shmem for a new agent\n"); goto error; } memset( agent, 0, sizeof(struct cc_agent) ); /* id */ agent->id.s = (char*)(agent+1); memcpy( agent->id.s, id->s, id->len); agent->id.len = id->len; /* location */ agent->location.s = (char*)shm_malloc(location->len); if (agent->location.s==NULL) { LM_ERR("not enough shmem for the location of the agent\n"); goto error; } memcpy( agent->location.s, location->s, location->len); agent->location.len = location->len; if (parse_uri( agent->location.s, agent->location.len, &uri)<0) { LM_ERR("location of the agent is not a SIP URI\n"); goto error; } agent->did = uri.user; /* LOG STATE */ agent->loged_in = logstate; /* set of skills */ if (skills && skills->len) { p = skills->s; while (p) { skill.s = p; p = q_memchr(skill.s, ',', skills->s+skills->len-skill.s); skill.len = p?(p-skill.s):(skills->s+skills->len-skill.s); trim(&skill); if (skill.len) { skill_id = get_skill_id(data,&skill); if (skill_id==0) { LM_ERR("cannot get skill id\n"); goto error; } n = agent->no_skills++; agent->skills[n] = skill_id; } if(p) p++; } } /* statistics */ #ifdef STATISTICS s.s = "cca_dist_incalls";s.len = 16 ; if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", name, &agent->st_dist_incalls, STAT_SHM_NAME)!=0 ) { LM_ERR("failed to add stat variable\n"); goto error; } s.s = "cca_answ_incalls";s.len = 16 ; if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", name, &agent->st_answ_incalls, STAT_SHM_NAME)!=0 ) { LM_ERR("failed to add stat variable\n"); goto error; } s.s = "cca_aban_incalls";s.len = 16 ; if ( (name=build_stat_name( &s, id->s))==0 || register_stat("call_center", name, &agent->st_aban_incalls, STAT_SHM_NAME)!=0 ) { LM_ERR("failed to add stat variable\n"); goto error; } s.s = "cca_att";s.len = 7 ; if ( (name=build_stat_name( &s, id->s))==0 || register_stat2("call_center", name, (stat_var **)cc_agent_get_att, STAT_SHM_NAME|STAT_IS_FUNC, (void*)agent, 0)!=0) { LM_ERR("failed to add stat variable\n"); goto error; } #endif if(last_call_end && (last_call_end + wrapup_time < (int)time(NULL))) { agent->state = CC_AGENT_WRAPUP; agent->last_call_end = last_call_end - startup_time; /* it will be a negative value */ } agent->is_new = 1; /* link the agent */ add_cc_agent_top(data, agent); data->totalnr_agents++; } else { /* agent already exists -> update only */ /* location - needs to be changed ? */ if ( agent->location.len!=location->len || memcmp(agent->location.s,location->s,location->len)!=0 ) { /* set new location */ if (agent->location.len < location->len ){ shm_free(agent->location.s); agent->location.s = (char*)shm_malloc(location->len); if (agent->location.s==NULL) { LM_ERR("not enough shmem for the location of the agent\n"); goto error1; } } memcpy( agent->location.s, location->s, location->len); agent->location.len = location->len; if (parse_uri( agent->location.s, agent->location.len, &uri)<0) { LM_ERR("location of the agent is not a SIP URI\n"); goto error1; } agent->did = uri.user; } /* if logstate changed - move between the lists TODO */ if(logstate != agent->loged_in) { agent_switch_login(data, agent, prev_agent); } /* skills - needs to be changed ? */ agent->no_skills = 0; if (skills && skills->len) { p = skills->s; while (p) { skill.s = p; p = q_memchr(skill.s, ',', skills->s+skills->len-skill.s); skill.len = p?(p-skill.s):(skills->s+skills->len-skill.s); trim(&skill); if (skill.len) { skill_id = get_skill_id(data,&skill); if (skill_id==0) { LM_ERR("cannot get skill id\n"); goto error1; } n = agent->no_skills++; agent->skills[n] = skill_id; } if(p) p++; } } agent->is_new = 1; } return 0; error1: remove_cc_agent(data, agent, prev_agent); error: if (agent) free_cc_agent(agent); return 0; }
static void cc_timer_agents(unsigned int ticks, void* param) { struct cc_agent *agent, *prev_agent, *tmp_ag; struct cc_call *call; str out; str dest; if (data==NULL || data->agents[CC_AG_ONLINE]==NULL) return; do { lock_get( data->lock ); prev_agent = data->agents[CC_AG_ONLINE]; agent = data->agents[CC_AG_ONLINE]; call = NULL; /* iterate all agents*/ do { //LM_DBG("%.*s , state=%d, last_call_end=%u, ticks=%u, wrapup=%u\n", // agent->id.len, agent->id.s, agent->state, agent->last_call_end, ticks, wrapup_time); /* for agents in WRAPUP time, check if expired */ if ( (agent->state==CC_AGENT_WRAPUP) && (ticks - agent->last_call_end > wrapup_time)) { agent->state = CC_AGENT_FREE; /* move it to the end of the list*/ if(data->last_online_agent != agent) { remove_cc_agent(data, agent, prev_agent); if(!data->last_online_agent) { LM_CRIT("last_online_agent NULL\n"); if(data->agents[CC_AG_ONLINE] == NULL) data->agents[CC_AG_ONLINE] = agent; else { for (tmp_ag = data->agents[CC_AG_ONLINE]; tmp_ag; tmp_ag= tmp_ag->next) { prev_agent = tmp_ag; } prev_agent->next = agent; agent->next = NULL; data->last_online_agent = agent; } } else { data->last_online_agent->next = agent; agent->next = NULL; data->last_online_agent = agent; } goto next_ag; } } /* for free agents -> check for calls */ if ( (data->queue.calls_no!=0) && (agent->state==CC_AGENT_FREE) ) { call = cc_queue_pop_call_for_agent( data, agent); if (call) { /* found a call for the agent */ break; } } next_ag: /* next agent */ prev_agent = agent; agent = agent->next; }while(agent); lock_release( data->lock ); /* no locking here */ if (call) { lock_get( call->lock ); call->ref_cnt--; /* is the call state still valid? (as queued) */ if(call->state != CC_CALL_QUEUED) { if (call->state==CC_CALL_ENDED && call->ref_cnt==0) { lock_release( call->lock ); free_cc_call( data, call); } else { lock_release( call->lock ); } continue; } LM_DBG("Call %p ref= %d, state= %d\n", call, call->ref_cnt, call->state); lock_get( data->lock ); dest = agent->location; /* make a copy for destination to agent */ out.len = OUT_BUF_LEN(dest.len); out.s = out_buf; memcpy( out.s, dest.s, out.len); call->prev_state = call->state; call->state = CC_CALL_TOAGENT; /* call no longer on wait */ LM_DBG("** onhold-- Took out of the queue [%p]\n", call); update_stat( stg_onhold_calls, -1); update_stat( call->flow->st_onhold_calls, -1); /* 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); /* unlock data */ lock_release( data->lock ); /* send call to selected agent */ if (set_call_leg( NULL, call, &out)< 0 ) { LM_ERR("failed to set new destination for call\n"); } lock_release( call->lock ); if(cc_db_update_call(call) < 0) { LM_ERR("Failed to update call in database\n"); } } } while (call); }