aboutsummaryrefslogtreecommitdiffstats
path: root/channels/chan_agent.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels/chan_agent.c')
-rw-r--r--channels/chan_agent.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/channels/chan_agent.c b/channels/chan_agent.c
index 277ebda09..5ca44251c 100644
--- a/channels/chan_agent.c
+++ b/channels/chan_agent.c
@@ -67,6 +67,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
+#include "asterisk/event.h"
static const char tdesc[] = "Call Agent Proxy Channel";
static const char config[] = "agents.conf";
@@ -147,6 +148,7 @@ static char urlprefix[AST_MAX_BUF] = "";
static char savecallsin[AST_MAX_BUF] = "";
static int updatecdr = 0;
static char beep[AST_MAX_BUF] = "beep";
+struct ast_event_sub *agent_devicestate_sub = NULL;
#define GETAGENTBYCALLERID "AGENTBYCALLERID"
@@ -171,6 +173,7 @@ struct agent_pvt {
char agent[AST_MAX_AGENT]; /*!< Agent ID */
char password[AST_MAX_AGENT]; /*!< Password for Agent login */
char name[AST_MAX_AGENT];
+ int inherited_devicestate; /*!< Does the underlying channel have a devicestate to pass? */
ast_mutex_t app_lock; /**< Synchronization between owning applications */
volatile pthread_t owning_app; /**< Owning application thread id */
volatile int app_sleep_cond; /**< Sleep condition for the login app */
@@ -261,6 +264,48 @@ static const struct ast_channel_tech agent_tech = {
.set_base_channel = agent_set_base_channel,
};
+static void agent_devicestate_cb(const struct ast_event *event, void *unused)
+{
+ int res, i;
+ struct agent_pvt *p;
+ char basename[AST_CHANNEL_NAME], *tmp;
+ const char *device;
+ enum ast_device_state state;
+
+ /* Try to be safe, but don't deadlock */
+ for (i = 0; i < 10; i++) {
+ if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
+ break;
+ }
+ }
+ if (res) {
+ return;
+ }
+
+ state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
+ device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
+
+ if (ast_strlen_zero(device)) {
+ return;
+ }
+
+ AST_LIST_TRAVERSE(&agents, p, list) {
+ ast_mutex_lock(&p->lock);
+ if (p->chan) {
+ ast_copy_string(basename, p->chan->name, sizeof(basename));
+ if ((tmp = strrchr(basename, '-'))) {
+ *tmp = '\0';
+ }
+ if (strcasecmp(p->chan->name, device) == 0 || strcasecmp(basename, device) == 0) {
+ p->inherited_devicestate = state;
+ ast_device_state_changed("Agent/%s", p->agent);
+ }
+ }
+ ast_mutex_unlock(&p->lock);
+ }
+ AST_LIST_UNLOCK(&agents);
+}
+
/*!
* Adds an agent to the global list of agents.
*
@@ -323,6 +368,7 @@ static struct agent_pvt *add_agent(const char *agent, int pending)
p->app_sleep_cond = 1;
p->group = group;
p->pending = pending;
+ p->inherited_devicestate = -1;
AST_LIST_INSERT_TAIL(&agents, p, list);
}
@@ -466,6 +512,7 @@ static struct ast_frame *agent_read(struct ast_channel *ast)
p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
}
p->chan = NULL;
+ p->inherited_devicestate = -1;
p->acknowledged = 0;
}
} else {
@@ -680,6 +727,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout)
} else {
/* Agent hung-up */
p->chan = NULL;
+ p->inherited_devicestate = -1;
}
if (!res) {
@@ -800,6 +848,7 @@ static int agent_hangup(struct ast_channel *ast)
/* Recognize the hangup and pass it along immediately */
ast_hangup(p->chan);
p->chan = NULL;
+ p->inherited_devicestate = -1;
}
ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
@@ -1523,6 +1572,7 @@ static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long
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();
@@ -2078,8 +2128,10 @@ static int login_exec(struct ast_channel *chan, void *data)
if (res && p->owner)
ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
/* Log us off if appropriate */
- if (p->chan == chan)
+ if (p->chan == chan) {
p->chan = NULL;
+ p->inherited_devicestate = -1;
+ }
p->acknowledged = 0;
logintime = time(NULL) - p->loginstart;
p->loginstart = 0;
@@ -2292,6 +2344,8 @@ static int agent_devicestate(void *data)
if (p->owner) {
if (res != AST_DEVICE_INUSE)
res = AST_DEVICE_BUSY;
+ } else if (p->inherited_devicestate > -1) {
+ res = p->inherited_devicestate;
} else {
if (res == AST_DEVICE_BUSY)
res = AST_DEVICE_INUSE;
@@ -2433,6 +2487,8 @@ static int load_module(void)
/* Dialplan Functions */
ast_custom_function_register(&agent_function);
+ agent_devicestate_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, agent_devicestate_cb, NULL);
+
return AST_MODULE_LOAD_SUCCESS;
}
@@ -2450,6 +2506,8 @@ static int unload_module(void)
struct agent_pvt *p;
/* First, take us out of the channel loop */
ast_channel_unregister(&agent_tech);
+ /* Delete devicestate subscription */
+ agent_devicestate_sub = ast_event_unsubscribe(agent_devicestate_sub);
/* Unregister dialplan functions */
ast_custom_function_unregister(&agent_function);
/* Unregister CLI commands */