diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 818f61935..535056ecb 100644 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -318,6 +318,7 @@ static void set_agentbycallerid(const char *callerid, const char *agent); static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state); static struct ast_channel* agent_get_base_channel(struct ast_channel *chan); static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base); +static int agent_logoff(const char *agent, int soft); /*! \brief Channel interface description for PBX integration */ static const struct ast_channel_tech agent_tech = { @@ -520,8 +521,12 @@ static struct ast_frame *agent_read(struct ast_channel *ast) struct ast_frame *f = NULL; static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; const char *status; - ast_mutex_lock(&p->lock); + int cur_time = time(NULL); + ast_mutex_lock(&p->lock); CHECK_FORMATS(ast, p); + if (!p->start) { + p->start = cur_time; + } if (p->chan) { ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; @@ -538,19 +543,16 @@ static struct ast_frame *agent_read(struct ast_channel *ast) if (p->chan) ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name); if (p->owner->_state != AST_STATE_UP) { - int howlong = time(NULL) - p->start; - if (p->autologoff && howlong > p->autologoff) { - long logintime = time(NULL) - p->loginstart; + int howlong = cur_time - p->start; + if (p->autologoff && howlong >= p->autologoff) { p->loginstart = 0; ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); - agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); - if (persistent_agents) - dump_agents(); + agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff"); } } status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { - long logintime = time(NULL) - p->loginstart; + long logintime = cur_time - p->loginstart; p->loginstart = 0; ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); @@ -563,28 +565,38 @@ static struct ast_frame *agent_read(struct ast_channel *ast) ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); p->acknowledged = 0; } - } else { - /* if acknowledgement is not required, and the channel is up, we may have missed - an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ - if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) - p->acknowledged = 1; - switch (f->frametype) { - case AST_FRAME_CONTROL: - if (f->subclass == AST_CONTROL_ANSWER) { - if (p->ackcall) { - ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); - /* Don't pass answer along */ - ast_frfree(f); - f = &ast_null_frame; - } else { - p->acknowledged = 1; - /* Use the builtin answer frame for the + } else { + /* if acknowledgement is not required, and the channel is up, we may have missed + an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ + if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { + p->acknowledged = 1; + } + + if (!p->acknowledged) { + int howlong = cur_time - p->start; + if (p->autologoff && (howlong >= p->autologoff)) { + ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); + agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff"); + agent_logoff(p->agent, 0); + } + } + switch (f->frametype) { + case AST_FRAME_CONTROL: + if (f->subclass == AST_CONTROL_ANSWER) { + if (p->ackcall) { + ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); + /* Don't pass answer along */ + ast_frfree(f); + f = &ast_null_frame; + } else { + p->acknowledged = 1; + /* Use the builtin answer frame for the recording start check below. */ - ast_frfree(f); - f = &answer_frame; - } - } - break; + ast_frfree(f); + f = &answer_frame; + } + } + break; case AST_FRAME_DTMF_BEGIN: /*ignore DTMF begin's as it can cause issues with queue announce files*/ if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){ @@ -592,30 +604,30 @@ static struct ast_frame *agent_read(struct ast_channel *ast) f = &ast_null_frame; } break; - case AST_FRAME_DTMF_END: - if (!p->acknowledged && (f->subclass == p->acceptdtmf)) { - ast_verb(3, "%s acknowledged\n", p->chan->name); - p->acknowledged = 1; - ast_frfree(f); - f = &answer_frame; - } else if (f->subclass == p->enddtmf && endcall) { - /* terminates call */ - ast_frfree(f); - f = NULL; - } - break; - case AST_FRAME_VOICE: - case AST_FRAME_VIDEO: - /* don't pass voice or video until the call is acknowledged */ - if (!p->acknowledged) { - ast_frfree(f); - f = &ast_null_frame; - } + case AST_FRAME_DTMF_END: + if (!p->acknowledged && (f->subclass == p->acceptdtmf)) { + ast_verb(3, "%s acknowledged\n", p->chan->name); + p->acknowledged = 1; + ast_frfree(f); + f = &answer_frame; + } else if (f->subclass == p->enddtmf && endcall) { + /* terminates call */ + ast_frfree(f); + f = NULL; + } + break; + case AST_FRAME_VOICE: + case AST_FRAME_VIDEO: + /* don't pass voice or video until the call is acknowledged */ + if (!p->acknowledged) { + ast_frfree(f); + f = &ast_null_frame; + } default: /* pass everything else on through */ break; - } - } + } + } CLEANUP(ast,p); if (p->chan && !p->chan->_bridge) { @@ -1642,7 +1654,7 @@ static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long p->logincallerid[0] = '\0'; ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); if (persistent_agents) - dump_agents(); + dump_agents(); }