📄 chan_agent.c
字号:
if (!secret) secret = ""; snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); add_agent(tmp, 0); } } catname = ast_category_browse(ucfg, catname); } ast_config_destroy(ucfg); } AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { if (p->dead) { AST_LIST_REMOVE_CURRENT(&agents, list); /* Destroy if appropriate */ if (!p->owner) { if (!p->chan) { ast_mutex_destroy(&p->lock); ast_mutex_destroy(&p->app_lock); free(p); } else { /* Cause them to hang up */ ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); } } } } AST_LIST_TRAVERSE_SAFE_END AST_LIST_UNLOCK(&agents); ast_config_destroy(cfg); return 1;}static int check_availability(struct agent_pvt *newlyavailable, int needlock){ struct ast_channel *chan=NULL, *parent=NULL; struct agent_pvt *p; int res; if (option_debug) ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); if (needlock) AST_LIST_LOCK(&agents); AST_LIST_TRAVERSE(&agents, p, list) { if (p == newlyavailable) { continue; } ast_mutex_lock(&p->lock); if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { if (option_debug) ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); /* We found a pending call, time to merge */ chan = agent_new(newlyavailable, AST_STATE_DOWN); parent = p->owner; p->abouttograb = 1; ast_mutex_unlock(&p->lock); break; } ast_mutex_unlock(&p->lock); } if (needlock) AST_LIST_UNLOCK(&agents); if (parent && chan) { if (newlyavailable->ackcall > 1) { /* Don't do beep here */ res = 0; } else { if (option_debug > 2) ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); if (option_debug > 2) ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); if (!res) { res = ast_waitstream(newlyavailable->chan, ""); ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); } } if (!res) { /* Note -- parent may have disappeared */ if (p->abouttograb) { newlyavailable->acknowledged = 1; /* Safe -- agent lock already held */ ast_setstate(parent, AST_STATE_UP); ast_setstate(chan, AST_STATE_UP); ast_copy_string(parent->context, chan->context, sizeof(parent->context)); /* Go ahead and mark the channel as a zombie so that masquerade will destroy it for us, and we need not call ast_hangup */ ast_mutex_lock(&parent->lock); ast_set_flag(chan, AST_FLAG_ZOMBIE); ast_channel_masquerade(parent, chan); ast_mutex_unlock(&parent->lock); p->abouttograb = 0; } else { if (option_debug) ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); agent_cleanup(newlyavailable); } } else { if (option_debug) ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); agent_cleanup(newlyavailable); } } return 0;}static int check_beep(struct agent_pvt *newlyavailable, int needlock){ struct agent_pvt *p; int res=0; ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); if (needlock) AST_LIST_LOCK(&agents); AST_LIST_TRAVERSE(&agents, p, list) { if (p == newlyavailable) { continue; } ast_mutex_lock(&p->lock); if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { if (option_debug) ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); ast_mutex_unlock(&p->lock); break; } ast_mutex_unlock(&p->lock); } if (needlock) AST_LIST_UNLOCK(&agents); if (p) { ast_mutex_unlock(&newlyavailable->lock); if (option_debug > 2) ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); if (option_debug > 2) ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); if (!res) { res = ast_waitstream(newlyavailable->chan, ""); if (option_debug) ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); } ast_mutex_lock(&newlyavailable->lock); } return res;}/* return 1 if multiple login is fine, 0 if it is not and we find a match, -1 if multiplelogin is not allowed and we don't find a match. */static int allow_multiple_login(char *chan, char *context){ struct agent_pvt *p; char loginchan[80]; if(multiplelogin) return 1; if(!chan) return 0; snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); AST_LIST_TRAVERSE(&agents, p, list) { if(!strcasecmp(chan, p->loginchan)) return 0; } return -1;}/*! \brief Part of the Asterisk PBX interface */static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause){ struct agent_pvt *p; struct ast_channel *chan = NULL; char *s; ast_group_t groupmatch; int groupoff; int waitforagent=0; int hasagent = 0; struct timeval tv; s = data; if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { groupmatch = (1 << groupoff); } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { groupmatch = (1 << groupoff); waitforagent = 1; } else groupmatch = 0; /* Check actual logged in agents first */ AST_LIST_LOCK(&agents); AST_LIST_TRAVERSE(&agents, p, list) { ast_mutex_lock(&p->lock); if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && ast_strlen_zero(p->loginchan)) { if (p->chan) hasagent++; tv = ast_tvnow(); if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { p->lastdisc = ast_tv(0, 0); /* Agent must be registered, but not have any active call, and not be in a waiting state */ if (!p->owner && p->chan) { /* Fixed agent */ chan = agent_new(p, AST_STATE_DOWN); } if (chan) { ast_mutex_unlock(&p->lock); break; } } } ast_mutex_unlock(&p->lock); } if (!p) { AST_LIST_TRAVERSE(&agents, p, list) { ast_mutex_lock(&p->lock); if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { if (p->chan || !ast_strlen_zero(p->loginchan)) hasagent++; tv = ast_tvnow();#if 0 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);#endif if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { p->lastdisc = ast_tv(0, 0); /* Agent must be registered, but not have any active call, and not be in a waiting state */ if (!p->owner && p->chan) { /* Could still get a fixed agent */ chan = agent_new(p, AST_STATE_DOWN); } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { /* Adjustable agent */ p->chan = ast_request("Local", format, p->loginchan, cause); if (p->chan) chan = agent_new(p, AST_STATE_DOWN); } if (chan) { ast_mutex_unlock(&p->lock); break; } } } ast_mutex_unlock(&p->lock); } } if (!chan && waitforagent) { /* No agent available -- but we're requesting to wait for one. Allocate a place holder */ if (hasagent) { if (option_debug) ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); p = add_agent(data, 1); p->group = groupmatch; chan = agent_new(p, AST_STATE_DOWN); if (!chan) ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); } else ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); } *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; AST_LIST_UNLOCK(&agents); return chan;}static force_inline int powerof(unsigned int d){ int x = ffs(d); if (x) return x - 1; return 0;}/*! * Lists agents and their status to the Manager API. * It is registered on load_module() and it gets called by the manager backend. * \param s * \param m * \returns * \sa action_agent_logoff(), action_agent_callback_login(), load_module(). */static int action_agents(struct mansession *s, const struct message *m){ const char *id = astman_get_header(m,"ActionID"); char idText[256] = ""; char chanbuf[256]; struct agent_pvt *p; char *username = NULL; char *loginChan = NULL; char *talkingtoChan = NULL; char *status = NULL; if (!ast_strlen_zero(id)) snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); astman_send_ack(s, m, "Agents will follow"); AST_LIST_LOCK(&agents); AST_LIST_TRAVERSE(&agents, p, list) { ast_mutex_lock(&p->lock); /* Status Values: AGENT_LOGGEDOFF - Agent isn't logged in AGENT_IDLE - Agent is logged in, and waiting for call AGENT_ONCALL - Agent is logged in, and on a call AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ username = S_OR(p->name, "None"); /* Set a default status. It 'should' get changed. */ status = "AGENT_UNKNOWN"; if (!ast_strlen_zero(p->loginchan) && !p->chan) { loginChan = p->loginchan; talkingtoChan = "n/a"; status = "AGENT_IDLE"; if (p->acknowledged) { snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); loginChan = chanbuf; } } else if (p->chan) { loginChan = ast_strdupa(p->chan->name); if (p->owner && p->owner->_bridge) { if (ast_bridged_channel(p->owner)) { talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, "")); } else { talkingtoChan = "n/a"; } status = "AGENT_ONCALL"; } else { talkingtoChan = "n/a"; status = "AGENT_IDLE"; } } else { loginChan = "n/a"; talkingtoChan = "n/a"; status = "AGENT_LOGGEDOFF"; } astman_append(s, "Event: Agents\r\n" "Agent: %s\r\n" "Name: %s\r\n" "Status: %s\r\n" "LoggedInChan: %s\r\n" "LoggedInTime: %d\r\n" "TalkingTo: %s\r\n" "%s" "\r\n", p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); ast_mutex_unlock(&p->lock); } AST_LIST_UNLOCK(&agents); astman_append(s, "Event: AgentsComplete\r\n" "%s" "\r\n",idText); return 0;}static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand){ char *tmp = NULL; char agent[AST_MAX_AGENT]; if (!ast_strlen_zero(logcommand)) tmp = logcommand; else tmp = ast_strdupa(""); snprintf(agent, sizeof(agent), "Agent/%s", p->agent); if (!ast_strlen_zero(uniqueid)) { manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", "Agent: %s\r\n" "Reason: %s\r\n" "Loginchan: %s\r\n" "Logintime: %ld\r\n" "Uniqueid: %s\r\n", p->agent, tmp, loginchan, logintime, uniqueid); } else { manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", "Agent: %s\r\n" "Reason: %s\r\n" "Loginchan: %s\r\n" "Logintime: %ld\r\n", p->agent, tmp, loginchan, logintime); } ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); set_agentbycallerid(p->logincallerid, NULL); p->loginchan[0] ='\0'; p->logincallerid[0] = '\0'; p->inherited_devicestate = -1; ast_device_state_changed("Agent/%s", p->agent); if (persistent_agents) dump_agents(); }static int agent_logoff(const char *agent, int soft){ struct agent_pvt *p; long logintime; int ret = -1; /* Return -1 if no agent if found */ AST_LIST_LOCK(&agents); AST_LIST_TRAVERSE(&agents, p, list) { if (!strcasecmp(p->agent, agent)) { ret = 0; if (p->owner || p->chan) { if (!soft) { ast_mutex_lock(&p->lock); while (p->owner && ast_channel_trylock(p->owner)) { DEADLOCK_AVOIDANCE(&p->lock); } if (p->owner) { ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -