Index: channels/chan_agent.c =================================================================== --- channels/chan_agent.c (revision 379385) +++ channels/chan_agent.c (working copy) @@ -272,12 +272,11 @@ int app_lock_flag; ast_cond_t app_complete_cond; ast_cond_t login_wait_cond; - volatile int app_sleep_cond; /**< Sleep condition for the login app */ - struct ast_channel *owner; /**< Agent */ - char logincallerid[80]; /**< Caller ID they had when they logged in */ - struct ast_channel *chan; /**< Channel we use */ - unsigned int flags; /**< Flags show if settings were applied with channel vars */ - AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */ + int app_sleep_cond; /*!< Non-zero if the login app should sleep. */ + struct ast_channel *owner; /*!< Agent */ + struct ast_channel *chan; /*!< Channel we use */ + unsigned int flags; /*!< Flags show if settings were applied with channel vars */ + AST_LIST_ENTRY(agent_pvt) list;/*!< Next Agent in the linked list. */ }; #define DATA_EXPORT_AGENT(MEMBER) \ @@ -288,8 +287,7 @@ MEMBER(agent_pvt, acknowledged, AST_DATA_BOOLEAN) \ MEMBER(agent_pvt, name, AST_DATA_STRING) \ MEMBER(agent_pvt, password, AST_DATA_PASSWORD) \ - MEMBER(agent_pvt, acceptdtmf, AST_DATA_CHARACTER) \ - MEMBER(agent_pvt, logincallerid, AST_DATA_STRING) + MEMBER(agent_pvt, acceptdtmf, AST_DATA_CHARACTER) AST_DATA_STRUCTURE(agent_pvt, DATA_EXPORT_AGENT); @@ -410,6 +408,22 @@ } /*! + * \internal + * \brief Destroy an agent pvt struct. + * + * \param doomed Agent pvt to destroy. + * + * \return Nothing + */ +static void agent_pvt_destroy(struct agent_pvt *doomed) +{ + ast_mutex_destroy(&doomed->lock); + ast_cond_destroy(&doomed->app_complete_cond); + ast_cond_destroy(&doomed->login_wait_cond); + ast_free(doomed); +} + +/*! * Adds an agent to the global list of agents. * * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" @@ -454,11 +468,16 @@ name = args.name; while (*name && *name < 33) name++; } - - /* Are we searching for the agent here ? To see if it exists already ? */ - AST_LIST_TRAVERSE(&agents, p, list) { - if (!pending && !strcmp(p->agent, agt)) - break; + + if (!pending) { + /* Are we searching for the agent here ? To see if it exists already ? */ + AST_LIST_TRAVERSE(&agents, p, list) { + if (!strcmp(p->agent, agt)) { + break; + } + } + } else { + p = NULL; } if (!p) { // Build the agent. @@ -540,18 +559,13 @@ } if (p->dead) { ast_mutex_unlock(&p->lock); - ast_mutex_destroy(&p->lock); - ast_cond_destroy(&p->app_complete_cond); - ast_cond_destroy(&p->login_wait_cond); - ast_free(p); + agent_pvt_destroy(p); } else { ast_mutex_unlock(&p->lock); } return 0; } -static int check_availability(struct agent_pvt *newlyavailable, int needlock); - static int agent_answer(struct ast_channel *ast) { ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); @@ -708,8 +722,7 @@ if (p->chan && !p->chan->_bridge) { if (strcasecmp(p->chan->tech->type, "Local")) { p->chan->_bridge = ast; - if (p->chan) - ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); + ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); } } ast_mutex_unlock(&p->lock); @@ -783,23 +796,19 @@ { struct agent_pvt *p = ast->tech_pvt; int res = -1; + ast_mutex_lock(&p->lock); if (p->chan && !ast_check_hangup(p->chan)) { - while (ast_channel_trylock(p->chan)) { - int res; - if ((res = ast_channel_unlock(ast))) { - ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", res > 0 ? strerror(res) : "Bad ao2obj data"); - ast_mutex_unlock(&p->lock); - return -1; - } - usleep(1); - ast_channel_lock(ast); - } + ast_channel_unlock(ast); + ast_channel_lock(p->chan); res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; ast_channel_unlock(p->chan); - } else + ast_mutex_unlock(&p->lock); + ast_channel_lock(ast); + } else { + ast_mutex_unlock(&p->lock); res = 0; - ast_mutex_unlock(&p->lock); + } return res; } @@ -895,7 +904,6 @@ agent_start_monitoring(ast, 0); p->acknowledged = 1; } - res = 0; } CLEANUP(ast, p); ast_mutex_unlock(&p->lock); @@ -907,7 +915,7 @@ /*! \brief return the channel or base channel if one exists. This function assumes the channel it is called on is already locked */ struct ast_channel* agent_get_base_channel(struct ast_channel *chan) { - struct agent_pvt *p = NULL; + struct agent_pvt *p; struct ast_channel *base = chan; /* chan is locked by the calling function */ @@ -968,10 +976,7 @@ */ ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); - if (p->start && (ast->_state != AST_STATE_UP)) { - p->start = 0; - } else - p->start = 0; + p->start = 0; if (p->chan) { p->chan->_bridge = NULL; /* If they're dead, go ahead and hang up on the agent now */ @@ -992,9 +997,7 @@ } /* Only register a device state change if the agent is still logged in */ - if (!p->loginstart) { - p->logincallerid[0] = '\0'; - } else { + if (p->loginstart) { ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); } @@ -1003,10 +1006,7 @@ kill it later */ p->abouttograb = 0; } else if (p->dead) { - ast_mutex_destroy(&p->lock); - ast_cond_destroy(&p->app_complete_cond); - ast_cond_destroy(&p->login_wait_cond); - ast_free(p); + agent_pvt_destroy(p); } else { if (p->chan) { /* Not dead -- check availability now */ @@ -1019,42 +1019,38 @@ return 0; } -static int agent_cont_sleep( void *data ) +static int agent_cont_sleep(void *data) { struct agent_pvt *p; int res; - p = (struct agent_pvt *)data; + p = (struct agent_pvt *) data; ast_mutex_lock(&p->lock); res = p->app_sleep_cond; - if (p->lastdisc.tv_sec) { - if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) - res = 1; + if (res && p->lastdisc.tv_sec) { + if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { + res = 0; + } } ast_mutex_unlock(&p->lock); - if (!res) - ast_debug(5, "agent_cont_sleep() returning %d\n", res ); + if (!res) { + ast_debug(5, "agent_cont_sleep() returning %d\n", res); + } return res; } -static int agent_ack_sleep(void *data) +static int agent_ack_sleep(struct agent_pvt *p) { - struct agent_pvt *p; - int res=0; + int digit; int to = 1000; struct ast_frame *f; struct timeval start = ast_tvnow(); int ms; /* Wait a second and look for something */ - - p = (struct agent_pvt *) data; - if (!p->chan) - return -1; - while ((ms = ast_remaining_ms(start, to))) { ms = ast_waitfor(p->chan, ms); if (ms < 0) { @@ -1064,23 +1060,31 @@ return 0; } f = ast_read(p->chan); - if (!f) + if (!f) { return -1; - if (f->frametype == AST_FRAME_DTMF) - res = f->subclass.integer; - else - res = 0; + } + if (f->frametype == AST_FRAME_DTMF) { + digit = f->subclass.integer; + } else { + digit = 0; + } ast_frfree(f); ast_mutex_lock(&p->lock); if (!p->app_sleep_cond) { ast_mutex_unlock(&p->lock); return 0; - } else if (res == p->acceptdtmf) { + } + if (digit == p->acceptdtmf) { ast_mutex_unlock(&p->lock); return 1; } + if (p->lastdisc.tv_sec) { + if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { + ast_mutex_unlock(&p->lock); + return 0; + } + } ast_mutex_unlock(&p->lock); - res = 0; } return 0; } @@ -1295,10 +1299,7 @@ /* Destroy if appropriate */ if (!p->owner) { if (!p->chan) { - ast_mutex_destroy(&p->lock); - ast_cond_destroy(&p->app_complete_cond); - ast_cond_destroy(&p->login_wait_cond); - ast_free(p); + agent_pvt_destroy(p); } else { /* Cause them to hang up */ ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); @@ -1437,8 +1438,9 @@ 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) + if (p->chan) { hasagent++; + } now = ast_tvnow(); if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { p->lastdisc = ast_tv(0, 0); @@ -1455,30 +1457,6 @@ } 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) { - hasagent++; - } - now = ast_tvnow(); - if (!p->lastdisc.tv_sec || (now.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, requestor ? requestor->linkedid : NULL); - } - 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. @@ -1486,10 +1464,14 @@ if (hasagent) { ast_debug(1, "Creating place holder for '%s'\n", s); p = add_agent(data, 1); - p->group = groupmatch; - chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); - if (!chan) - ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); + if (p) { + p->group = groupmatch; + chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); + if (!chan) { + AST_LIST_REMOVE(&agents, p, list); + agent_pvt_destroy(p); + } + } } else { ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); } @@ -1939,7 +1921,6 @@ int tries = 0; int max_login_tries = maxlogintries; struct agent_pvt *p; - struct ast_module_user *u; char user[AST_MAX_AGENT] = ""; char pass[AST_MAX_AGENT]; char agent[AST_MAX_AGENT] = ""; @@ -1957,8 +1938,6 @@ int update_cdr = updatecdr; char *filename = "agent-loginok"; - u = ast_module_user_add(chan); - parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); @@ -2090,7 +2069,6 @@ long logintime; snprintf(agent, sizeof(agent), "Agent/%s", p->agent); - p->logincallerid[0] = '\0'; p->acknowledged = 0; ast_mutex_unlock(&p->lock); @@ -2226,10 +2204,7 @@ /* If there is no owner, go ahead and kill it now */ ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent); if (p->dead && !p->owner) { - ast_mutex_destroy(&p->lock); - ast_cond_destroy(&p->app_complete_cond); - ast_cond_destroy(&p->login_wait_cond); - ast_free(p); + agent_pvt_destroy(p); } } else { @@ -2259,8 +2234,6 @@ if (!res) res = ast_safe_sleep(chan, 500); - ast_module_user_remove(u); - return -1; }