Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
Data Structures | Macros | Enumerations | Functions | Variables
app_agent_pool.c File Reference

Call center agent pool. More...

#include "asterisk.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_internal.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_after.h"
#include "asterisk/config_options.h"
#include "asterisk/features_config.h"
#include "asterisk/astobj2.h"
#include "asterisk/stringfields.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/causes.h"
Include dependency graph for app_agent_pool.c:

Go to the source code of this file.

Data Structures

struct  agent_cfg
 
struct  agent_complete
 
struct  agent_pvt
 Structure representing an agent. More...
 
struct  agents_cfg
 

Macros

#define agent_lock(agent)   _agent_lock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
 Lock the agent. More...
 
#define agent_unlock(agent)   _agent_unlock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
 Unlock the agent. More...
 
#define AST_MAX_BUF   256
 
#define CALLER_SAFETY_TIMEOUT_TIME   (2 * 60 * 1000)
 
#define FORMAT_HDR   "%-8s %-20s %-11s %-30s %s\n"
 
#define FORMAT_ROW   "%-8s %-20s %-11s %-30s %s\n"
 
#define LOGIN_WAIT_TIMEOUT_TIME   5
 

Enumerations

enum  AGENT_LOGIN_OPT_FLAGS { OPT_SILENT = (1 << 0) }
 
enum  agent_override_flags { AGENT_FLAG_ACK_CALL = (1 << 0) , AGENT_FLAG_DTMF_ACCEPT = (1 << 1) , AGENT_FLAG_AUTO_LOGOFF = (1 << 2) , AGENT_FLAG_WRAPUP_TIME = (1 << 3) }
 
enum  agent_state {
  AGENT_STATE_LOGGED_OUT , AGENT_STATE_PROBATION_WAIT , AGENT_STATE_READY_FOR_CALL , AGENT_STATE_CALL_PRESENT ,
  AGENT_STATE_CALL_WAIT_ACK , AGENT_STATE_ON_CALL , AGENT_STATE_CALL_WRAPUP , AGENT_STATE_LOGGING_OUT
}
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static void _agent_lock (struct agent_pvt *agent, const char *file, const char *function, int line, const char *var)
 
static void _agent_unlock (struct agent_pvt *agent, const char *file, const char *function, int line, const char *var)
 
static int action_agent_logoff (struct mansession *s, const struct message *m)
 
static int action_agents (struct mansession *s, const struct message *m)
 
static void agent_after_bridge_cb (struct ast_channel *chan, void *data)
 
static void agent_after_bridge_cb_failed (enum ast_bridge_after_cb_reason reason, void *data)
 
static void agent_alert (struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
 
static struct ast_bridge_channelagent_bridge_channel_get_lock (struct agent_pvt *agent)
 
static void * agent_cfg_alloc (const char *name)
 
static void agent_cfg_destructor (void *vdoomed)
 
static void * agent_cfg_find (struct ao2_container *agents, const char *username)
 
static int agent_cfg_sort_cmp (const void *obj_left, const void *obj_right, int flags)
 
static void agent_connect_caller (struct ast_bridge_channel *bridge_channel, struct agent_pvt *agent)
 
static void agent_devstate_changed (const char *agent_id)
 
static int agent_function_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static char * agent_handle_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * agent_handle_show_all (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * agent_handle_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static char * agent_handle_show_specific (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 
static struct ast_channelagent_lock_logged (struct agent_pvt *agent)
 
static void agent_login_channel_config (struct agent_pvt *agent, struct ast_channel *chan)
 
static int agent_login_exec (struct ast_channel *chan, const char *data)
 Dialplan AgentLogin application to log in an agent. More...
 
static int agent_logoff_request (const char *agent_id, int soft)
 
static void agent_logout (struct agent_pvt *agent)
 
static int agent_mark (void *obj, void *arg, int flags)
 
static int agent_pvt_cmp (void *obj, void *arg, int flags)
 
static void agent_pvt_destructor (void *vdoomed)
 
static enum ast_device_state agent_pvt_devstate_get (const char *agent_id)
 
static struct agent_pvtagent_pvt_new (struct agent_cfg *cfg)
 
static int agent_pvt_sort_cmp (const void *obj_left, const void *obj_right, int flags)
 
static int agent_request_exec (struct ast_channel *chan, const char *data)
 Dialplan AgentRequest application to locate an agent to talk with. More...
 
static void agent_run (struct agent_pvt *agent, struct ast_channel *logged)
 
static void agent_show_requested (struct ast_cli_args *a, int online_only)
 
static int agent_sweep (void *obj, void *arg, int flags)
 
static void * agents_cfg_alloc (void)
 
static void agents_cfg_destructor (void *vdoomed)
 
static void agents_mark (void)
 
static void agents_post_apply_config (void)
 
static void agents_sweep (void)
 
static AO2_GLOBAL_OBJ_STATIC (agent_holding)
 
static AO2_GLOBAL_OBJ_STATIC (cfg_handle)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int bridge_agent_hold_ack (struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 
static int bridge_agent_hold_deferred_create (void)
 
static void bridge_agent_hold_dissolving (struct ast_bridge *self)
 The bridge is being dissolved. More...
 
static int bridge_agent_hold_heartbeat (struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 
static struct ast_bridgebridge_agent_hold_new (void)
 
static void bridge_agent_hold_pull (struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
 
static int bridge_agent_hold_push (struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
 
static void bridge_init_agent_hold (void)
 
static void caller_abort_agent (struct agent_pvt *agent)
 
static int caller_joined_bridge (struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 
static int caller_safety_timeout (struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 
static void clear_agent_status (struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
 
static char * complete_agent (const char *word, int state)
 
static char * complete_agent_logoff (const char *word, int state)
 
static int complete_agent_logoff_search (void *obj, void *arg, void *data, int flags)
 
static int complete_agent_search (void *obj, void *arg, void *data, int flags)
 
 CONFIG_INFO_STANDARD (cfg_info, cfg_handle, agents_cfg_alloc,.files=ACO_FILES(&agents_conf),.post_apply_config=agents_post_apply_config,)
 
static void destroy_config (void)
 
static int load_config (void)
 
static int load_module (void)
 
static int reload (void)
 
static void send_agent_login (struct ast_channel *chan, const char *agent)
 
static void send_agent_logoff (struct ast_channel *chan, const char *agent, long logintime)
 
static int send_alert_to_agent (struct ast_bridge_channel *bridge_channel, const char *agent_id)
 
static int send_colp_to_agent (struct ast_bridge_channel *bridge_channel, struct ast_party_connected_line *connected)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Call center agent pool applications" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
 
static struct ast_custom_function agent_function
 
static ast_mutex_t agent_holding_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
 
static const struct ast_app_option agent_login_opts [128] = { [ 's' ] = { .flag = OPT_SILENT }, }
 
static struct aco_type agent_type
 
static struct aco_typeagent_types [] = ACO_TYPES(&agent_type)
 
static struct ao2_containeragents
 
static struct aco_file agents_conf
 
static const char app_agent_login [] = "AgentLogin"
 
static const char app_agent_request [] = "AgentRequest"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_bridge_methods bridge_agent_hold_v_table
 
static struct ast_cli_entry cli_agents []
 
static struct aco_type general_type
 

Detailed Description

Call center agent pool.

Author
Richard Mudgett rmudg.nosp@m.ett@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

See Also:

Definition in file app_agent_pool.c.

Macro Definition Documentation

◆ agent_lock

#define agent_lock (   agent)    _agent_lock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)

Lock the agent.

Parameters
agentAgent to lock

Definition at line 656 of file app_agent_pool.c.

◆ agent_unlock

#define agent_unlock (   agent)    _agent_unlock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)

Unlock the agent.

Parameters
agentAgent to unlock

Definition at line 667 of file app_agent_pool.c.

◆ AST_MAX_BUF

#define AST_MAX_BUF   256

Definition at line 342 of file app_agent_pool.c.

◆ CALLER_SAFETY_TIMEOUT_TIME

#define CALLER_SAFETY_TIMEOUT_TIME   (2 * 60 * 1000)

Maximum wait time (in ms) for the custom_beep file to play announcing the caller.

Definition at line 345 of file app_agent_pool.c.

◆ FORMAT_HDR

#define FORMAT_HDR   "%-8s %-20s %-11s %-30s %s\n"

◆ FORMAT_ROW

#define FORMAT_ROW   "%-8s %-20s %-11s %-30s %s\n"

◆ LOGIN_WAIT_TIMEOUT_TIME

#define LOGIN_WAIT_TIMEOUT_TIME   5

Number of seconds to wait for local channel optimizations to complete.

Definition at line 348 of file app_agent_pool.c.

Enumeration Type Documentation

◆ AGENT_LOGIN_OPT_FLAGS

Enumerator
OPT_SILENT 

Definition at line 2074 of file app_agent_pool.c.

2074 {
2075 OPT_SILENT = (1 << 0),
2076};
@ OPT_SILENT

◆ agent_override_flags

Agent config option override flags.

Enumerator
AGENT_FLAG_ACK_CALL 
AGENT_FLAG_DTMF_ACCEPT 
AGENT_FLAG_AUTO_LOGOFF 
AGENT_FLAG_WRAPUP_TIME 

Definition at line 586 of file app_agent_pool.c.

586 {
587 AGENT_FLAG_ACK_CALL = (1 << 0),
588 AGENT_FLAG_DTMF_ACCEPT = (1 << 1),
589 AGENT_FLAG_AUTO_LOGOFF = (1 << 2),
590 AGENT_FLAG_WRAPUP_TIME = (1 << 3),
591};
@ AGENT_FLAG_ACK_CALL
@ AGENT_FLAG_AUTO_LOGOFF
@ AGENT_FLAG_WRAPUP_TIME
@ AGENT_FLAG_DTMF_ACCEPT

◆ agent_state

Enumerator
AGENT_STATE_LOGGED_OUT 

The agent is defined but an agent is not present.

AGENT_STATE_PROBATION_WAIT 

Forced initial login wait to allow any local channel optimizations to happen.

AGENT_STATE_READY_FOR_CALL 

The agent is ready for a call.

AGENT_STATE_CALL_PRESENT 

The agent has a call waiting to connect.

AGENT_STATE_CALL_WAIT_ACK 

The agent needs to ack the call.

AGENT_STATE_ON_CALL 

The agent is connected with a call.

AGENT_STATE_CALL_WRAPUP 

The agent is resting between calls.

AGENT_STATE_LOGGING_OUT 

The agent is being kicked out.

Definition at line 566 of file app_agent_pool.c.

566 {
567 /*! The agent is defined but an agent is not present. */
569 /*! Forced initial login wait to allow any local channel optimizations to happen. */
571 /*! The agent is ready for a call. */
573 /*! The agent has a call waiting to connect. */
575 /*! The agent needs to ack the call. */
577 /*! The agent is connected with a call. */
579 /*! The agent is resting between calls. */
581 /*! The agent is being kicked out. */
583};
@ AGENT_STATE_LOGGED_OUT
@ AGENT_STATE_CALL_PRESENT
@ AGENT_STATE_PROBATION_WAIT
@ AGENT_STATE_CALL_WAIT_ACK
@ AGENT_STATE_READY_FOR_CALL
@ AGENT_STATE_ON_CALL
@ AGENT_STATE_LOGGING_OUT
@ AGENT_STATE_CALL_WRAPUP

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2694 of file app_agent_pool.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2694 of file app_agent_pool.c.

◆ _agent_lock()

static void _agent_lock ( struct agent_pvt agent,
const char *  file,
const char *  function,
int  line,
const char *  var 
)
inlinestatic

Definition at line 657 of file app_agent_pool.c.

658{
659 __ao2_lock(agent, AO2_LOCK_REQ_MUTEX, file, function, line, var);
660}
#define var
Definition: ast_expr2f.c:605
@ AO2_LOCK_REQ_MUTEX
Definition: astobj2.h:702
int __ao2_lock(void *a, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
Lock an object.
Definition: astobj2.c:222

References __ao2_lock(), AO2_LOCK_REQ_MUTEX, make_ari_stubs::file, and var.

◆ _agent_unlock()

static void _agent_unlock ( struct agent_pvt agent,
const char *  file,
const char *  function,
int  line,
const char *  var 
)
inlinestatic

Definition at line 668 of file app_agent_pool.c.

669{
670 __ao2_unlock(agent, file, function, line, var);
671}
int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var)
Unlock an object.
Definition: astobj2.c:288

References __ao2_unlock(), make_ari_stubs::file, and var.

◆ action_agent_logoff()

static int action_agent_logoff ( struct mansession s,
const struct message m 
)
static

Definition at line 2583 of file app_agent_pool.c.

2584{
2585 const char *agent = astman_get_header(m, "Agent");
2586 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
2587
2588 if (ast_strlen_zero(agent)) {
2589 astman_send_error(s, m, "No agent specified");
2590 return 0;
2591 }
2592
2593 if (!agent_logoff_request(agent, ast_true(soft_s))) {
2594 astman_send_ack(s, m, "Agent logged out");
2595 } else {
2596 astman_send_error(s, m, "No such agent");
2597 }
2598
2599 return 0;
2600}
static int agent_logoff_request(const char *agent_id, int soft)
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2001
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65

References agent_logoff_request(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().

Referenced by load_module().

◆ action_agents()

static int action_agents ( struct mansession s,
const struct message m 
)
static

Definition at line 2505 of file app_agent_pool.c.

2506{
2507 const char *id = astman_get_header(m, "ActionID");
2508 char id_text[AST_MAX_BUF];
2509 struct ao2_iterator iter;
2510 struct agent_pvt *agent;
2511 struct ast_str *out = ast_str_alloca(4096);
2512 int num_agents = 0;
2513
2514 if (!ast_strlen_zero(id)) {
2515 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
2516 } else {
2517 id_text[0] = '\0';
2518 }
2519 astman_send_listack(s, m, "Agents will follow", "start");
2520
2521 iter = ao2_iterator_init(agents, 0);
2522 for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2523 struct ast_channel *logged;
2524
2525 agent_lock(agent);
2526 logged = agent_lock_logged(agent);
2527
2528 /*
2529 * Status Values:
2530 * AGENT_LOGGEDOFF - Agent isn't logged in
2531 * AGENT_IDLE - Agent is logged in, and waiting for call
2532 * AGENT_ONCALL - Agent is logged in, and on a call
2533 * AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this.
2534 */
2535 ast_str_set(&out, 0, "Agent: %s\r\n", agent->username);
2536 ast_str_append(&out, 0, "Name: %s\r\n", agent->cfg->full_name);
2537
2538 if (logged) {
2539 const char *talking_to_chan;
2540 struct ast_str *logged_headers;
2541 RAII_VAR(struct ast_channel_snapshot *, logged_snapshot, ast_channel_snapshot_create(logged), ao2_cleanup);
2542
2543 if (!logged_snapshot
2544 || !(logged_headers =
2545 ast_manager_build_channel_state_string(logged_snapshot))) {
2546 ast_channel_unlock(logged);
2547 ast_channel_unref(logged);
2548 agent_unlock(agent);
2549 continue;
2550 }
2551
2552 talking_to_chan = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2553 if (!ast_strlen_zero(talking_to_chan)) {
2554 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_ONCALL");
2555 ast_str_append(&out, 0, "TalkingToChan: %s\r\n", talking_to_chan);
2556 ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2557 } else {
2558 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_IDLE");
2559 }
2560 ast_str_append(&out, 0, "LoggedInTime: %ld\r\n", (long) agent->login_start);
2561 ast_str_append(&out, 0, "%s", ast_str_buffer(logged_headers));
2562 ast_channel_unlock(logged);
2563 ast_channel_unref(logged);
2564 ast_free(logged_headers);
2565 } else {
2566 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_LOGGEDOFF");
2567 }
2568
2569 agent_unlock(agent);
2570
2571 astman_append(s, "Event: Agents\r\n"
2572 "%s%s\r\n",
2573 ast_str_buffer(out), id_text);
2574 ++num_agents;
2575 }
2576 ao2_iterator_destroy(&iter);
2577
2578 astman_send_list_complete_start(s, m, "AgentsComplete", num_agents);
2580 return 0;
2581}
static struct ao2_container * agents
#define AST_MAX_BUF
#define agent_lock(agent)
Lock the agent.
static struct ast_channel * agent_lock_logged(struct agent_pvt *agent)
#define agent_unlock(agent)
Unlock the agent.
#define ast_free(a)
Definition: astmm.h:180
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_channel_unref(c)
Decrease channel reference count.
Definition: channel.h:3004
#define ast_channel_unlock(chan)
Definition: channel.h:2969
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2011
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2047
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_alloca(init_len)
Definition: strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
const ast_string_field full_name
Structure representing an agent.
const ast_string_field username
time_t call_start
time_t login_start
struct agent_cfg * cfg
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Structure representing a snapshot of channel state.
Main Channel structure associated with a channel.
Support for dynamic strings.
Definition: strings.h:623
FILE * out
Definition: utils/frame.c:33
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

References agent_lock, agent_lock_logged(), agent_unlock, agents, ao2_cleanup, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_snapshot_create(), ast_channel_unlock, ast_channel_unref, ast_free, ast_manager_build_channel_state_string(), AST_MAX_BUF, ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), agent_pvt::call_start, agent_pvt::cfg, agent_cfg::full_name, agent_pvt::login_start, out, pbx_builtin_getvar_helper(), RAII_VAR, and agent_pvt::username.

Referenced by load_module().

◆ agent_after_bridge_cb()

static void agent_after_bridge_cb ( struct ast_channel chan,
void *  data 
)
static

Definition at line 1598 of file app_agent_pool.c.

1599{
1600 struct agent_pvt *agent;
1601
1602 agent = ao2_find(agents, chan, 0);
1603 if (!agent) {
1604 return;
1605 }
1606
1607 ast_debug(1, "Agent %s: New agent channel %s.\n",
1608 agent->username, ast_channel_name(chan));
1609 agent_run(agent, chan);
1610 ao2_ref(agent, -1);
1611}
static void agent_run(struct agent_pvt *agent, struct ast_channel *logged)
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_debug(level,...)
Log a DEBUG message.

References agent_run(), agents, ao2_find, ao2_ref, ast_channel_name(), ast_debug, and agent_pvt::username.

Referenced by bridge_agent_hold_push().

◆ agent_after_bridge_cb_failed()

static void agent_after_bridge_cb_failed ( enum ast_bridge_after_cb_reason  reason,
void *  data 
)
static

Definition at line 1613 of file app_agent_pool.c.

1614{
1615 struct ast_channel *chan = data;
1616 struct agent_pvt *agent;
1617
1618 agent = ao2_find(agents, chan, 0);
1619 if (!agent) {
1620 return;
1621 }
1622 ast_log(LOG_WARNING, "Agent %s: Forced logout. Lost control of %s because: %s\n",
1623 agent->username, ast_channel_name(chan),
1625 agent_lock(agent);
1626 agent_logout(agent);
1627 ao2_ref(agent, -1);
1628}
static void agent_logout(struct agent_pvt *agent)
#define ast_log
Definition: astobj2.c:42
const char * ast_bridge_after_cb_reason_string(enum ast_bridge_after_cb_reason reason)
Get a string representation of an after bridge callback reason.
Definition: bridge_after.c:288
#define LOG_WARNING
const char * data

References agent_lock, agent_logout(), agents, ao2_find, ao2_ref, ast_bridge_after_cb_reason_string(), ast_channel_name(), ast_log, ast_channel::data, LOG_WARNING, and agent_pvt::username.

Referenced by bridge_agent_hold_push().

◆ agent_alert()

static void agent_alert ( struct ast_bridge_channel bridge_channel,
const void *  payload,
size_t  payload_size 
)
static

Definition at line 1718 of file app_agent_pool.c.

1719{
1720 const char *agent_id = payload;
1721 const char *playfile;
1722 const char *dtmf_accept;
1723 struct agent_pvt *agent;
1724 int digit;
1725 char dtmf[2];
1726
1727 agent = ao2_find(agents, agent_id, OBJ_KEY);
1728 if (!agent) {
1729 ast_debug(1, "Agent '%s' does not exist. Where did it go?\n", agent_id);
1730 return;
1731 }
1732
1733 /* Change holding bridge participant role's idle mode to silence */
1734 ast_bridge_channel_lock_bridge(bridge_channel);
1735 ast_bridge_channel_clear_roles(bridge_channel);
1736 ast_channel_set_bridge_role_option(bridge_channel->chan, "holding_participant", "idle_mode", "silence");
1737 ast_bridge_channel_establish_roles(bridge_channel);
1738 ast_bridge_unlock(bridge_channel->bridge);
1739
1740 agent_lock(agent);
1741 playfile = ast_strdupa(agent->cfg->beep_sound);
1742
1743 /* Determine which DTMF digits interrupt the alerting signal. */
1745 ? agent->override_ack_call : agent->cfg->ack_call) {
1746 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1747 ? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
1748
1749 /* Only the first digit of the ack will stop playback. */
1750 dtmf[0] = *dtmf_accept;
1751 dtmf[1] = '\0';
1752 dtmf_accept = dtmf;
1753 } else {
1754 dtmf_accept = NULL;
1755 }
1756 agent_unlock(agent);
1757
1758 /* Alert the agent. */
1759 digit = ast_stream_and_wait(bridge_channel->chan, playfile,
1760 ast_strlen_zero(dtmf_accept) ? AST_DIGIT_ANY : dtmf_accept);
1761 ast_stopstream(bridge_channel->chan);
1762
1763 agent_lock(agent);
1764 switch (agent->state) {
1766 if (!ast_strlen_zero(dtmf_accept)) {
1768 agent->ack_time = ast_tvnow();
1769
1770 if (0 < digit) {
1771 /* Playback was interrupted by a digit. */
1772 agent_unlock(agent);
1773 ao2_ref(agent, -1);
1774 ast_bridge_channel_feature_digit(bridge_channel, digit);
1775 return;
1776 }
1777 break;
1778 }
1779
1780 /* Connect to caller now. */
1781 ast_debug(1, "Agent %s: Immediately connecting to call.\n", agent->username);
1782 agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
1783 ao2_ref(agent, -1);
1784 return;
1785 default:
1786 break;
1787 }
1788 agent_unlock(agent);
1789 ao2_ref(agent, -1);
1790}
static void agent_connect_caller(struct ast_bridge_channel *bridge_channel, struct agent_pvt *agent)
char digit
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define OBJ_KEY
Definition: astobj2.h:1151
#define ast_bridge_unlock(bridge)
Unlock the bridge.
Definition: bridge.h:481
void ast_bridge_channel_feature_digit(struct ast_bridge_channel *bridge_channel, int digit)
Add a DTMF digit to the collected digits to match against DTMF features.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
Set a role option on a channel.
Definition: bridge_roles.c:375
int ast_bridge_channel_establish_roles(struct ast_bridge_channel *bridge_channel)
Clone the roles from a bridge_channel's attached ast_channel onto the bridge_channel's role list.
Definition: bridge_roles.c:443
void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
Clear all roles from a bridge_channel's role list.
Definition: bridge_roles.c:491
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:222
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
Definition: file.c:1878
#define AST_DIGIT_ANY
Definition: file.h:48
#define NULL
Definition: resample.c:96
const ast_string_field dtmf_accept
int ack_call
TRUE if agent needs to ack a call to accept it.
const ast_string_field beep_sound
const ast_string_field override_dtmf_accept
enum agent_state state
struct timeval ack_time
unsigned int override_ack_call
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_channel * chan
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#define ast_test_flag(p, flag)
Definition: utils.h:63

References agent_cfg::ack_call, agent_pvt::ack_time, agent_connect_caller(), AGENT_FLAG_ACK_CALL, AGENT_FLAG_DTMF_ACCEPT, agent_lock, AGENT_STATE_CALL_PRESENT, AGENT_STATE_CALL_WAIT_ACK, agent_unlock, agents, ao2_find, ao2_ref, ast_bridge_channel_clear_roles(), ast_bridge_channel_establish_roles(), ast_bridge_channel_feature_digit(), ast_bridge_channel_lock_bridge(), ast_bridge_unlock, ast_channel_set_bridge_role_option(), ast_debug, AST_DIGIT_ANY, ast_stopstream(), ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_tvnow(), agent_cfg::beep_sound, ast_bridge_channel::bridge, agent_pvt::cfg, ast_bridge_channel::chan, digit, agent_cfg::dtmf_accept, NULL, OBJ_KEY, agent_pvt::override_ack_call, agent_pvt::override_dtmf_accept, agent_pvt::state, and agent_pvt::username.

Referenced by send_alert_to_agent().

◆ agent_bridge_channel_get_lock()

static struct ast_bridge_channel * agent_bridge_channel_get_lock ( struct agent_pvt agent)
static

Definition at line 1640 of file app_agent_pool.c.

1641{
1642 struct ast_channel *logged;
1643 struct ast_bridge_channel *bc;
1644
1645 for (;;) {
1646 agent_lock(agent);
1647 logged = agent->logged;
1648 if (!logged) {
1649 agent_unlock(agent);
1650 return NULL;
1651 }
1652 ast_channel_ref(logged);
1653 agent_unlock(agent);
1654
1655 ast_channel_lock(logged);
1657 ast_channel_unlock(logged);
1658 ast_channel_unref(logged);
1659 if (!bc) {
1660 if (agent->logged != logged) {
1661 continue;
1662 }
1663 return NULL;
1664 }
1665
1667 if (bc->chan != logged || agent->logged != logged) {
1669 ao2_ref(bc, -1);
1670 continue;
1671 }
1672 return bc;
1673 }
1674}
#define ast_bridge_channel_unlock(bridge_channel)
Unlock the bridge_channel.
#define ast_bridge_channel_lock(bridge_channel)
Lock the bridge_channel.
#define ast_channel_lock(chan)
Definition: channel.h:2968
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2993
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel's bridge pointer.
Definition: channel.c:10604
#define bc
struct ast_channel * logged
Structure that contains information regarding a channel in a bridge.

References agent_lock, agent_unlock, ao2_ref, ast_bridge_channel_lock, ast_bridge_channel_unlock, ast_channel_get_bridge_channel(), ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, bc, agent_pvt::logged, and NULL.

Referenced by agent_request_exec(), caller_abort_agent(), and caller_joined_bridge().

◆ agent_cfg_alloc()

static void * agent_cfg_alloc ( const char *  name)
static

Definition at line 440 of file app_agent_pool.c.

441{
442 struct agent_cfg *cfg;
443
444 cfg = ao2_alloc_options(sizeof(*cfg), agent_cfg_destructor,
446 if (!cfg || ast_string_field_init(cfg, 64)) {
447 ao2_cleanup(cfg);
448 return NULL;
449 }
451 return cfg;
452}
static void agent_cfg_destructor(void *vdoomed)
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
static const char name[]
Definition: format_mp3.c:68
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
const ast_string_field username

References agent_cfg_destructor(), AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_cleanup, ast_string_field_init, ast_string_field_set, name, NULL, and agent_cfg::username.

◆ agent_cfg_destructor()

static void agent_cfg_destructor ( void *  vdoomed)
static

Definition at line 433 of file app_agent_pool.c.

434{
435 struct agent_cfg *doomed = vdoomed;
436
438}
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374

References ast_string_field_free_memory.

Referenced by agent_cfg_alloc().

◆ agent_cfg_find()

static void * agent_cfg_find ( struct ao2_container agents,
const char *  username 
)
static

Definition at line 454 of file app_agent_pool.c.

455{
456 return ao2_find(agents, username, OBJ_KEY);
457}

References agents, ao2_find, OBJ_KEY, and agent_cfg::username.

◆ agent_cfg_sort_cmp()

static int agent_cfg_sort_cmp ( const void *  obj_left,
const void *  obj_right,
int  flags 
)
static

Definition at line 411 of file app_agent_pool.c.

412{
413 const struct agent_cfg *cfg_left = obj_left;
414 const struct agent_cfg *cfg_right = obj_right;
415 const char *right_key = obj_right;
416 int cmp;
417
418 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
419 default:
420 case OBJ_POINTER:
421 right_key = cfg_right->username;
422 /* Fall through */
423 case OBJ_KEY:
424 cmp = strcmp(cfg_left->username, right_key);
425 break;
426 case OBJ_PARTIAL_KEY:
427 cmp = strncmp(cfg_left->username, right_key, strlen(right_key));
428 break;
429 }
430 return cmp;
431}
#define OBJ_POINTER
Definition: astobj2.h:1150
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1152

References OBJ_KEY, OBJ_PARTIAL_KEY, OBJ_POINTER, and agent_cfg::username.

Referenced by agents_cfg_alloc().

◆ agent_connect_caller()

static void agent_connect_caller ( struct ast_bridge_channel bridge_channel,
struct agent_pvt agent 
)
static

Definition at line 1022 of file app_agent_pool.c.

1023{
1024 struct ast_bridge *caller_bridge;
1025 int record_agent_calls;
1026 int res;
1027
1028 record_agent_calls = agent->cfg->record_agent_calls;
1029 caller_bridge = agent->caller_bridge;
1030 agent->caller_bridge = NULL;
1031 agent->state = AGENT_STATE_ON_CALL;
1032 time(&agent->call_start);
1033 agent_unlock(agent);
1034
1035 if (!caller_bridge) {
1036 /* Reset agent. */
1039 return;
1040 }
1041 res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan,
1042 NULL, 0);
1043 if (res) {
1044 /* Reset agent. */
1045 ast_bridge_destroy(caller_bridge, 0);
1048 return;
1049 }
1052 if (res) {
1053 /* Reset agent. */
1054 ast_bridge_destroy(caller_bridge, 0);
1055 return;
1056 }
1057
1058 if (record_agent_calls) {
1060 .start_stop = AUTO_MONITOR_START,
1061 };
1062
1063 /*
1064 * The agent is in the new bridge so we can invoke the
1065 * mixmonitor hook to only start recording.
1066 */
1068 }
1069
1070 ao2_t_ref(caller_bridge, -1, "Agent successfully in caller_bridge");
1071}
static void clear_agent_status(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
Definition: bridge.c:944
int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
Move a channel from one bridge to another.
Definition: bridge.c:2460
int ast_bridge_channel_write_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
Write a control frame into the bridge with data.
@ BRIDGE_CHANNEL_STATE_END
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
int ast_bridge_channel_write_callback(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_custom_callback_option flags, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
Write a bridge action custom callback frame into the bridge.
@ AST_BRIDGE_BUILTIN_AUTOMIXMON
int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
Invoke a built in feature hook now.
Definition: bridge.c:3090
@ AUTO_MONITOR_START
#define AST_CAUSE_NORMAL_CLEARING
Definition: causes.h:106
@ AST_CONTROL_ANSWER
int record_agent_calls
struct ast_bridge * caller_bridge
Structure that contains information about a bridge.
Definition: bridge.h:349
static struct test_options options

References AGENT_STATE_ON_CALL, agent_unlock, ao2_t_ref, AST_BRIDGE_BUILTIN_AUTOMIXMON, ast_bridge_channel_leave_bridge(), ast_bridge_channel_write_callback(), ast_bridge_channel_write_control_data(), ast_bridge_destroy(), ast_bridge_features_do(), ast_bridge_move(), AST_CAUSE_NORMAL_CLEARING, AST_CONTROL_ANSWER, AUTO_MONITOR_START, ast_bridge_channel::bridge, BRIDGE_CHANNEL_STATE_END, agent_pvt::call_start, agent_pvt::caller_bridge, agent_pvt::cfg, ast_bridge_channel::chan, clear_agent_status(), NULL, options, agent_cfg::record_agent_calls, and agent_pvt::state.

Referenced by agent_alert(), and bridge_agent_hold_ack().

◆ agent_devstate_changed()

static void agent_devstate_changed ( const char *  agent_id)
static

Definition at line 748 of file app_agent_pool.c.

749{
751}
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53

References AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, and ast_devstate_changed().

Referenced by agent_logout(), agent_pvt_destructor(), agent_request_exec(), agents_post_apply_config(), bridge_agent_hold_heartbeat(), and bridge_agent_hold_push().

◆ agent_function_read()

static int agent_function_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 2162 of file app_agent_pool.c.

2163{
2164 char *parse;
2165 struct agent_pvt *agent;
2166 struct ast_channel *logged;
2168 AST_APP_ARG(agentid);
2170 );
2171
2172 buf[0] = '\0';
2173
2174 parse = ast_strdupa(data ?: "");
2175 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2176
2177 if (ast_strlen_zero(args.agentid)) {
2178 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2179 return -1;
2180 }
2181 if (!args.item) {
2182 args.item = "status";
2183 }
2184
2185 agent = ao2_find(agents, args.agentid, OBJ_KEY);
2186 if (!agent) {
2187 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2188 return -1;
2189 }
2190
2191 agent_lock(agent);
2192 if (!strcasecmp(args.item, "status")) {
2193 const char *status;
2194
2195 if (agent->logged) {
2196 status = "LOGGEDIN";
2197 } else {
2198 status = "LOGGEDOUT";
2199 }
2201 } else if (!strcasecmp(args.item, "name")) {
2202 ast_copy_string(buf, agent->cfg->full_name, len);
2203 } else if (!strcasecmp(args.item, "mohclass")) {
2204 ast_copy_string(buf, agent->cfg->moh, len);
2205 } else if (!strcasecmp(args.item, "channel")) {
2206 logged = agent_lock_logged(agent);
2207 if (logged) {
2208 char *pos;
2209
2211 ast_channel_unlock(logged);
2212 ast_channel_unref(logged);
2213
2214 pos = strrchr(buf, '-');
2215 if (pos) {
2216 *pos = '\0';
2217 }
2218 }
2219 } else if (!strcasecmp(args.item, "fullchannel")) {
2220 logged = agent_lock_logged(agent);
2221 if (logged) {
2223 ast_channel_unlock(logged);
2224 ast_channel_unref(logged);
2225 }
2226 }
2227 agent_unlock(agent);
2228 ao2_ref(agent, -1);
2229
2230 return 0;
2231}
jack_status_t status
Definition: app_jack.c:146
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
const ast_string_field moh
static struct aco_type item
Definition: test_config.c:1463
const char * args

References agent_lock, agent_lock_logged(), agent_unlock, agents, ao2_find, ao2_ref, args, AST_APP_ARG, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log, AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), buf, agent_pvt::cfg, ast_channel::data, agent_cfg::full_name, item, len(), LOG_WARNING, agent_pvt::logged, agent_cfg::moh, OBJ_KEY, and status.

◆ agent_handle_logoff_cmd()

static char * agent_handle_logoff_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 2463 of file app_agent_pool.c.

2464{
2465 switch (cmd) {
2466 case CLI_INIT:
2467 e->command = "agent logoff";
2468 e->usage =
2469 "Usage: agent logoff <agent-id> [soft]\n"
2470 " Sets an agent as no longer logged in.\n"
2471 " If 'soft' is specified, do not hangup existing calls.\n";
2472 return NULL;
2473 case CLI_GENERATE:
2474 if (a->pos == 2) {
2475 return complete_agent_logoff(a->word, a->n);
2476 } else if (a->pos == 3 && a->n == 0
2477 && (ast_strlen_zero(a->word)
2478 || !strncasecmp("soft", a->word, strlen(a->word)))) {
2479 return ast_strdup("soft");
2480 }
2481 return NULL;
2482 }
2483
2484 if (a->argc < 3 || 4 < a->argc) {
2485 return CLI_SHOWUSAGE;
2486 }
2487 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) {
2488 return CLI_SHOWUSAGE;
2489 }
2490
2491 if (!agent_logoff_request(a->argv[2], a->argc == 4)) {
2492 ast_cli(a->fd, "Logging out %s\n", a->argv[2]);
2493 }
2494
2495 return CLI_SUCCESS;
2496}
static char * complete_agent_logoff(const char *word, int state)
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
static struct test_val a

References a, agent_logoff_request(), ast_cli(), ast_strdup, ast_strlen_zero(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_agent_logoff(), NULL, and ast_cli_entry::usage.

◆ agent_handle_show_all()

static char * agent_handle_show_all ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 2382 of file app_agent_pool.c.

2383{
2384 switch (cmd) {
2385 case CLI_INIT:
2386 e->command = "agent show all";
2387 e->usage =
2388 "Usage: agent show all\n"
2389 " Provides summary information for all agents.\n";
2390 return NULL;
2391 case CLI_GENERATE:
2392 return NULL;
2393 }
2394
2395 if (a->argc != 3) {
2396 return CLI_SHOWUSAGE;
2397 }
2398
2400
2401 return CLI_SUCCESS;
2402}
static void agent_show_requested(struct ast_cli_args *a, int online_only)

References a, agent_show_requested(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

◆ agent_handle_show_online()

static char * agent_handle_show_online ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 2360 of file app_agent_pool.c.

2361{
2362 switch (cmd) {
2363 case CLI_INIT:
2364 e->command = "agent show online";
2365 e->usage =
2366 "Usage: agent show online\n"
2367 " Provides summary information for logged in agents.\n";
2368 return NULL;
2369 case CLI_GENERATE:
2370 return NULL;
2371 }
2372
2373 if (a->argc != 3) {
2374 return CLI_SHOWUSAGE;
2375 }
2376
2378
2379 return CLI_SUCCESS;
2380}

References a, agent_show_requested(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

◆ agent_handle_show_specific()

static char * agent_handle_show_specific ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 2404 of file app_agent_pool.c.

2405{
2406 struct agent_pvt *agent;
2407 struct ast_channel *logged;
2408 struct ast_str *out = ast_str_alloca(4096);
2409
2410 switch (cmd) {
2411 case CLI_INIT:
2412 e->command = "agent show";
2413 e->usage =
2414 "Usage: agent show <agent-id>\n"
2415 " Show information about the <agent-id> agent\n";
2416 return NULL;
2417 case CLI_GENERATE:
2418 if (a->pos == 2) {
2419 return complete_agent(a->word, a->n);
2420 }
2421 return NULL;
2422 }
2423
2424 if (a->argc != 3) {
2425 return CLI_SHOWUSAGE;
2426 }
2427
2428 agent = ao2_find(agents, a->argv[2], OBJ_KEY);
2429 if (!agent) {
2430 ast_cli(a->fd, "Agent '%s' not found\n", a->argv[2]);
2431 return CLI_SUCCESS;
2432 }
2433
2434 agent_lock(agent);
2435 logged = agent_lock_logged(agent);
2436 ast_str_set(&out, 0, "Id: %s\n", agent->username);
2437 ast_str_append(&out, 0, "Name: %s\n", agent->cfg->full_name);
2438 ast_str_append(&out, 0, "Beep: %s\n", agent->cfg->beep_sound);
2439 ast_str_append(&out, 0, "MOH: %s\n", agent->cfg->moh);
2440 ast_str_append(&out, 0, "RecordCalls: %s\n", AST_CLI_YESNO(agent->cfg->record_agent_calls));
2441 ast_str_append(&out, 0, "State: %s\n", ast_devstate_str(agent->devstate));
2442 if (logged) {
2443 const char *talking_with;
2444
2445 ast_str_append(&out, 0, "LoggedInChannel: %s\n", ast_channel_name(logged));
2446 ast_str_append(&out, 0, "LoggedInTime: %ld\n", (long) agent->login_start);
2447 talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2448 if (!ast_strlen_zero(talking_with)) {
2449 ast_str_append(&out, 0, "TalkingWith: %s\n", talking_with);
2450 ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2451 }
2452 ast_channel_unlock(logged);
2453 ast_channel_unref(logged);
2454 }
2455 agent_unlock(agent);
2456 ao2_ref(agent, -1);
2457
2458 ast_cli(a->fd, "%s", ast_str_buffer(out));
2459
2460 return CLI_SUCCESS;
2461}
static char * complete_agent(const char *word, int state)
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
Definition: cli.h:71
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
Definition: devicestate.c:255
enum ast_device_state devstate

References a, agent_lock, agent_lock_logged(), agent_unlock, agents, ao2_find, ao2_ref, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_cli(), AST_CLI_YESNO, ast_devstate_str(), ast_str_alloca, ast_str_append(), ast_str_buffer(), ast_str_set(), ast_strlen_zero(), agent_cfg::beep_sound, agent_pvt::call_start, agent_pvt::cfg, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_agent(), agent_pvt::devstate, agent_cfg::full_name, agent_pvt::login_start, agent_cfg::moh, NULL, OBJ_KEY, out, pbx_builtin_getvar_helper(), agent_cfg::record_agent_calls, ast_cli_entry::usage, and agent_pvt::username.

◆ agent_lock_logged()

static struct ast_channel * agent_lock_logged ( struct agent_pvt agent)
static

Definition at line 684 of file app_agent_pool.c.

685{
686 struct ast_channel *logged;
687
688 for (;;) {
689 if (!agent->logged) { /* No owner. Nothing to do. */
690 return NULL;
691 }
692
693 /* If we don't ref the logged, it could be killed when we unlock the agent. */
694 logged = ast_channel_ref(agent->logged);
695
696 /* Locking logged requires us to lock channel, then agent. */
697 agent_unlock(agent);
698 ast_channel_lock(logged);
699 agent_lock(agent);
700
701 /* Check if logged changed during agent unlock period */
702 if (logged != agent->logged) {
703 /* Channel changed. Unref and do another pass. */
704 ast_channel_unlock(logged);
705 ast_channel_unref(logged);
706 } else {
707 /* Channel stayed the same. Return it. */
708 return logged;
709 }
710 }
711}

References agent_lock, agent_unlock, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, agent_pvt::logged, and NULL.

Referenced by action_agents(), agent_function_read(), agent_handle_show_specific(), agent_logoff_request(), and agent_show_requested().

◆ agent_login_channel_config()

static void agent_login_channel_config ( struct agent_pvt agent,
struct ast_channel chan 
)
static

Definition at line 2018 of file app_agent_pool.c.

2019{
2020 struct ast_flags opts = { 0 };
2022 unsigned int override_ack_call = 0;
2023 unsigned int override_auto_logoff = 0;
2024 unsigned int override_wrapup_time = 0;
2025 const char *override_dtmf_accept = NULL;
2026 const char *var;
2027
2029
2030 /* Get config values from channel. */
2031 ast_channel_lock(chan);
2033
2034 var = pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2035 if (!ast_strlen_zero(var)) {
2036 override_ack_call = ast_true(var) ? 1 : 0;
2038 }
2039
2040 var = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2041 if (!ast_strlen_zero(var)) {
2042 override_dtmf_accept = ast_strdupa(var);
2044 }
2045
2046 var = pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2047 if (!ast_strlen_zero(var)) {
2048 if (sscanf(var, "%u", &override_auto_logoff) == 1) {
2050 }
2051 }
2052
2053 var = pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2054 if (!ast_strlen_zero(var)) {
2055 if (sscanf(var, "%u", &override_wrapup_time) == 1) {
2057 }
2058 }
2059 ast_channel_unlock(chan);
2060
2061 /* Set config values on agent. */
2062 agent_lock(agent);
2064 agent->waiting_colp = connected;
2065
2066 ast_string_field_set(agent, override_dtmf_accept, override_dtmf_accept);
2067 ast_copy_flags(agent, &opts, AST_FLAGS_ALL);
2068 agent->override_auto_logoff = override_auto_logoff;
2069 agent->override_wrapup_time = override_wrapup_time;
2070 agent->override_ack_call = override_ack_call;
2071 agent_unlock(agent);
2072}
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2091
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:2050
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:2041
char connected
Definition: eagi_proxy.c:82
unsigned int override_auto_logoff
struct ast_party_connected_line waiting_colp
unsigned int override_wrapup_time
Structure used to handle boolean flags.
Definition: utils.h:199
Connected Line/Party information.
Definition: channel.h:458
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196

References AGENT_FLAG_ACK_CALL, AGENT_FLAG_AUTO_LOGOFF, AGENT_FLAG_DTMF_ACCEPT, AGENT_FLAG_WRAPUP_TIME, agent_lock, agent_unlock, ast_channel_connected(), ast_channel_lock, ast_channel_unlock, ast_copy_flags, AST_FLAGS_ALL, ast_party_connected_line_copy(), ast_party_connected_line_free(), ast_party_connected_line_init(), ast_set_flag, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_true(), connected, NULL, agent_pvt::override_ack_call, agent_pvt::override_auto_logoff, agent_pvt::override_wrapup_time, pbx_builtin_getvar_helper(), var, and agent_pvt::waiting_colp.

Referenced by agent_login_exec().

◆ agent_login_exec()

static int agent_login_exec ( struct ast_channel chan,
const char *  data 
)
static

Dialplan AgentLogin application to log in an agent.

Parameters
chanChannel attempting to login as an agent.
dataApplication parameters
Return values
0To continue in dialplan.
-1To hangup.

Definition at line 2090 of file app_agent_pool.c.

2091{
2092 char *parse;
2093 struct ast_flags opts;
2095 AST_APP_ARG(agent_id);
2097 AST_APP_ARG(other); /* Any remaining unused arguments */
2098 );
2099
2100 RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
2101
2103 return -1;
2104 }
2105
2106 if (ast_channel_state(chan) != AST_STATE_UP && ast_answer(chan)) {
2107 return -1;
2108 }
2109
2110 parse = ast_strdupa(data);
2112
2113 if (ast_strlen_zero(args.agent_id)) {
2114 ast_log(LOG_WARNING, "AgentLogin requires an AgentId\n");
2115 return -1;
2116 }
2117
2118 if (ast_app_parse_options(agent_login_opts, &opts, NULL, args.options)) {
2119 /* General invalid option syntax. */
2120 return -1;
2121 }
2122
2123 /* Find the agent. */
2124 agent = ao2_find(agents, args.agent_id, OBJ_KEY);
2125 if (!agent) {
2126 ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
2127 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
2128 return 0;
2129 }
2130
2131 /* Has someone already logged in as this agent already? */
2132 agent_lock(agent);
2133 if (agent->logged) {
2134 agent_unlock(agent);
2135 ast_verb(3, "Agent '%s' already logged in.\n", agent->username);
2136 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ALREADY_LOGGED_IN");
2137 return 0;
2138 }
2139 agent->logged = ast_channel_ref(chan);
2140 agent->last_disconnect = ast_tvnow();
2141 time(&agent->login_start);
2142 agent->deferred_logoff = 0;
2143 agent_unlock(agent);
2144
2145 agent_login_channel_config(agent, chan);
2146
2147 if (!ast_test_flag(&opts, OPT_SILENT)) {
2148 ast_stream_and_wait(chan, "agent-loginok", AST_DIGIT_NONE);
2149 }
2150
2151 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", agent->username,
2154 ast_channel_lock(chan);
2155 send_agent_login(chan, agent->username);
2156 ast_channel_unlock(chan);
2157
2158 agent_run(agent, chan);
2159 return -1;
2160}
static int bridge_agent_hold_deferred_create(void)
static void send_agent_login(struct ast_channel *chan, const char *agent)
static const struct ast_app_option agent_login_opts[128]
static void agent_login_channel_config(struct agent_pvt *agent, struct ast_channel *chan)
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:2824
struct ast_format * ast_channel_readformat(struct ast_channel *chan)
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
#define AST_DIGIT_NONE
Definition: file.h:47
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
#define ast_verb(level,...)
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.

References agent_lock, agent_login_channel_config(), agent_login_opts, agent_run(), agent_unlock, agents, ao2_cleanup, ao2_find, args, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_channel_lock, ast_channel_readformat(), ast_channel_ref, ast_channel_unlock, ast_channel_writeformat(), AST_DECLARE_APP_ARGS, AST_DIGIT_NONE, ast_format_get_name(), ast_log, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_stream_and_wait(), ast_strlen_zero(), ast_test_flag, ast_tvnow(), ast_verb, bridge_agent_hold_deferred_create(), LOG_WARNING, NULL, OBJ_KEY, OPT_SILENT, options, pbx_builtin_setvar_helper(), RAII_VAR, and send_agent_login().

Referenced by load_module().

◆ agent_logoff_request()

static int agent_logoff_request ( const char *  agent_id,
int  soft 
)
static

Definition at line 967 of file app_agent_pool.c.

968{
969 struct ast_channel *logged;
970 RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, agent_id, OBJ_KEY), ao2_cleanup);
971
972 if (!agent) {
973 return -1;
974 }
975
976 agent_lock(agent);
977 logged = agent_lock_logged(agent);
978 if (logged) {
979 if (soft) {
980 agent->deferred_logoff = 1;
981 } else {
983 }
984 ast_channel_unlock(logged);
985 ast_channel_unref(logged);
986 }
987 agent_unlock(agent);
988 return 0;
989}
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2490
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168

References agent_lock, agent_lock_logged(), agent_unlock, agents, ao2_cleanup, ao2_find, ast_channel_unlock, ast_channel_unref, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, OBJ_KEY, and RAII_VAR.

Referenced by action_agent_logoff(), and agent_handle_logoff_cmd().

◆ agent_logout()

static void agent_logout ( struct agent_pvt agent)
static

Definition at line 1463 of file app_agent_pool.c.

1464{
1465 struct ast_channel *logged;
1466 struct ast_bridge *caller_bridge;
1467 long time_logged_in;
1468
1469 time_logged_in = time(NULL) - agent->login_start;
1470 logged = agent->logged;
1471 agent->logged = NULL;
1472 caller_bridge = agent->caller_bridge;
1473 agent->caller_bridge = NULL;
1477 agent_unlock(agent);
1479
1480 if (caller_bridge) {
1481 ast_bridge_destroy(caller_bridge, 0);
1482 }
1483
1484 ast_channel_lock(logged);
1485 send_agent_logoff(logged, agent->username, time_logged_in);
1486 ast_channel_unlock(logged);
1487 ast_verb(2, "Agent '%s' logged out. Logged in for %ld seconds.\n",
1488 agent->username, time_logged_in);
1489 ast_channel_unref(logged);
1490}
static void send_agent_logoff(struct ast_channel *chan, const char *agent, long logintime)
static void agent_devstate_changed(const char *agent_id)
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
#define ast_clear_flag(p, flag)
Definition: utils.h:77

References agent_devstate_changed(), AGENT_STATE_LOGGED_OUT, agent_unlock, ast_bridge_destroy(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_clear_flag, AST_DEVICE_UNAVAILABLE, AST_FLAGS_ALL, ast_verb, agent_pvt::caller_bridge, agent_pvt::devstate, agent_pvt::logged, agent_pvt::login_start, NULL, send_agent_logoff(), agent_pvt::state, and agent_pvt::username.

Referenced by agent_after_bridge_cb_failed(), and agent_run().

◆ agent_mark()

static int agent_mark ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 866 of file app_agent_pool.c.

867{
868 struct agent_pvt *agent = obj;
869
870 agent_lock(agent);
871 agent->the_mark = 1;
872 agent_unlock(agent);
873 return 0;
874}
unsigned int the_mark

References agent_lock, agent_unlock, and agent_pvt::the_mark.

Referenced by agents_mark().

◆ agent_pvt_cmp()

static int agent_pvt_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 844 of file app_agent_pool.c.

845{
846 const struct agent_pvt *agent = obj;
847 int cmp;
848
849 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
850 case OBJ_POINTER:
851 case OBJ_KEY:
852 case OBJ_PARTIAL_KEY:
853 cmp = CMP_MATCH;
854 break;
855 default:
856 if (agent->logged == arg) {
857 cmp = CMP_MATCH;
858 } else {
859 cmp = 0;
860 }
861 break;
862 }
863 return cmp;
864}
@ CMP_MATCH
Definition: astobj2.h:1027
unsigned int flags

References CMP_MATCH, agent_pvt::flags, agent_pvt::logged, OBJ_KEY, OBJ_PARTIAL_KEY, and OBJ_POINTER.

Referenced by load_module().

◆ agent_pvt_destructor()

static void agent_pvt_destructor ( void *  vdoomed)
static

Definition at line 753 of file app_agent_pool.c.

754{
755 struct agent_pvt *doomed = vdoomed;
756
757 /* Make sure device state reflects agent destruction. */
758 if (!ast_strlen_zero(doomed->username)) {
759 ast_debug(1, "Agent %s: Destroyed.\n", doomed->username);
761 }
762
764 if (doomed->caller_bridge) {
766 doomed->caller_bridge = NULL;
767 }
768 if (doomed->logged) {
769 doomed->logged = ast_channel_unref(doomed->logged);
770 }
771 ao2_cleanup(doomed->cfg);
772 doomed->cfg = NULL;
774}

References agent_devstate_changed(), ao2_cleanup, ast_bridge_destroy(), ast_channel_unref, ast_debug, ast_party_connected_line_free(), ast_string_field_free_memory, ast_strlen_zero(), agent_pvt::caller_bridge, agent_pvt::cfg, agent_pvt::logged, NULL, agent_pvt::username, and agent_pvt::waiting_colp.

Referenced by agent_pvt_new().

◆ agent_pvt_devstate_get()

static enum ast_device_state agent_pvt_devstate_get ( const char *  agent_id)
static

Definition at line 726 of file app_agent_pool.c.

727{
728 enum ast_device_state dev_state = AST_DEVICE_INVALID;
729 struct agent_pvt *agent;
730
731 agent = ao2_find(agents, agent_id, OBJ_KEY);
732 if (agent) {
733 agent_lock(agent);
734 dev_state = agent->devstate;
735 agent_unlock(agent);
736 ao2_ref(agent, -1);
737 }
738 return dev_state;
739}
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_INVALID
Definition: devicestate.h:57

References agent_lock, agent_unlock, agents, ao2_find, ao2_ref, AST_DEVICE_INVALID, agent_pvt::devstate, and OBJ_KEY.

Referenced by load_module().

◆ agent_pvt_new()

static struct agent_pvt * agent_pvt_new ( struct agent_cfg cfg)
static

Definition at line 776 of file app_agent_pool.c.

777{
778 struct agent_pvt *agent;
779
780 agent = ao2_alloc(sizeof(*agent), agent_pvt_destructor);
781 if (!agent) {
782 return NULL;
783 }
784 if (ast_string_field_init(agent, 32)) {
785 ao2_ref(agent, -1);
786 return NULL;
787 }
790 ao2_ref(cfg, +1);
791 agent->cfg = cfg;
793 return agent;
794}
static void agent_pvt_destructor(void *vdoomed)
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409

References agent_pvt_destructor(), ao2_alloc, ao2_ref, AST_DEVICE_UNAVAILABLE, ast_party_connected_line_init(), ast_string_field_init, ast_string_field_set, agent_pvt::cfg, agent_pvt::devstate, NULL, agent_cfg::username, agent_pvt::username, and agent_pvt::waiting_colp.

Referenced by agents_post_apply_config().

◆ agent_pvt_sort_cmp()

static int agent_pvt_sort_cmp ( const void *  obj_left,
const void *  obj_right,
int  flags 
)
static

Definition at line 812 of file app_agent_pool.c.

813{
814 const struct agent_pvt *agent_left = obj_left;
815 const struct agent_pvt *agent_right = obj_right;
816 const char *right_key = obj_right;
817 int cmp;
818
819 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
820 default:
821 case OBJ_POINTER:
822 right_key = agent_right->username;
823 /* Fall through */
824 case OBJ_KEY:
825 cmp = strcmp(agent_left->username, right_key);
826 break;
827 case OBJ_PARTIAL_KEY:
828 cmp = strncmp(agent_left->username, right_key, strlen(right_key));
829 break;
830 }
831 return cmp;
832}

References agent_pvt::flags, OBJ_KEY, OBJ_PARTIAL_KEY, OBJ_POINTER, and agent_pvt::username.

Referenced by load_module().

◆ agent_request_exec()

static int agent_request_exec ( struct ast_channel chan,
const char *  data 
)
static

Dialplan AgentRequest application to locate an agent to talk with.

Parameters
chanChannel wanting to talk with an agent.
dataApplication parameters
Return values
0To continue in dialplan.
-1To hangup.

Definition at line 1869 of file app_agent_pool.c.

1870{
1871 struct ast_bridge *caller_bridge;
1872 struct ast_bridge_channel *logged;
1873 char *parse;
1874 int res;
1875 struct ast_bridge_features caller_features;
1878 AST_APP_ARG(agent_id);
1879 AST_APP_ARG(other); /* Any remaining unused arguments */
1880 );
1881
1882 RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1883
1885 return -1;
1886 }
1887
1888 parse = ast_strdupa(data);
1890
1891 if (ast_strlen_zero(args.agent_id)) {
1892 ast_log(LOG_WARNING, "AgentRequest requires an AgentId\n");
1893 return -1;
1894 }
1895
1896 /* Find the agent. */
1897 agent = ao2_find(agents, args.agent_id, OBJ_KEY);
1898 if (!agent) {
1899 ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
1900 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
1901 return 0;
1902 }
1903
1904 if (ast_bridge_features_init(&caller_features)) {
1905 return -1;
1906 }
1907
1908 /* Add safety timeout hook. */
1909 ao2_ref(agent, +1);
1912 ao2_ref(agent, -1);
1913 ast_bridge_features_cleanup(&caller_features);
1914 return -1;
1915 }
1916
1917 /* Setup the alert agent on caller joining the bridge hook. */
1918 ao2_ref(agent, +1);
1919 if (ast_bridge_join_hook(&caller_features, caller_joined_bridge, agent,
1920 __ao2_cleanup, 0)) {
1921 ao2_ref(agent, -1);
1922 ast_bridge_features_cleanup(&caller_features);
1923 return -1;
1924 }
1925
1926 caller_bridge = ast_bridge_basic_new();
1927 if (!caller_bridge) {
1928 ast_bridge_features_cleanup(&caller_features);
1929 return -1;
1930 }
1931
1932 agent_lock(agent);
1933 switch (agent->state) {
1936 agent_unlock(agent);
1937 ast_bridge_destroy(caller_bridge, 0);
1938 ast_bridge_features_cleanup(&caller_features);
1939 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1940 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1941 return 0;
1943 ao2_ref(caller_bridge, +1);
1944 agent->caller_bridge = caller_bridge;
1945 agent->state = AGENT_STATE_CALL_PRESENT;
1946 agent->devstate = AST_DEVICE_INUSE;
1947 break;
1948 default:
1949 agent_unlock(agent);
1950 ast_bridge_destroy(caller_bridge, 0);
1951 ast_bridge_features_cleanup(&caller_features);
1952 ast_verb(3, "Agent '%s' is busy.\n", agent->username);
1953 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "BUSY");
1954 return 0;
1955 }
1956 agent_unlock(agent);
1957 agent_devstate_changed(agent->username);
1958
1959 /* Get COLP for agent. */
1961 ast_channel_lock(chan);
1963 ast_channel_unlock(chan);
1964
1965 logged = agent_bridge_channel_get_lock(agent);
1966 if (!logged) {
1968 caller_abort_agent(agent);
1969 ast_bridge_destroy(caller_bridge, 0);
1970 ast_bridge_features_cleanup(&caller_features);
1971 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1972 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1973 return 0;
1974 }
1975
1976 send_colp_to_agent(logged, &connected);
1978 ao2_ref(logged, -1);
1980
1981 if (ast_bridge_join(caller_bridge, chan, NULL, &caller_features, NULL,
1983 caller_abort_agent(agent);
1984 ast_verb(3, "Agent '%s': Caller %s failed to join the bridge.\n",
1985 agent->username, ast_channel_name(chan));
1986 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ERROR");
1987 }
1988 ast_bridge_features_cleanup(&caller_features);
1989
1990 /* Determine if we need to continue in the dialplan after the bridge. */
1991 ast_channel_lock(chan);
1993 /*
1994 * The bridge was broken for a hangup that isn't real.
1995 * Don't run the h extension, because the channel isn't
1996 * really hung up. This should really only happen with
1997 * AST_SOFTHANGUP_ASYNCGOTO.
1998 */
1999 res = 0;
2000 } else {
2001 res = ast_check_hangup(chan)
2003 || ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENT_STATUS"));
2004 }
2005 ast_channel_unlock(chan);
2006
2007 return res ? -1 : 0;
2008}
#define CALLER_SAFETY_TIMEOUT_TIME
static int send_colp_to_agent(struct ast_bridge_channel *bridge_channel, struct ast_party_connected_line *connected)
static int caller_joined_bridge(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
static struct ast_bridge_channel * agent_bridge_channel_get_lock(struct agent_pvt *agent)
static int caller_safety_timeout(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
static void caller_abort_agent(struct agent_pvt *agent)
void __ao2_cleanup(void *obj)
Definition: astobj2.c:677
int ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, struct ast_bridge_tech_optimizations *tech_args, enum ast_bridge_join_flags flags)
Join a channel to a bridge (blocking)
Definition: bridge.c:1621
@ AST_BRIDGE_JOIN_PASS_REFERENCE
Definition: bridge.h:535
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
Definition: bridge.c:3620
int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach an interval hook to a bridge features structure.
Definition: bridge.c:3319
@ AST_BRIDGE_HOOK_REMOVE_ON_PULL
int ast_bridge_join_hook(struct ast_bridge_features *features, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a bridge channel join hook to a bridge features structure.
Definition: bridge.c:3275
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
Definition: bridge.c:3653
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
@ AST_SOFTHANGUP_ASYNCGOTO
Definition: channel.h:1146
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8315
@ AST_FLAG_ZOMBIE
Definition: channel.h:1007
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
Structure that contains features information.

References __ao2_cleanup(), agent_bridge_channel_get_lock(), agent_devstate_changed(), agent_lock, AGENT_STATE_CALL_PRESENT, AGENT_STATE_LOGGED_OUT, AGENT_STATE_LOGGING_OUT, AGENT_STATE_READY_FOR_CALL, agent_unlock, agents, ao2_cleanup, ao2_find, ao2_ref, args, AST_APP_ARG, ast_bridge_basic_new(), ast_bridge_channel_unlock, ast_bridge_destroy(), ast_bridge_features_cleanup(), ast_bridge_features_init(), AST_BRIDGE_HOOK_REMOVE_ON_PULL, ast_bridge_interval_hook(), ast_bridge_join(), ast_bridge_join_hook(), AST_BRIDGE_JOIN_PASS_REFERENCE, ast_channel_caller(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_softhangup_internal_flag(), ast_channel_unlock, ast_check_hangup(), ast_connected_line_copy_from_caller(), AST_DECLARE_APP_ARGS, AST_DEVICE_INUSE, AST_FLAG_ZOMBIE, ast_log, ast_party_connected_line_free(), ast_party_connected_line_init(), AST_SOFTHANGUP_ASYNCGOTO, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_verb, bridge_agent_hold_deferred_create(), caller_abort_agent(), caller_joined_bridge(), caller_safety_timeout(), CALLER_SAFETY_TIMEOUT_TIME, connected, LOG_WARNING, NULL, OBJ_KEY, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), RAII_VAR, and send_colp_to_agent().

Referenced by load_module().

◆ agent_run()

static void agent_run ( struct agent_pvt agent,
struct ast_channel logged 
)
static

Definition at line 1500 of file app_agent_pool.c.

1501{
1502 struct ast_bridge_features features;
1503
1504 if (ast_bridge_features_init(&features)) {
1506 goto agent_run_cleanup;
1507 }
1508 for (;;) {
1509 struct agents_cfg *cfgs;
1510 struct agent_cfg *cfg_new;
1511 struct agent_cfg *cfg_old;
1512 struct ast_bridge *holding;
1513 struct ast_bridge *caller_bridge;
1514
1516
1517 holding = ao2_global_obj_ref(agent_holding);
1518 if (!holding) {
1519 ast_debug(1, "Agent %s: Someone destroyed the agent holding bridge.\n",
1520 agent->username);
1521 break;
1522 }
1523
1524 /*
1525 * When the agent channel leaves the bridging system we usually
1526 * want to put the agent back into the holding bridge for the
1527 * next caller.
1528 */
1529 ast_bridge_join(holding, logged, NULL, &features, NULL,
1531 if (logged != agent->logged) {
1532 /* This channel is no longer the logged in agent. */
1533 break;
1534 }
1535
1536 if (agent->dead) {
1537 /* The agent is no longer configured. */
1538 break;
1539 }
1540
1541 /* Update the agent's config before rejoining the holding bridge. */
1543 if (!cfgs) {
1544 /* There is no agent configuration. All agents were destroyed. */
1545 break;
1546 }
1547 cfg_new = ao2_find(cfgs->agents, agent->username, OBJ_KEY);
1548 ao2_ref(cfgs, -1);
1549 if (!cfg_new) {
1550 /* The agent is no longer configured. */
1551 break;
1552 }
1553 agent_lock(agent);
1554 cfg_old = agent->cfg;
1555 agent->cfg = cfg_new;
1556
1557 agent->last_disconnect = ast_tvnow();
1558
1559 /* Clear out any caller bridge before rejoining the holding bridge. */
1560 caller_bridge = agent->caller_bridge;
1561 agent->caller_bridge = NULL;
1562 agent_unlock(agent);
1563 ao2_ref(cfg_old, -1);
1564 if (caller_bridge) {
1565 ast_bridge_destroy(caller_bridge, 0);
1566 }
1567
1568 if (agent->state == AGENT_STATE_LOGGING_OUT
1569 || agent->deferred_logoff
1570 || ast_check_hangup_locked(logged)) {
1571 /* The agent was requested to logout or hungup. */
1572 break;
1573 }
1574
1575 /*
1576 * It is safe to access agent->waiting_colp without a lock. It
1577 * is only setup on agent login and not changed.
1578 */
1580 }
1581 ast_bridge_features_cleanup(&features);
1582
1583agent_run_cleanup:
1584 agent_lock(agent);
1585 if (logged != agent->logged) {
1586 /*
1587 * We are no longer the agent channel because of local channel
1588 * optimization.
1589 */
1590 agent_unlock(agent);
1591 ast_debug(1, "Agent %s: Channel %s is no longer the agent.\n",
1592 agent->username, ast_channel_name(logged));
1593 return;
1594 }
1595 agent_logout(agent);
1596}
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
int ast_check_hangup_locked(struct ast_channel *chan)
Definition: channel.c:459
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9115
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
static corosync_cfg_handle_t cfg_handle
Definition: res_corosync.c:284
unsigned int dead
TRUE if the agent is no longer configured and is being destroyed.
struct timeval last_disconnect
unsigned int deferred_logoff
struct ao2_container * agents

References agent_lock, agent_logout(), AGENT_STATE_LOGGING_OUT, agent_unlock, agents_cfg::agents, ao2_find, ao2_global_obj_ref, ao2_ref, ast_bridge_destroy(), ast_bridge_features_cleanup(), ast_bridge_features_init(), ast_bridge_join(), AST_BRIDGE_JOIN_PASS_REFERENCE, AST_CAUSE_NORMAL_CLEARING, ast_channel_hangupcause_set(), ast_channel_name(), ast_channel_update_connected_line(), ast_check_hangup_locked(), ast_debug, ast_tvnow(), agent_pvt::caller_bridge, agent_pvt::cfg, cfg_handle, agent_pvt::dead, agent_pvt::deferred_logoff, agent_pvt::last_disconnect, agent_pvt::logged, NULL, OBJ_KEY, agent_pvt::state, agent_pvt::username, and agent_pvt::waiting_colp.

Referenced by agent_after_bridge_cb(), and agent_login_exec().

◆ agent_show_requested()

static void agent_show_requested ( struct ast_cli_args a,
int  online_only 
)
static

Definition at line 2305 of file app_agent_pool.c.

2306{
2307#define FORMAT_HDR "%-8s %-20s %-11s %-30s %s\n"
2308#define FORMAT_ROW "%-8s %-20s %-11s %-30s %s\n"
2309
2310 struct ao2_iterator iter;
2311 struct agent_pvt *agent;
2312 struct ast_str *out = ast_str_alloca(512);
2313 unsigned int agents_total = 0;
2314 unsigned int agents_logged_in = 0;
2315 unsigned int agents_talking = 0;
2316
2317 ast_cli(a->fd, FORMAT_HDR, "Agent-ID", "Name", "State", "Channel", "Talking with");
2318 iter = ao2_iterator_init(agents, 0);
2319 for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2320 struct ast_channel *logged;
2321
2322 ++agents_total;
2323
2324 agent_lock(agent);
2325 logged = agent_lock_logged(agent);
2326 if (logged) {
2327 const char *talking_with;
2328
2329 ++agents_logged_in;
2330
2331 talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2332 if (!ast_strlen_zero(talking_with)) {
2333 ++agents_talking;
2334 } else {
2335 talking_with = "";
2336 }
2337 ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
2338 ast_devstate_str(agent->devstate), ast_channel_name(logged), talking_with);
2339 ast_channel_unlock(logged);
2340 ast_channel_unref(logged);
2341 } else {
2342 ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
2343 ast_devstate_str(agent->devstate), "", "");
2344 }
2345 agent_unlock(agent);
2346
2347 if (!online_only || logged) {
2348 ast_cli(a->fd, "%s", ast_str_buffer(out));
2349 }
2350 }
2351 ao2_iterator_destroy(&iter);
2352
2353 ast_cli(a->fd, "\nDefined agents: %u, Logged in: %u, Talking: %u\n",
2354 agents_total, agents_logged_in, agents_talking);
2355
2356#undef FORMAT_HDR
2357#undef FORMAT_ROW
2358}
#define FORMAT_ROW
#define FORMAT_HDR

References a, agent_lock, agent_lock_logged(), agent_unlock, agents, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_channel_name(), ast_channel_unlock, ast_channel_unref, ast_cli(), ast_devstate_str(), ast_str_alloca, ast_str_buffer(), ast_str_set(), ast_strlen_zero(), agent_pvt::cfg, agent_pvt::devstate, FORMAT_HDR, FORMAT_ROW, agent_cfg::full_name, out, pbx_builtin_getvar_helper(), and agent_pvt::username.

Referenced by agent_handle_show_all(), and agent_handle_show_online().

◆ agent_sweep()

static int agent_sweep ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 881 of file app_agent_pool.c.

882{
883 struct agent_pvt *agent = obj;
884 int cmp = 0;
885
886 agent_lock(agent);
887 if (agent->the_mark) {
888 agent->the_mark = 0;
889 agent->dead = 1;
890 /* Unlink dead agents immediately. */
891 cmp = CMP_MATCH;
892 }
893 agent_unlock(agent);
894 return cmp;
895}

References agent_lock, agent_unlock, CMP_MATCH, agent_pvt::dead, and agent_pvt::the_mark.

Referenced by agents_sweep().

◆ agents_cfg_alloc()

static void * agents_cfg_alloc ( void  )
static

Definition at line 512 of file app_agent_pool.c.

513{
514 struct agents_cfg *cfg;
515
516 cfg = ao2_alloc_options(sizeof(*cfg), agents_cfg_destructor,
518 if (!cfg) {
519 return NULL;
520 }
523 if (!cfg->agents) {
524 ao2_ref(cfg, -1);
525 cfg = NULL;
526 }
527 return cfg;
528}
static void agents_cfg_destructor(void *vdoomed)
static int agent_cfg_sort_cmp(const void *obj_left, const void *obj_right, int flags)
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188

References agent_cfg_sort_cmp(), agents_cfg::agents, agents_cfg_destructor(), AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, ao2_container_alloc_rbtree, ao2_ref, and NULL.

◆ agents_cfg_destructor()

static void agents_cfg_destructor ( void *  vdoomed)
static

Definition at line 492 of file app_agent_pool.c.

493{
494 struct agents_cfg *doomed = vdoomed;
495
496 ao2_cleanup(doomed->agents);
497 doomed->agents = NULL;
498}

References agents_cfg::agents, ao2_cleanup, and NULL.

Referenced by agents_cfg_alloc().

◆ agents_mark()

static void agents_mark ( void  )
static

Definition at line 876 of file app_agent_pool.c.

877{
879}
static int agent_mark(void *obj, void *arg, int flags)
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693

References agent_mark(), agents, ao2_callback, and NULL.

Referenced by agents_post_apply_config().

◆ agents_post_apply_config()

static void agents_post_apply_config ( void  )
static

Definition at line 927 of file app_agent_pool.c.

928{
929 struct ao2_iterator iter;
930 struct agent_cfg *cfg;
932
933 ast_assert(cfgs != NULL);
934
935 agents_mark();
936 iter = ao2_iterator_init(cfgs->agents, 0);
937 for (; (cfg = ao2_iterator_next(&iter)); ao2_ref(cfg, -1)) {
938 RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, cfg->username, OBJ_KEY), ao2_cleanup);
939
940 if (agent) {
941 agent_lock(agent);
942 agent->the_mark = 0;
943 if (!agent->logged) {
944 struct agent_cfg *cfg_old;
945
946 /* Replace the config of agents not logged in. */
947 cfg_old = agent->cfg;
948 ao2_ref(cfg, +1);
949 agent->cfg = cfg;
950 ao2_cleanup(cfg_old);
951 }
952 agent_unlock(agent);
953 continue;
954 }
955 agent = agent_pvt_new(cfg);
956 if (!agent) {
957 continue;
958 }
959 ao2_link(agents, agent);
960 ast_debug(1, "Agent %s: Created.\n", agent->username);
961 agent_devstate_changed(agent->username);
962 }
964 agents_sweep();
965}
static struct agent_pvt * agent_pvt_new(struct agent_cfg *cfg)
static void agents_mark(void)
static void agents_sweep(void)
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ast_assert(a)
Definition: utils.h:739

References agent_devstate_changed(), agent_lock, agent_pvt_new(), agent_unlock, agents, agents_mark(), agents_sweep(), ao2_cleanup, ao2_find, ao2_global_obj_ref, ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_link, ao2_ref, ast_assert, ast_debug, cfg_handle, NULL, OBJ_KEY, RAII_VAR, and agent_cfg::username.

◆ agents_sweep()

static void agents_sweep ( void  )
static

Definition at line 897 of file app_agent_pool.c.

898{
899 struct ao2_iterator *iter;
900 struct agent_pvt *agent;
901 struct ast_channel *logged;
902
904 if (!iter) {
905 return;
906 }
907 for (; (agent = ao2_iterator_next(iter)); ao2_ref(agent, -1)) {
908 agent_lock(agent);
909 if (agent->logged) {
910 logged = ast_channel_ref(agent->logged);
911 } else {
912 logged = NULL;
913 }
914 agent_unlock(agent);
915 if (!logged) {
916 continue;
917 }
919 "Forced logoff of agent %s(%s). Agent no longer configured.\n",
920 agent->username, ast_channel_name(logged));
922 ast_channel_unref(logged);
923 }
925}
static int agent_sweep(void *obj, void *arg, int flags)
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define LOG_NOTICE

References agent_lock, agent_sweep(), agent_unlock, agents, ao2_callback, ao2_iterator_destroy(), ao2_iterator_next, ao2_ref, ast_channel_name(), ast_channel_ref, ast_channel_unref, ast_log, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, LOG_NOTICE, agent_pvt::logged, NULL, OBJ_MULTIPLE, OBJ_UNLINK, and agent_pvt::username.

Referenced by agents_post_apply_config().

◆ AO2_GLOBAL_OBJ_STATIC() [1/2]

static AO2_GLOBAL_OBJ_STATIC ( agent_holding  )
static

Agent holding bridge instance holder.

◆ AO2_GLOBAL_OBJ_STATIC() [2/2]

static AO2_GLOBAL_OBJ_STATIC ( cfg_handle  )
static

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 2694 of file app_agent_pool.c.

◆ bridge_agent_hold_ack()

static int bridge_agent_hold_ack ( struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
)
static

Definition at line 1073 of file app_agent_pool.c.

1074{
1075 struct agent_pvt *agent = hook_pvt;
1076
1077 agent_lock(agent);
1078 switch (agent->state) {
1080 /* Connect to caller now. */
1081 ast_debug(1, "Agent %s: Acked call.\n", agent->username);
1082 agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
1083 return 0;
1084 default:
1085 break;
1086 }
1087 agent_unlock(agent);
1088 return 0;
1089}

References agent_connect_caller(), agent_lock, AGENT_STATE_CALL_WAIT_ACK, agent_unlock, ast_debug, agent_pvt::state, and agent_pvt::username.

Referenced by bridge_agent_hold_push().

◆ bridge_agent_hold_deferred_create()

static int bridge_agent_hold_deferred_create ( void  )
static

Definition at line 1403 of file app_agent_pool.c.

1404{
1405 RAII_VAR(struct ast_bridge *, holding, ao2_global_obj_ref(agent_holding), ao2_cleanup);
1406
1407 if (!holding) {
1409 holding = ao2_global_obj_ref(agent_holding);
1410 if (!holding) {
1411 holding = bridge_agent_hold_new();
1412 ao2_global_obj_replace_unref(agent_holding, holding);
1413 }
1415 if (!holding) {
1416 ast_log(LOG_ERROR, "Could not create agent holding bridge.\n");
1417 return -1;
1418 }
1419 }
1420 return 0;
1421}
static struct ast_bridge * bridge_agent_hold_new(void)
static ast_mutex_t agent_holding_lock
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define LOG_ERROR
#define ast_mutex_unlock(a)
Definition: lock.h:190
#define ast_mutex_lock(a)
Definition: lock.h:189

References agent_holding_lock, ao2_cleanup, ao2_global_obj_ref, ao2_global_obj_replace_unref, ast_log, ast_mutex_lock, ast_mutex_unlock, bridge_agent_hold_new(), LOG_ERROR, and RAII_VAR.

Referenced by agent_login_exec(), and agent_request_exec().

◆ bridge_agent_hold_dissolving()

static void bridge_agent_hold_dissolving ( struct ast_bridge self)
static

The bridge is being dissolved.

Parameters
selfBridge to operate upon.

The bridge is being dissolved. Remove any external references to the bridge so it can be destroyed.

Note
On entry, self must NOT be locked.

Definition at line 1372 of file app_agent_pool.c.

1373{
1374 ao2_global_obj_release(agent_holding);
1376}
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
struct ast_bridge_methods ast_bridge_base_v_table
Bridge base class virtual method table.
Definition: bridge.c:923
ast_bridge_dissolving_fn dissolving
Definition: bridge.h:263

References ao2_global_obj_release, ast_bridge_base_v_table, and ast_bridge_methods::dissolving.

Referenced by bridge_init_agent_hold().

◆ bridge_agent_hold_heartbeat()

static int bridge_agent_hold_heartbeat ( struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
)
static

Definition at line 1091 of file app_agent_pool.c.

1092{
1093 struct agent_pvt *agent = hook_pvt;
1094 int probation_timedout = 0;
1095 int ack_timedout = 0;
1096 int wrapup_timedout = 0;
1097 int deferred_logoff;
1098 unsigned int wrapup_time;
1099 unsigned int auto_logoff;
1100
1101 agent_lock(agent);
1103 if (deferred_logoff) {
1105 }
1106
1107 switch (agent->state) {
1109 probation_timedout =
1110 LOGIN_WAIT_TIMEOUT_TIME <= (time(NULL) - agent->probation_start);
1111 if (probation_timedout) {
1112 /* Now ready for a caller. */
1115 }
1116 break;
1118 /* Check ack call time. */
1119 auto_logoff = agent->cfg->auto_logoff;
1121 auto_logoff = agent->override_auto_logoff;
1122 }
1123 if (auto_logoff) {
1124 auto_logoff *= 1000;
1125 ack_timedout = ast_tvdiff_ms(ast_tvnow(), agent->ack_time) > auto_logoff;
1126 if (ack_timedout) {
1128 }
1129 }
1130 break;
1132 /* Check wrapup time. */
1133 wrapup_time = agent->cfg->wrapup_time;
1135 wrapup_time = agent->override_wrapup_time;
1136 }
1137 wrapup_timedout = ast_tvdiff_ms(ast_tvnow(), agent->last_disconnect) > wrapup_time;
1138 if (wrapup_timedout) {
1141 }
1142 break;
1143 default:
1144 break;
1145 }
1146 agent_unlock(agent);
1147
1148 if (deferred_logoff) {
1149 ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username);
1152 } else if (probation_timedout) {
1153 ast_debug(1, "Agent %s: Login complete.\n", agent->username);
1155 } else if (ack_timedout) {
1156 ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username);
1159 } else if (wrapup_timedout) {
1160 ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username);
1162 }
1163
1164 return 0;
1165}
#define LOGIN_WAIT_TIMEOUT_TIME
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
unsigned int auto_logoff
Number of seconds for agent to ack a call before being logged off.
unsigned int wrapup_time
Time after a call in ms before the agent can get a new call.
time_t probation_start
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107

References agent_pvt::ack_time, agent_devstate_changed(), AGENT_FLAG_AUTO_LOGOFF, AGENT_FLAG_WRAPUP_TIME, agent_lock, AGENT_STATE_CALL_WAIT_ACK, AGENT_STATE_CALL_WRAPUP, AGENT_STATE_LOGGING_OUT, AGENT_STATE_PROBATION_WAIT, AGENT_STATE_READY_FOR_CALL, agent_unlock, ast_bridge_channel_leave_bridge(), AST_CAUSE_NORMAL_CLEARING, ast_debug, AST_DEVICE_NOT_INUSE, ast_test_flag, ast_tvdiff_ms(), ast_tvnow(), agent_cfg::auto_logoff, BRIDGE_CHANNEL_STATE_END, agent_pvt::cfg, agent_pvt::deferred_logoff, agent_pvt::devstate, agent_pvt::last_disconnect, LOGIN_WAIT_TIMEOUT_TIME, NULL, agent_pvt::override_auto_logoff, agent_pvt::override_wrapup_time, agent_pvt::probation_start, agent_pvt::state, agent_pvt::username, and agent_cfg::wrapup_time.

Referenced by bridge_agent_hold_push().

◆ bridge_agent_hold_new()

static struct ast_bridge * bridge_agent_hold_new ( void  )
static

Definition at line 1380 of file app_agent_pool.c.

1381{
1382 struct ast_bridge *bridge;
1383
1384 bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
1388 "AgentPool", NULL, NULL);
1389 bridge = bridge_register(bridge);
1390 return bridge;
1391}
static struct ast_bridge_methods bridge_agent_hold_v_table
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:86
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
@ AST_BRIDGE_FLAG_TRANSFER_PROHIBITED
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
struct ast_bridge * bridge_register(struct ast_bridge *bridge)
Register the new bridge with the system.
Definition: bridge.c:691
struct ast_bridge * bridge_base_init(struct ast_bridge *self, uint32_t capabilities, unsigned int flags, const char *creator, const char *name, const char *id)
Initialize the base class of the bridge.
Definition: bridge.c:742
struct ast_bridge * bridge_alloc(size_t size, const struct ast_bridge_methods *v_table)
Definition: bridge.c:706

References AST_BRIDGE_CAPABILITY_HOLDING, AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM, AST_BRIDGE_FLAG_MERGE_INHIBIT_TO, AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, AST_BRIDGE_FLAG_TRANSFER_PROHIBITED, bridge_agent_hold_v_table, bridge_alloc(), bridge_base_init(), bridge_register(), and NULL.

Referenced by bridge_agent_hold_deferred_create().

◆ bridge_agent_hold_pull()

static void bridge_agent_hold_pull ( struct ast_bridge self,
struct ast_bridge_channel bridge_channel 
)
static

Definition at line 1355 of file app_agent_pool.c.

1356{
1357 ast_channel_remove_bridge_role(bridge_channel->chan, "holding_participant");
1358 ast_bridge_base_v_table.pull(self, bridge_channel);
1359}
void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
Removes a bridge role from a channel.
Definition: bridge_roles.c:332
ast_bridge_pull_channel_fn pull
Definition: bridge.h:267

References ast_bridge_base_v_table, ast_channel_remove_bridge_role(), ast_channel::bridge_channel, ast_bridge_channel::chan, and ast_bridge_methods::pull.

Referenced by bridge_init_agent_hold().

◆ bridge_agent_hold_push()

static int bridge_agent_hold_push ( struct ast_bridge self,
struct ast_bridge_channel bridge_channel,
struct ast_bridge_channel swap 
)
static
Todo:
XXX the login probation time should be only if it is needed.

Need to determine if there are any local channels that can optimize and wait until they actually do before leaving the AGENT_STATE_PROBATION_WAIT state. For now, the blind timer of LOGIN_WAIT_TIMEOUT_TIME will do.

Definition at line 1184 of file app_agent_pool.c.

1185{
1186 int res = 0;
1187 unsigned int wrapup_time;
1188 char dtmf[AST_FEATURE_MAX_LEN];
1189 struct ast_channel *chan;
1190 const char *moh_class;
1191 RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1192
1193 chan = bridge_channel->chan;
1194
1195 agent = ao2_find(agents, swap ? swap->chan : chan, 0);
1196 if (!agent) {
1197 /* Could not find the agent. */
1198 return -1;
1199 }
1200
1201 /* Setup agent entertainment */
1202 agent_lock(agent);
1203 moh_class = ast_strdupa(agent->cfg->moh);
1204 agent_unlock(agent);
1205 res |= ast_channel_add_bridge_role(chan, "holding_participant");
1206 res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
1207 res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", moh_class);
1208
1209 /* Add DTMF acknowledge hook. */
1210 dtmf[0] = '\0';
1211 agent_lock(agent);
1213 ? agent->override_ack_call : agent->cfg->ack_call) {
1214 const char *dtmf_accept;
1215
1216 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1217 ? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
1218 ast_copy_string(dtmf, dtmf_accept, sizeof(dtmf));
1219 }
1220 agent_unlock(agent);
1221 if (!ast_strlen_zero(dtmf)) {
1222 ao2_ref(agent, +1);
1225 ao2_ref(agent, -1);
1226 res = -1;
1227 }
1228 }
1229
1230 /* Add heartbeat interval hook. */
1231 ao2_ref(agent, +1);
1234 ao2_ref(agent, -1);
1235 res = -1;
1236 }
1237
1238 res |= ast_bridge_base_v_table.push(self, bridge_channel, swap);
1239 if (res) {
1240 ast_channel_remove_bridge_role(chan, "holding_participant");
1241 return -1;
1242 }
1243
1244 if (swap) {
1247 if (res) {
1248 ast_channel_remove_bridge_role(chan, "holding_participant");
1249 return -1;
1250 }
1251
1252 agent_lock(agent);
1253 ast_channel_unref(agent->logged);
1254 agent->logged = ast_channel_ref(chan);
1255 agent_unlock(agent);
1256
1257 /*
1258 * Kick the channel out so it can come back in fully controlled.
1259 * Otherwise, the after bridge callback will linger and the
1260 * agent will have some slightly different behavior in corner
1261 * cases.
1262 */
1265 return 0;
1266 }
1267
1268 agent_lock(agent);
1269 switch (agent->state) {
1271 /*!
1272 * \todo XXX the login probation time should be only if it is needed.
1273 *
1274 * Need to determine if there are any local channels that can
1275 * optimize and wait until they actually do before leaving the
1276 * AGENT_STATE_PROBATION_WAIT state. For now, the blind
1277 * timer of LOGIN_WAIT_TIMEOUT_TIME will do.
1278 */
1279 /*
1280 * Start the login probation timer.
1281 *
1282 * We cannot handle an agent local channel optimization when the
1283 * agent is on a call. The optimization may kick the agent
1284 * channel we know about out of the call without our being able
1285 * to switch to the replacement channel. Get any agent local
1286 * channel optimization out of the way while the agent is in the
1287 * holding bridge.
1288 */
1289 time(&agent->probation_start);
1290 agent->state = AGENT_STATE_PROBATION_WAIT;
1291 agent_unlock(agent);
1292 break;
1294 /* Restart the probation timer. */
1295 time(&agent->probation_start);
1296 agent_unlock(agent);
1297 break;
1299 /*
1300 * Likely someone manually kicked us out of the holding bridge
1301 * and we came right back in.
1302 */
1303 agent_unlock(agent);
1304 break;
1305 default:
1306 /* Unexpected agent state. */
1307 ast_assert(0);
1308 /* Fall through */
1311 agent->state = AGENT_STATE_READY_FOR_CALL;
1312 agent->devstate = AST_DEVICE_NOT_INUSE;
1313 agent_unlock(agent);
1314 ast_debug(1, "Agent %s: Call abort recovery complete.\n", agent->username);
1315 agent_devstate_changed(agent->username);
1316 break;
1319 wrapup_time = agent->cfg->wrapup_time;
1321 wrapup_time = agent->override_wrapup_time;
1322 }
1323 if (wrapup_time) {
1324 agent->state = AGENT_STATE_CALL_WRAPUP;
1325 } else {
1326 agent->state = AGENT_STATE_READY_FOR_CALL;
1327 agent->devstate = AST_DEVICE_NOT_INUSE;
1328 }
1329 agent_unlock(agent);
1330 if (!wrapup_time) {
1331 /* No wrapup time. */
1332 ast_debug(1, "Agent %s: Ready for new call.\n", agent->username);
1333 agent_devstate_changed(agent->username);
1334 }
1335 break;
1336 }
1337
1338 return 0;
1339}
static int bridge_agent_hold_heartbeat(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
static void agent_after_bridge_cb(struct ast_channel *chan, void *data)
static void agent_after_bridge_cb_failed(enum ast_bridge_after_cb_reason reason, void *data)
static int bridge_agent_hold_ack(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
int ast_bridge_set_after_callback(struct ast_channel *chan, ast_bridge_after_cb callback, ast_bridge_after_cb_failed failed, void *data)
Setup an after bridge callback for when the channel leaves the bridging system.
Definition: bridge_after.c:251
int ast_bridge_dtmf_hook(struct ast_bridge_features *features, const char *dtmf, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach a DTMF hook to a bridge features structure.
Definition: bridge.c:3182
int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
Adds a bridge role to a channel.
Definition: bridge_roles.c:313
#define AST_FEATURE_MAX_LEN
struct ast_bridge_features * features
ast_bridge_push_channel_fn push
Definition: bridge.h:265
struct ast_bridge_channel * bridge_channel

References __ao2_cleanup(), agent_after_bridge_cb(), agent_after_bridge_cb_failed(), agent_devstate_changed(), AGENT_FLAG_ACK_CALL, AGENT_FLAG_DTMF_ACCEPT, AGENT_FLAG_WRAPUP_TIME, agent_lock, AGENT_STATE_CALL_PRESENT, AGENT_STATE_CALL_WAIT_ACK, AGENT_STATE_CALL_WRAPUP, AGENT_STATE_LOGGED_OUT, AGENT_STATE_ON_CALL, AGENT_STATE_PROBATION_WAIT, AGENT_STATE_READY_FOR_CALL, agent_unlock, agents, ao2_cleanup, ao2_find, ao2_ref, ast_assert, ast_bridge_base_v_table, ast_bridge_channel_leave_bridge(), ast_bridge_dtmf_hook(), AST_BRIDGE_HOOK_REMOVE_ON_PULL, ast_bridge_interval_hook(), ast_bridge_set_after_callback(), AST_CAUSE_NORMAL_CLEARING, ast_channel_add_bridge_role(), ast_channel_ref, ast_channel_remove_bridge_role(), ast_channel_set_bridge_role_option(), ast_channel_unref, ast_copy_string(), ast_debug, AST_DEVICE_NOT_INUSE, AST_FEATURE_MAX_LEN, ast_strdupa, ast_strlen_zero(), ast_test_flag, bridge_agent_hold_ack(), bridge_agent_hold_heartbeat(), ast_channel::bridge_channel, BRIDGE_CHANNEL_STATE_END, ast_bridge_channel::chan, ast_bridge_channel::features, NULL, ast_bridge_methods::push, and RAII_VAR.

Referenced by bridge_init_agent_hold().

◆ bridge_init_agent_hold()

static void bridge_init_agent_hold ( void  )
static

Definition at line 1393 of file app_agent_pool.c.

1394{
1395 /* Setup bridge agent_hold subclass v_table. */
1397 bridge_agent_hold_v_table.name = "agent_hold";
1401}
static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
static void bridge_agent_hold_dissolving(struct ast_bridge *self)
The bridge is being dissolved.
static void bridge_agent_hold_pull(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel)
const char * name
Definition: bridge.h:259

References ast_bridge_base_v_table, bridge_agent_hold_dissolving(), bridge_agent_hold_pull(), bridge_agent_hold_push(), bridge_agent_hold_v_table, ast_bridge_methods::dissolving, ast_bridge_methods::name, ast_bridge_methods::pull, and ast_bridge_methods::push.

Referenced by load_module().

◆ caller_abort_agent()

static void caller_abort_agent ( struct agent_pvt agent)
static

Definition at line 1676 of file app_agent_pool.c.

1677{
1678 struct ast_bridge_channel *logged;
1679
1680 logged = agent_bridge_channel_get_lock(agent);
1681 if (!logged) {
1682 struct ast_bridge *caller_bridge;
1683
1684 ast_debug(1, "Agent '%s' no longer logged in.\n", agent->username);
1685
1686 agent_lock(agent);
1687 caller_bridge = agent->caller_bridge;
1688 agent->caller_bridge = NULL;
1689 agent_unlock(agent);
1690 if (caller_bridge) {
1691 ast_bridge_destroy(caller_bridge, 0);
1692 }
1693 return;
1694 }
1695
1696 /* Kick the agent out of the holding bridge to reset it. */
1700}
void ast_bridge_channel_leave_bridge_nolock(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).

References agent_bridge_channel_get_lock(), agent_lock, agent_unlock, ast_bridge_channel_leave_bridge_nolock(), ast_bridge_channel_unlock, ast_bridge_destroy(), AST_CAUSE_NORMAL_CLEARING, ast_debug, BRIDGE_CHANNEL_STATE_END, agent_pvt::caller_bridge, NULL, and agent_pvt::username.

Referenced by agent_request_exec(), caller_joined_bridge(), and caller_safety_timeout().

◆ caller_joined_bridge()

static int caller_joined_bridge ( struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
)
static

Definition at line 1827 of file app_agent_pool.c.

1828{
1829 struct agent_pvt *agent = hook_pvt;
1830 struct ast_bridge_channel *logged;
1831 int res;
1832
1833 logged = agent_bridge_channel_get_lock(agent);
1834 if (!logged) {
1835 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1836 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1837
1839 caller_abort_agent(agent);
1840 return -1;
1841 }
1842
1843 res = send_alert_to_agent(logged, agent->username);
1845 ao2_ref(logged, -1);
1846 if (res) {
1847 ast_verb(3, "Agent '%s': Failed to alert the agent.\n", agent->username);
1848 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
1849
1851 caller_abort_agent(agent);
1852 return -1;
1853 }
1854
1855 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_CONNECTED");
1856 ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
1857 return -1;
1858}
static int send_alert_to_agent(struct ast_bridge_channel *bridge_channel, const char *agent_id)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4296
@ AST_CONTROL_RINGING

References agent_bridge_channel_get_lock(), ao2_ref, ast_bridge_channel_leave_bridge(), ast_bridge_channel_unlock, AST_CONTROL_RINGING, ast_indicate(), ast_verb, BRIDGE_CHANNEL_STATE_END, caller_abort_agent(), ast_bridge_channel::chan, pbx_builtin_setvar_helper(), send_alert_to_agent(), and agent_pvt::username.

Referenced by agent_request_exec().

◆ caller_safety_timeout()

static int caller_safety_timeout ( struct ast_bridge_channel bridge_channel,
void *  hook_pvt 
)
static

Definition at line 1702 of file app_agent_pool.c.

1703{
1704 struct agent_pvt *agent = hook_pvt;
1705
1706 if (agent->state == AGENT_STATE_CALL_PRESENT) {
1707 ast_log(LOG_WARNING, "Agent '%s' process did not respond. Safety timeout.\n",
1708 agent->username);
1709 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
1710
1712 caller_abort_agent(agent);
1713 }
1714
1715 return -1;
1716}

References AGENT_STATE_CALL_PRESENT, ast_bridge_channel_leave_bridge(), ast_log, BRIDGE_CHANNEL_STATE_END, caller_abort_agent(), ast_bridge_channel::chan, LOG_WARNING, pbx_builtin_setvar_helper(), agent_pvt::state, and agent_pvt::username.

Referenced by agent_request_exec().

◆ clear_agent_status()

static void clear_agent_status ( struct ast_bridge_channel bridge_channel,
const void *  payload,
size_t  payload_size 
)
static

Definition at line 1007 of file app_agent_pool.c.

1008{
1009 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", NULL);
1010}

References ast_channel::bridge_channel, ast_bridge_channel::chan, NULL, and pbx_builtin_setvar_helper().

Referenced by agent_connect_caller().

◆ complete_agent()

static char * complete_agent ( const char *  word,
int  state 
)
static

Definition at line 2255 of file app_agent_pool.c.

2256{
2257 char *ret;
2258 struct agent_pvt *agent;
2259 struct agent_complete search = {
2260 .state = state,
2261 };
2262
2264 complete_agent_search, (char *) word, &search);
2265 if (!agent) {
2266 return NULL;
2267 }
2268 ret = ast_strdup(agent->username);
2269 ao2_ref(agent, -1);
2270 return ret;
2271}
static int complete_agent_search(void *obj, void *arg, void *data, int flags)
#define ao2_callback_data(container, flags, cb_fn, arg, data)
Definition: astobj2.h:1723
enum cc_state state
Definition: ccss.c:393
short word

References agents, ao2_callback_data, ao2_ref, ast_strdup, ast_strlen_zero(), complete_agent_search(), NULL, OBJ_PARTIAL_KEY, agent_complete::state, state, and agent_pvt::username.

Referenced by agent_handle_show_specific().

◆ complete_agent_logoff()

static char * complete_agent_logoff ( const char *  word,
int  state 
)
static

Definition at line 2287 of file app_agent_pool.c.

2288{
2289 char *ret;
2290 struct agent_pvt *agent;
2291 struct agent_complete search = {
2292 .state = state,
2293 };
2294
2296 complete_agent_logoff_search, (char *) word, &search);
2297 if (!agent) {
2298 return NULL;
2299 }
2300 ret = ast_strdup(agent->username);
2301 ao2_ref(agent, -1);
2302 return ret;
2303}
static int complete_agent_logoff_search(void *obj, void *arg, void *data, int flags)

References agents, ao2_callback_data, ao2_ref, ast_strdup, ast_strlen_zero(), complete_agent_logoff_search(), NULL, OBJ_PARTIAL_KEY, agent_complete::state, state, and agent_pvt::username.

Referenced by agent_handle_logoff_cmd().

◆ complete_agent_logoff_search()

static int complete_agent_logoff_search ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Definition at line 2273 of file app_agent_pool.c.

2274{
2275 struct agent_pvt *agent = obj;
2276 struct agent_complete *search = data;
2277
2278 if (!agent->logged) {
2279 return 0;
2280 }
2281 if (++search->which > search->state) {
2282 return CMP_MATCH;
2283 }
2284 return 0;
2285}

References CMP_MATCH, agent_pvt::logged, agent_complete::state, and agent_complete::which.

Referenced by complete_agent_logoff().

◆ complete_agent_search()

static int complete_agent_search ( void *  obj,
void *  arg,
void *  data,
int  flags 
)
static

Definition at line 2245 of file app_agent_pool.c.

2246{
2247 struct agent_complete *search = data;
2248
2249 if (++search->which > search->state) {
2250 return CMP_MATCH;
2251 }
2252 return 0;
2253}

References CMP_MATCH, agent_complete::state, and agent_complete::which.

Referenced by complete_agent().

◆ CONFIG_INFO_STANDARD()

CONFIG_INFO_STANDARD ( cfg_info  ,
cfg_handle  ,
agents_cfg_alloc  ,
files = ACO_FILES(&agents_conf),
post_apply_config = agents_post_apply_config 
)

◆ destroy_config()

static void destroy_config ( void  )
static

Definition at line 537 of file app_agent_pool.c.

538{
540 aco_info_destroy(&cfg_info);
541}
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.

References aco_info_destroy(), ao2_global_obj_release, and cfg_handle.

Referenced by unload_module().

◆ load_config()

static int load_config ( void  )
static

Definition at line 543 of file app_agent_pool.c.

544{
545 if (aco_info_init(&cfg_info)) {
546 return -1;
547 }
548
549 /* Agent options */
550 aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ack_call));
551 aco_option_register(&cfg_info, "acceptdtmf", ACO_EXACT, agent_types, "#", OPT_STRINGFIELD_T, 1, STRFLDSET(struct agent_cfg, dtmf_accept));
552 aco_option_register(&cfg_info, "autologoff", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, auto_logoff));
553 aco_option_register(&cfg_info, "wrapuptime", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, wrapup_time));
554 aco_option_register(&cfg_info, "musiconhold", ACO_EXACT, agent_types, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, moh));
555 aco_option_register(&cfg_info, "recordagentcalls", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, record_agent_calls));
556 aco_option_register(&cfg_info, "custom_beep", ACO_EXACT, agent_types, "beep", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, beep_sound));
557 aco_option_register(&cfg_info, "fullname", ACO_EXACT, agent_types, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, full_name));
558
559 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
560 return -1;
561 }
562
563 return 0;
564}
static struct aco_type * agent_types[]
@ ACO_EXACT
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.

References ACO_EXACT, aco_info_init(), aco_option_register, aco_process_config(), ACO_PROCESS_ERROR, agent_types, FLDSET, NULL, OPT_BOOL_T, OPT_STRINGFIELD_T, OPT_UINT_T, and STRFLDSET.

Referenced by load_module().

◆ load_module()

static int load_module ( void  )
static

Definition at line 2634 of file app_agent_pool.c.

2635{
2636 int res = 0;
2637
2640 if (!agents) {
2642 }
2643
2644 /* Init agent holding bridge v_table. */
2646
2647 /* Setup to provide Agent:agent-id device state. */
2649
2650 /* CLI Commands */
2652
2653 /* Manager commands */
2656
2657 /* Dialplan Functions */
2659
2660 /* Dialplan applications */
2663
2664 if (res) {
2665 ast_log(LOG_ERROR, "Unable to register application. Not loading module.\n");
2666 unload_module();
2668 }
2669
2670 if (load_config()) {
2671 ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
2672 unload_module();
2674 }
2675
2677}
static int action_agents(struct mansession *s, const struct message *m)
static struct ast_custom_function agent_function
static int agent_pvt_sort_cmp(const void *obj_left, const void *obj_right, int flags)
static const char app_agent_login[]
static int agent_request_exec(struct ast_channel *chan, const char *data)
Dialplan AgentRequest application to locate an agent to talk with.
static enum ast_device_state agent_pvt_devstate_get(const char *agent_id)
static int action_agent_logoff(struct mansession *s, const struct message *m)
static void bridge_init_agent_hold(void)
static struct ast_cli_entry cli_agents[]
static const char app_agent_request[]
static int unload_module(void)
static int agent_pvt_cmp(void *obj, void *arg, int flags)
static int agent_login_exec(struct ast_channel *chan, const char *data)
Dialplan AgentLogin application to log in an agent.
static int load_config(void)
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition: astobj2.h:1211
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
Definition: devicestate.c:391
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
#define EVENT_FLAG_AGENT
Definition: manager.h:80
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
#define ARRAY_LEN(a)
Definition: utils.h:666

References action_agent_logoff(), action_agents(), agent_function, agent_login_exec(), agent_pvt_cmp(), agent_pvt_devstate_get(), agent_pvt_sort_cmp(), agent_request_exec(), agents, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_container_alloc_rbtree, app_agent_login, app_agent_request, ARRAY_LEN, ast_cli_register_multiple, ast_custom_function_register, ast_devstate_prov_add(), ast_log, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, bridge_init_agent_hold(), cli_agents, EVENT_FLAG_AGENT, load_config(), LOG_ERROR, and unload_module().

◆ reload()

static int reload ( void  )
static

Definition at line 2679 of file app_agent_pool.c.

2680{
2681 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2682 /* Just keep the config we already have in place. */
2683 return -1;
2684 }
2685 return 0;
2686}

References aco_process_config(), and ACO_PROCESS_ERROR.

◆ send_agent_login()

static void send_agent_login ( struct ast_channel chan,
const char *  agent 
)
static

Definition at line 1423 of file app_agent_pool.c.

1424{
1425 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1426
1427 ast_assert(agent != NULL);
1428
1429 blob = ast_json_pack("{s: s}",
1430 "agent", agent);
1431 if (!blob) {
1432 return;
1433 }
1434
1436}
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
Abstract JSON element (object, array, string, int, ...).

References ast_assert, ast_channel_agent_login_type(), ast_channel_publish_blob(), ast_json_pack(), ast_json_unref(), NULL, and RAII_VAR.

Referenced by agent_login_exec().

◆ send_agent_logoff()

static void send_agent_logoff ( struct ast_channel chan,
const char *  agent,
long  logintime 
)
static

Definition at line 1438 of file app_agent_pool.c.

1439{
1440 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1441
1442 ast_assert(agent != NULL);
1443
1444 blob = ast_json_pack("{s: s, s: I}",
1445 "agent", agent,
1446 "logintime", (ast_json_int_t)logintime);
1447 if (!blob) {
1448 return;
1449 }
1450
1452}
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87

References ast_assert, ast_channel_agent_logoff_type(), ast_channel_publish_blob(), ast_json_pack(), ast_json_unref(), NULL, and RAII_VAR.

Referenced by agent_logout().

◆ send_alert_to_agent()

static int send_alert_to_agent ( struct ast_bridge_channel bridge_channel,
const char *  agent_id 
)
static

Definition at line 1792 of file app_agent_pool.c.

1793{
1794 return ast_bridge_channel_queue_callback(bridge_channel,
1795 AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, agent_alert, agent_id, strlen(agent_id) + 1);
1796}
static void agent_alert(struct ast_bridge_channel *bridge_channel, const void *payload, size_t payload_size)
@ AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA
int ast_bridge_channel_queue_callback(struct ast_bridge_channel *bridge_channel, enum ast_bridge_channel_custom_callback_option flags, ast_bridge_custom_callback_fn callback, const void *payload, size_t payload_size)
Queue a bridge action custom callback frame onto the bridge channel.

References agent_alert(), AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, and ast_bridge_channel_queue_callback().

Referenced by caller_joined_bridge().

◆ send_colp_to_agent()

static int send_colp_to_agent ( struct ast_bridge_channel bridge_channel,
struct ast_party_connected_line connected 
)
static

Definition at line 1798 of file app_agent_pool.c.

1799{
1801 .id.name = 1,
1802 .id.number = 1,
1803 .id.subaddress = 1,
1804 };
1805 unsigned char data[1024]; /* This should be large enough */
1806 size_t datalen;
1807
1808 datalen = ast_connected_line_build_data(data, sizeof(data), connected, &update);
1809 if (datalen == (size_t) -1) {
1810 return 0;
1811 }
1812
1813 return ast_bridge_channel_queue_control_data(bridge_channel,
1814 AST_CONTROL_CONNECTED_LINE, data, datalen);
1815}
int ast_bridge_channel_queue_control_data(struct ast_bridge_channel *bridge_channel, enum ast_control_frame_type control, const void *data, size_t datalen)
Queue a control frame onto the bridge channel with data.
int ast_connected_line_build_data(unsigned char *data, size_t datalen, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Build the connected line information data frame.
Definition: channel.c:8719
static void update(int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, struct g726_state *state_ptr)
Definition: codec_g726.c:367
@ AST_CONTROL_CONNECTED_LINE
Indicate what information in ast_party_connected_line should be set.
Definition: channel.h:491

References ast_bridge_channel_queue_control_data(), ast_connected_line_build_data(), AST_CONTROL_CONNECTED_LINE, connected, and update().

Referenced by agent_request_exec().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2602 of file app_agent_pool.c.

2603{
2604 struct ast_bridge *holding;
2605
2606 /* Unregister dialplan applications */
2609
2610 /* Unregister dialplan functions */
2612
2613 /* Unregister manager command */
2614 ast_manager_unregister("Agents");
2615 ast_manager_unregister("AgentLogoff");
2616
2617 /* Unregister CLI commands */
2619
2620 ast_devstate_prov_del("Agent");
2621
2622 /* Destroy agent holding bridge. */
2623 holding = ao2_global_obj_replace(agent_holding, NULL);
2624 if (holding) {
2625 ast_bridge_destroy(holding, 0);
2626 }
2627
2630 agents = NULL;
2631 return 0;
2632}
static void destroy_config(void)
#define ao2_global_obj_replace(holder, obj)
Replace an ao2 object in the global holder.
Definition: astobj2.h:878
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
int ast_devstate_prov_del(const char *label)
Remove device state provider.
Definition: devicestate.c:418
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7606
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.

References agent_function, agents, ao2_cleanup, ao2_global_obj_replace, app_agent_login, app_agent_request, ARRAY_LEN, ast_bridge_destroy(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_prov_del(), ast_manager_unregister(), ast_unregister_application(), cli_agents, destroy_config(), and NULL.

Referenced by load_module().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Call center agent pool applications" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_DEVSTATE_PROVIDER, }
static

Definition at line 2694 of file app_agent_pool.c.

◆ agent_function

struct ast_custom_function agent_function
static
Initial value:
= {
.name = "AGENT",
}
static int agent_function_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)

Definition at line 2233 of file app_agent_pool.c.

Referenced by load_module(), and unload_module().

◆ agent_holding_lock

ast_mutex_t agent_holding_lock = { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP , NULL, {1, 0} }
static

Agent holding bridge deferred creation lock.

Definition at line 995 of file app_agent_pool.c.

Referenced by bridge_agent_hold_deferred_create().

◆ agent_login_opts

const struct ast_app_option agent_login_opts[128] = { [ 's' ] = { .flag = OPT_SILENT }, }
static

Definition at line 2079 of file app_agent_pool.c.

Referenced by agent_login_exec().

◆ agent_type

struct aco_type agent_type
static

Definition at line 465 of file app_agent_pool.c.

Referenced by ast_channel_get_cc_agent_type().

◆ agent_types

struct aco_type* agent_types[] = ACO_TYPES(&agent_type)
static

Definition at line 475 of file app_agent_pool.c.

Referenced by load_config().

◆ agents

struct ao2_container* agents
static

◆ agents_conf

struct aco_file agents_conf
static
Initial value:
= {
.filename = "agents.conf",
}
static struct aco_type agent_type
static struct aco_type general_type
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.

Definition at line 485 of file app_agent_pool.c.

◆ app_agent_login

const char app_agent_login[] = "AgentLogin"
static

Definition at line 350 of file app_agent_pool.c.

Referenced by load_module(), and unload_module().

◆ app_agent_request

const char app_agent_request[] = "AgentRequest"
static

Definition at line 351 of file app_agent_pool.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2694 of file app_agent_pool.c.

◆ bridge_agent_hold_v_table

struct ast_bridge_methods bridge_agent_hold_v_table
static

Definition at line 1378 of file app_agent_pool.c.

Referenced by bridge_agent_hold_new(), and bridge_init_agent_hold().

◆ cli_agents

struct ast_cli_entry cli_agents[]
static

Definition at line 2498 of file app_agent_pool.c.

Referenced by load_module(), and unload_module().

◆ general_type

struct aco_type general_type
static

Definition at line 478 of file app_agent_pool.c.