Asterisk - The Open Source Telephony Project GIT-master-43bf8a4
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 701 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 712 of file app_agent_pool.c.

◆ AST_MAX_BUF

#define AST_MAX_BUF   256

Definition at line 387 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 390 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 393 of file app_agent_pool.c.

Enumeration Type Documentation

◆ AGENT_LOGIN_OPT_FLAGS

Enumerator
OPT_SILENT 

Definition at line 2119 of file app_agent_pool.c.

2119 {
2120 OPT_SILENT = (1 << 0),
2121};
@ 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 631 of file app_agent_pool.c.

631 {
632 AGENT_FLAG_ACK_CALL = (1 << 0),
633 AGENT_FLAG_DTMF_ACCEPT = (1 << 1),
634 AGENT_FLAG_AUTO_LOGOFF = (1 << 2),
635 AGENT_FLAG_WRAPUP_TIME = (1 << 3),
636};
@ 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 611 of file app_agent_pool.c.

611 {
612 /*! The agent is defined but an agent is not present. */
614 /*! Forced initial login wait to allow any local channel optimizations to happen. */
616 /*! The agent is ready for a call. */
618 /*! The agent has a call waiting to connect. */
620 /*! The agent needs to ack the call. */
622 /*! The agent is connected with a call. */
624 /*! The agent is resting between calls. */
626 /*! The agent is being kicked out. */
628};
@ 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 2739 of file app_agent_pool.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2739 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 702 of file app_agent_pool.c.

703{
704 __ao2_lock(agent, AO2_LOCK_REQ_MUTEX, file, function, line, var);
705}
#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 713 of file app_agent_pool.c.

714{
715 __ao2_unlock(agent, file, function, line, var);
716}
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 2628 of file app_agent_pool.c.

2629{
2630 const char *agent = astman_get_header(m, "Agent");
2631 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
2632
2633 if (ast_strlen_zero(agent)) {
2634 astman_send_error(s, m, "No agent specified");
2635 return 0;
2636 }
2637
2638 if (!agent_logoff_request(agent, ast_true(soft_s))) {
2639 astman_send_ack(s, m, "Agent logged out");
2640 } else {
2641 astman_send_error(s, m, "No such agent");
2642 }
2643
2644 return 0;
2645}
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:1982
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2014
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643
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 2550 of file app_agent_pool.c.

2551{
2552 const char *id = astman_get_header(m, "ActionID");
2553 char id_text[AST_MAX_BUF];
2554 struct ao2_iterator iter;
2555 struct agent_pvt *agent;
2556 struct ast_str *out = ast_str_alloca(4096);
2557 int num_agents = 0;
2558
2559 if (!ast_strlen_zero(id)) {
2560 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
2561 } else {
2562 id_text[0] = '\0';
2563 }
2564 astman_send_listack(s, m, "Agents will follow", "start");
2565
2566 iter = ao2_iterator_init(agents, 0);
2567 for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2568 struct ast_channel *logged;
2569
2570 agent_lock(agent);
2571 logged = agent_lock_logged(agent);
2572
2573 /*
2574 * Status Values:
2575 * AGENT_LOGGEDOFF - Agent isn't logged in
2576 * AGENT_IDLE - Agent is logged in, and waiting for call
2577 * AGENT_ONCALL - Agent is logged in, and on a call
2578 * AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this.
2579 */
2580 ast_str_set(&out, 0, "Agent: %s\r\n", agent->username);
2581 ast_str_append(&out, 0, "Name: %s\r\n", agent->cfg->full_name);
2582
2583 if (logged) {
2584 const char *talking_to_chan;
2585 struct ast_str *logged_headers;
2586 RAII_VAR(struct ast_channel_snapshot *, logged_snapshot, ast_channel_snapshot_create(logged), ao2_cleanup);
2587
2588 if (!logged_snapshot
2589 || !(logged_headers =
2590 ast_manager_build_channel_state_string(logged_snapshot))) {
2591 ast_channel_unlock(logged);
2592 ast_channel_unref(logged);
2593 agent_unlock(agent);
2594 continue;
2595 }
2596
2597 talking_to_chan = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2598 if (!ast_strlen_zero(talking_to_chan)) {
2599 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_ONCALL");
2600 ast_str_append(&out, 0, "TalkingToChan: %s\r\n", talking_to_chan);
2601 ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2602 } else {
2603 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_IDLE");
2604 }
2605 ast_str_append(&out, 0, "LoggedInTime: %ld\r\n", (long) agent->login_start);
2606 ast_str_append(&out, 0, "%s", ast_str_buffer(logged_headers));
2607 ast_channel_unlock(logged);
2608 ast_channel_unref(logged);
2609 ast_free(logged_headers);
2610 } else {
2611 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_LOGGEDOFF");
2612 }
2613
2614 agent_unlock(agent);
2615
2616 astman_append(s, "Event: Agents\r\n"
2617 "%s%s\r\n",
2618 ast_str_buffer(out), id_text);
2619 ++num_agents;
2620 }
2621 ao2_iterator_destroy(&iter);
2622
2623 astman_send_list_complete_start(s, m, "AgentsComplete", num_agents);
2625 return 0;
2626}
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:3008
#define ast_channel_unlock(chan)
Definition: channel.h:2973
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:2024
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:2060
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2068
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1903
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:965

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 1643 of file app_agent_pool.c.

1644{
1645 struct agent_pvt *agent;
1646
1647 agent = ao2_find(agents, chan, 0);
1648 if (!agent) {
1649 return;
1650 }
1651
1652 ast_debug(1, "Agent %s: New agent channel %s.\n",
1653 agent->username, ast_channel_name(chan));
1654 agent_run(agent, chan);
1655 ao2_ref(agent, -1);
1656}
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 1658 of file app_agent_pool.c.

1659{
1660 struct ast_channel *chan = data;
1661 struct agent_pvt *agent;
1662
1663 agent = ao2_find(agents, chan, 0);
1664 if (!agent) {
1665 return;
1666 }
1667 ast_log(LOG_WARNING, "Agent %s: Forced logout. Lost control of %s because: %s\n",
1668 agent->username, ast_channel_name(chan),
1670 agent_lock(agent);
1671 agent_logout(agent);
1672 ao2_ref(agent, -1);
1673}
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 1763 of file app_agent_pool.c.

1764{
1765 const char *agent_id = payload;
1766 const char *playfile;
1767 const char *dtmf_accept;
1768 struct agent_pvt *agent;
1769 int digit;
1770 char dtmf[2];
1771
1772 agent = ao2_find(agents, agent_id, OBJ_KEY);
1773 if (!agent) {
1774 ast_debug(1, "Agent '%s' does not exist. Where did it go?\n", agent_id);
1775 return;
1776 }
1777
1778 /* Change holding bridge participant role's idle mode to silence */
1779 ast_bridge_channel_lock_bridge(bridge_channel);
1780 ast_bridge_channel_clear_roles(bridge_channel);
1781 ast_channel_set_bridge_role_option(bridge_channel->chan, "holding_participant", "idle_mode", "silence");
1782 ast_bridge_channel_establish_roles(bridge_channel);
1783 ast_bridge_unlock(bridge_channel->bridge);
1784
1785 agent_lock(agent);
1786 playfile = ast_strdupa(agent->cfg->beep_sound);
1787
1788 /* Determine which DTMF digits interrupt the alerting signal. */
1790 ? agent->override_ack_call : agent->cfg->ack_call) {
1791 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1792 ? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
1793
1794 /* Only the first digit of the ack will stop playback. */
1795 dtmf[0] = *dtmf_accept;
1796 dtmf[1] = '\0';
1797 dtmf_accept = dtmf;
1798 } else {
1799 dtmf_accept = NULL;
1800 }
1801 agent_unlock(agent);
1802
1803 /* Alert the agent. */
1804 digit = ast_stream_and_wait(bridge_channel->chan, playfile,
1805 ast_strlen_zero(dtmf_accept) ? AST_DIGIT_ANY : dtmf_accept);
1806 ast_stopstream(bridge_channel->chan);
1807
1808 agent_lock(agent);
1809 switch (agent->state) {
1811 if (!ast_strlen_zero(dtmf_accept)) {
1813 agent->ack_time = ast_tvnow();
1814
1815 if (0 < digit) {
1816 /* Playback was interrupted by a digit. */
1817 agent_unlock(agent);
1818 ao2_ref(agent, -1);
1819 ast_bridge_channel_feature_digit(bridge_channel, digit);
1820 return;
1821 }
1822 break;
1823 }
1824
1825 /* Connect to caller now. */
1826 ast_debug(1, "Agent %s: Immediately connecting to call.\n", agent->username);
1827 agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
1828 ao2_ref(agent, -1);
1829 return;
1830 default:
1831 break;
1832 }
1833 agent_unlock(agent);
1834 ao2_ref(agent, -1);
1835}
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:485
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:1886
#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 1685 of file app_agent_pool.c.

1686{
1687 struct ast_channel *logged;
1688 struct ast_bridge_channel *bc;
1689
1690 for (;;) {
1691 agent_lock(agent);
1692 logged = agent->logged;
1693 if (!logged) {
1694 agent_unlock(agent);
1695 return NULL;
1696 }
1697 ast_channel_ref(logged);
1698 agent_unlock(agent);
1699
1700 ast_channel_lock(logged);
1702 ast_channel_unlock(logged);
1703 ast_channel_unref(logged);
1704 if (!bc) {
1705 if (agent->logged != logged) {
1706 continue;
1707 }
1708 return NULL;
1709 }
1710
1712 if (bc->chan != logged || agent->logged != logged) {
1714 ao2_ref(bc, -1);
1715 continue;
1716 }
1717 return bc;
1718 }
1719}
#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:2972
#define ast_channel_ref(c)
Increase channel reference count.
Definition: channel.h:2997
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:10583
#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 485 of file app_agent_pool.c.

486{
487 struct agent_cfg *cfg;
488
489 cfg = ao2_alloc_options(sizeof(*cfg), agent_cfg_destructor,
491 if (!cfg || ast_string_field_init(cfg, 64)) {
492 ao2_cleanup(cfg);
493 return NULL;
494 }
496 return cfg;
497}
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 478 of file app_agent_pool.c.

479{
480 struct agent_cfg *doomed = vdoomed;
481
483}
#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 499 of file app_agent_pool.c.

500{
501 return ao2_find(agents, username, OBJ_KEY);
502}

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 456 of file app_agent_pool.c.

457{
458 const struct agent_cfg *cfg_left = obj_left;
459 const struct agent_cfg *cfg_right = obj_right;
460 const char *right_key = obj_right;
461 int cmp;
462
463 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
464 default:
465 case OBJ_POINTER:
466 right_key = cfg_right->username;
467 /* Fall through */
468 case OBJ_KEY:
469 cmp = strcmp(cfg_left->username, right_key);
470 break;
471 case OBJ_PARTIAL_KEY:
472 cmp = strncmp(cfg_left->username, right_key, strlen(right_key));
473 break;
474 }
475 return cmp;
476}
#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 1067 of file app_agent_pool.c.

1068{
1069 struct ast_bridge *caller_bridge;
1070 int record_agent_calls;
1071 int res;
1072
1073 record_agent_calls = agent->cfg->record_agent_calls;
1074 caller_bridge = agent->caller_bridge;
1075 agent->caller_bridge = NULL;
1076 agent->state = AGENT_STATE_ON_CALL;
1077 time(&agent->call_start);
1078 agent_unlock(agent);
1079
1080 if (!caller_bridge) {
1081 /* Reset agent. */
1084 return;
1085 }
1086 res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan,
1087 NULL, 0);
1088 if (res) {
1089 /* Reset agent. */
1090 ast_bridge_destroy(caller_bridge, 0);
1093 return;
1094 }
1097 if (res) {
1098 /* Reset agent. */
1099 ast_bridge_destroy(caller_bridge, 0);
1100 return;
1101 }
1102
1103 if (record_agent_calls) {
1105 .start_stop = AUTO_MONITOR_START,
1106 };
1107
1108 /*
1109 * The agent is in the new bridge so we can invoke the
1110 * mixmonitor hook to only start recording.
1111 */
1113 }
1114
1115 ao2_t_ref(caller_bridge, -1, "Agent successfully in caller_bridge");
1116}
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:1009
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:2529
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:3159
@ 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:353
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 793 of file app_agent_pool.c.

794{
796}
@ 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:513
@ 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 2207 of file app_agent_pool.c.

2208{
2209 char *parse;
2210 struct agent_pvt *agent;
2211 struct ast_channel *logged;
2213 AST_APP_ARG(agentid);
2215 );
2216
2217 buf[0] = '\0';
2218
2219 parse = ast_strdupa(data ?: "");
2220 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2221
2222 if (ast_strlen_zero(args.agentid)) {
2223 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2224 return -1;
2225 }
2226 if (!args.item) {
2227 args.item = "status";
2228 }
2229
2230 agent = ao2_find(agents, args.agentid, OBJ_KEY);
2231 if (!agent) {
2232 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2233 return -1;
2234 }
2235
2236 agent_lock(agent);
2237 if (!strcasecmp(args.item, "status")) {
2238 const char *status;
2239
2240 if (agent->logged) {
2241 status = "LOGGEDIN";
2242 } else {
2243 status = "LOGGEDOUT";
2244 }
2246 } else if (!strcasecmp(args.item, "name")) {
2247 ast_copy_string(buf, agent->cfg->full_name, len);
2248 } else if (!strcasecmp(args.item, "mohclass")) {
2249 ast_copy_string(buf, agent->cfg->moh, len);
2250 } else if (!strcasecmp(args.item, "channel")) {
2251 logged = agent_lock_logged(agent);
2252 if (logged) {
2253 char *pos;
2254
2256 ast_channel_unlock(logged);
2257 ast_channel_unref(logged);
2258
2259 pos = strrchr(buf, '-');
2260 if (pos) {
2261 *pos = '\0';
2262 }
2263 }
2264 } else if (!strcasecmp(args.item, "fullchannel")) {
2265 logged = agent_lock_logged(agent);
2266 if (logged) {
2268 ast_channel_unlock(logged);
2269 ast_channel_unref(logged);
2270 }
2271 }
2272 agent_unlock(agent);
2273 ao2_ref(agent, -1);
2274
2275 return 0;
2276}
jack_status_t status
Definition: app_jack.c:149
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 2508 of file app_agent_pool.c.

2509{
2510 switch (cmd) {
2511 case CLI_INIT:
2512 e->command = "agent logoff";
2513 e->usage =
2514 "Usage: agent logoff <agent-id> [soft]\n"
2515 " Sets an agent as no longer logged in.\n"
2516 " If 'soft' is specified, do not hangup existing calls.\n";
2517 return NULL;
2518 case CLI_GENERATE:
2519 if (a->pos == 2) {
2520 return complete_agent_logoff(a->word, a->n);
2521 } else if (a->pos == 3 && a->n == 0
2522 && (ast_strlen_zero(a->word)
2523 || !strncasecmp("soft", a->word, strlen(a->word)))) {
2524 return ast_strdup("soft");
2525 }
2526 return NULL;
2527 }
2528
2529 if (a->argc < 3 || 4 < a->argc) {
2530 return CLI_SHOWUSAGE;
2531 }
2532 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) {
2533 return CLI_SHOWUSAGE;
2534 }
2535
2536 if (!agent_logoff_request(a->argv[2], a->argc == 4)) {
2537 ast_cli(a->fd, "Logging out %s\n", a->argv[2]);
2538 }
2539
2540 return CLI_SUCCESS;
2541}
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 2427 of file app_agent_pool.c.

2428{
2429 switch (cmd) {
2430 case CLI_INIT:
2431 e->command = "agent show all";
2432 e->usage =
2433 "Usage: agent show all\n"
2434 " Provides summary information for all agents.\n";
2435 return NULL;
2436 case CLI_GENERATE:
2437 return NULL;
2438 }
2439
2440 if (a->argc != 3) {
2441 return CLI_SHOWUSAGE;
2442 }
2443
2445
2446 return CLI_SUCCESS;
2447}
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 2405 of file app_agent_pool.c.

2406{
2407 switch (cmd) {
2408 case CLI_INIT:
2409 e->command = "agent show online";
2410 e->usage =
2411 "Usage: agent show online\n"
2412 " Provides summary information for logged in agents.\n";
2413 return NULL;
2414 case CLI_GENERATE:
2415 return NULL;
2416 }
2417
2418 if (a->argc != 3) {
2419 return CLI_SHOWUSAGE;
2420 }
2421
2423
2424 return CLI_SUCCESS;
2425}

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 2449 of file app_agent_pool.c.

2450{
2451 struct agent_pvt *agent;
2452 struct ast_channel *logged;
2453 struct ast_str *out = ast_str_alloca(4096);
2454
2455 switch (cmd) {
2456 case CLI_INIT:
2457 e->command = "agent show";
2458 e->usage =
2459 "Usage: agent show <agent-id>\n"
2460 " Show information about the <agent-id> agent\n";
2461 return NULL;
2462 case CLI_GENERATE:
2463 if (a->pos == 2) {
2464 return complete_agent(a->word, a->n);
2465 }
2466 return NULL;
2467 }
2468
2469 if (a->argc != 3) {
2470 return CLI_SHOWUSAGE;
2471 }
2472
2473 agent = ao2_find(agents, a->argv[2], OBJ_KEY);
2474 if (!agent) {
2475 ast_cli(a->fd, "Agent '%s' not found\n", a->argv[2]);
2476 return CLI_SUCCESS;
2477 }
2478
2479 agent_lock(agent);
2480 logged = agent_lock_logged(agent);
2481 ast_str_set(&out, 0, "Id: %s\n", agent->username);
2482 ast_str_append(&out, 0, "Name: %s\n", agent->cfg->full_name);
2483 ast_str_append(&out, 0, "Beep: %s\n", agent->cfg->beep_sound);
2484 ast_str_append(&out, 0, "MOH: %s\n", agent->cfg->moh);
2485 ast_str_append(&out, 0, "RecordCalls: %s\n", AST_CLI_YESNO(agent->cfg->record_agent_calls));
2486 ast_str_append(&out, 0, "State: %s\n", ast_devstate_str(agent->devstate));
2487 if (logged) {
2488 const char *talking_with;
2489
2490 ast_str_append(&out, 0, "LoggedInChannel: %s\n", ast_channel_name(logged));
2491 ast_str_append(&out, 0, "LoggedInTime: %ld\n", (long) agent->login_start);
2492 talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2493 if (!ast_strlen_zero(talking_with)) {
2494 ast_str_append(&out, 0, "TalkingWith: %s\n", talking_with);
2495 ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2496 }
2497 ast_channel_unlock(logged);
2498 ast_channel_unref(logged);
2499 }
2500 agent_unlock(agent);
2501 ao2_ref(agent, -1);
2502
2503 ast_cli(a->fd, "%s", ast_str_buffer(out));
2504
2505 return CLI_SUCCESS;
2506}
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:258
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 729 of file app_agent_pool.c.

730{
731 struct ast_channel *logged;
732
733 for (;;) {
734 if (!agent->logged) { /* No owner. Nothing to do. */
735 return NULL;
736 }
737
738 /* If we don't ref the logged, it could be killed when we unlock the agent. */
739 logged = ast_channel_ref(agent->logged);
740
741 /* Locking logged requires us to lock channel, then agent. */
742 agent_unlock(agent);
743 ast_channel_lock(logged);
744 agent_lock(agent);
745
746 /* Check if logged changed during agent unlock period */
747 if (logged != agent->logged) {
748 /* Channel changed. Unref and do another pass. */
749 ast_channel_unlock(logged);
750 ast_channel_unref(logged);
751 } else {
752 /* Channel stayed the same. Return it. */
753 return logged;
754 }
755 }
756}

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 2063 of file app_agent_pool.c.

2064{
2065 struct ast_flags opts = { 0 };
2067 unsigned int override_ack_call = 0;
2068 unsigned int override_auto_logoff = 0;
2069 unsigned int override_wrapup_time = 0;
2070 const char *override_dtmf_accept = NULL;
2071 const char *var;
2072
2074
2075 /* Get config values from channel. */
2076 ast_channel_lock(chan);
2078
2079 var = pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2080 if (!ast_strlen_zero(var)) {
2081 override_ack_call = ast_true(var) ? 1 : 0;
2083 }
2084
2085 var = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2086 if (!ast_strlen_zero(var)) {
2087 override_dtmf_accept = ast_strdupa(var);
2089 }
2090
2091 var = pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2092 if (!ast_strlen_zero(var)) {
2093 if (sscanf(var, "%u", &override_auto_logoff) == 1) {
2095 }
2096 }
2097
2098 var = pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2099 if (!ast_strlen_zero(var)) {
2100 if (sscanf(var, "%u", &override_wrapup_time) == 1) {
2102 }
2103 }
2104 ast_channel_unlock(chan);
2105
2106 /* Set config values on agent. */
2107 agent_lock(agent);
2109 agent->waiting_colp = connected;
2110
2111 ast_string_field_set(agent, override_dtmf_accept, override_dtmf_accept);
2112 ast_copy_flags(agent, &opts, AST_FLAGS_ALL);
2113 agent->override_auto_logoff = override_auto_logoff;
2114 agent->override_wrapup_time = override_wrapup_time;
2115 agent->override_ack_call = override_ack_call;
2116 agent_unlock(agent);
2117}
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2039
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:1998
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:1989
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:217
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:214

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 2135 of file app_agent_pool.c.

2136{
2137 char *parse;
2138 struct ast_flags opts;
2140 AST_APP_ARG(agent_id);
2142 AST_APP_ARG(other); /* Any remaining unused arguments */
2143 );
2144
2145 RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
2146
2148 return -1;
2149 }
2150
2151 if (ast_channel_state(chan) != AST_STATE_UP && ast_answer(chan)) {
2152 return -1;
2153 }
2154
2155 parse = ast_strdupa(data);
2157
2158 if (ast_strlen_zero(args.agent_id)) {
2159 ast_log(LOG_WARNING, "AgentLogin requires an AgentId\n");
2160 return -1;
2161 }
2162
2163 if (ast_app_parse_options(agent_login_opts, &opts, NULL, args.options)) {
2164 /* General invalid option syntax. */
2165 return -1;
2166 }
2167
2168 /* Find the agent. */
2169 agent = ao2_find(agents, args.agent_id, OBJ_KEY);
2170 if (!agent) {
2171 ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
2172 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
2173 return 0;
2174 }
2175
2176 /* Has someone already logged in as this agent already? */
2177 agent_lock(agent);
2178 if (agent->logged) {
2179 agent_unlock(agent);
2180 ast_verb(3, "Agent '%s' already logged in.\n", agent->username);
2181 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ALREADY_LOGGED_IN");
2182 return 0;
2183 }
2184 agent->logged = ast_channel_ref(chan);
2185 agent->last_disconnect = ast_tvnow();
2186 time(&agent->login_start);
2187 agent->deferred_logoff = 0;
2188 agent_unlock(agent);
2189
2190 agent_login_channel_config(agent, chan);
2191
2192 if (!ast_test_flag(&opts, OPT_SILENT)) {
2193 ast_stream_and_wait(chan, "agent-loginok", AST_DIGIT_NONE);
2194 }
2195
2196 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", agent->username,
2199 ast_channel_lock(chan);
2200 send_agent_login(chan, agent->username);
2201 ast_channel_unlock(chan);
2202
2203 agent_run(agent, chan);
2204 return -1;
2205}
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:2774
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 1012 of file app_agent_pool.c.

1013{
1014 struct ast_channel *logged;
1015 RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, agent_id, OBJ_KEY), ao2_cleanup);
1016
1017 if (!agent) {
1018 return -1;
1019 }
1020
1021 agent_lock(agent);
1022 logged = agent_lock_logged(agent);
1023 if (logged) {
1024 if (soft) {
1025 agent->deferred_logoff = 1;
1026 } else {
1028 }
1029 ast_channel_unlock(logged);
1030 ast_channel_unref(logged);
1031 }
1032 agent_unlock(agent);
1033 return 0;
1034}
@ AST_SOFTHANGUP_EXPLICIT
Definition: channel.h:1168
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
Definition: channel.c:2440

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 1508 of file app_agent_pool.c.

1509{
1510 struct ast_channel *logged;
1511 struct ast_bridge *caller_bridge;
1512 long time_logged_in;
1513
1514 time_logged_in = time(NULL) - agent->login_start;
1515 logged = agent->logged;
1516 agent->logged = NULL;
1517 caller_bridge = agent->caller_bridge;
1518 agent->caller_bridge = NULL;
1522 agent_unlock(agent);
1524
1525 if (caller_bridge) {
1526 ast_bridge_destroy(caller_bridge, 0);
1527 }
1528
1529 ast_channel_lock(logged);
1530 send_agent_logoff(logged, agent->username, time_logged_in);
1531 ast_channel_unlock(logged);
1532 ast_verb(2, "Agent '%s' logged out. Logged in for %ld seconds.\n",
1533 agent->username, time_logged_in);
1534 ast_channel_unref(logged);
1535}
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 911 of file app_agent_pool.c.

912{
913 struct agent_pvt *agent = obj;
914
915 agent_lock(agent);
916 agent->the_mark = 1;
917 agent_unlock(agent);
918 return 0;
919}
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 889 of file app_agent_pool.c.

890{
891 const struct agent_pvt *agent = obj;
892 int cmp;
893
894 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
895 case OBJ_POINTER:
896 case OBJ_KEY:
897 case OBJ_PARTIAL_KEY:
898 cmp = CMP_MATCH;
899 break;
900 default:
901 if (agent->logged == arg) {
902 cmp = CMP_MATCH;
903 } else {
904 cmp = 0;
905 }
906 break;
907 }
908 return cmp;
909}
@ 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 798 of file app_agent_pool.c.

799{
800 struct agent_pvt *doomed = vdoomed;
801
802 /* Make sure device state reflects agent destruction. */
803 if (!ast_strlen_zero(doomed->username)) {
804 ast_debug(1, "Agent %s: Destroyed.\n", doomed->username);
806 }
807
809 if (doomed->caller_bridge) {
811 doomed->caller_bridge = NULL;
812 }
813 if (doomed->logged) {
814 doomed->logged = ast_channel_unref(doomed->logged);
815 }
816 ao2_cleanup(doomed->cfg);
817 doomed->cfg = NULL;
819}

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 771 of file app_agent_pool.c.

772{
773 enum ast_device_state dev_state = AST_DEVICE_INVALID;
774 struct agent_pvt *agent;
775
776 agent = ao2_find(agents, agent_id, OBJ_KEY);
777 if (agent) {
778 agent_lock(agent);
779 dev_state = agent->devstate;
780 agent_unlock(agent);
781 ao2_ref(agent, -1);
782 }
783 return dev_state;
784}
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 821 of file app_agent_pool.c.

822{
823 struct agent_pvt *agent;
824
825 agent = ao2_alloc(sizeof(*agent), agent_pvt_destructor);
826 if (!agent) {
827 return NULL;
828 }
829 if (ast_string_field_init(agent, 32)) {
830 ao2_ref(agent, -1);
831 return NULL;
832 }
835 ao2_ref(cfg, +1);
836 agent->cfg = cfg;
838 return agent;
839}
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 857 of file app_agent_pool.c.

858{
859 const struct agent_pvt *agent_left = obj_left;
860 const struct agent_pvt *agent_right = obj_right;
861 const char *right_key = obj_right;
862 int cmp;
863
864 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
865 default:
866 case OBJ_POINTER:
867 right_key = agent_right->username;
868 /* Fall through */
869 case OBJ_KEY:
870 cmp = strcmp(agent_left->username, right_key);
871 break;
872 case OBJ_PARTIAL_KEY:
873 cmp = strncmp(agent_left->username, right_key, strlen(right_key));
874 break;
875 }
876 return cmp;
877}

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 1914 of file app_agent_pool.c.

1915{
1916 struct ast_bridge *caller_bridge;
1917 struct ast_bridge_channel *logged;
1918 char *parse;
1919 int res;
1920 struct ast_bridge_features caller_features;
1923 AST_APP_ARG(agent_id);
1924 AST_APP_ARG(other); /* Any remaining unused arguments */
1925 );
1926
1927 RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1928
1930 return -1;
1931 }
1932
1933 parse = ast_strdupa(data);
1935
1936 if (ast_strlen_zero(args.agent_id)) {
1937 ast_log(LOG_WARNING, "AgentRequest requires an AgentId\n");
1938 return -1;
1939 }
1940
1941 /* Find the agent. */
1942 agent = ao2_find(agents, args.agent_id, OBJ_KEY);
1943 if (!agent) {
1944 ast_verb(3, "Agent '%s' does not exist.\n", args.agent_id);
1945 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "INVALID");
1946 return 0;
1947 }
1948
1949 if (ast_bridge_features_init(&caller_features)) {
1950 return -1;
1951 }
1952
1953 /* Add safety timeout hook. */
1954 ao2_ref(agent, +1);
1957 ao2_ref(agent, -1);
1958 ast_bridge_features_cleanup(&caller_features);
1959 return -1;
1960 }
1961
1962 /* Setup the alert agent on caller joining the bridge hook. */
1963 ao2_ref(agent, +1);
1964 if (ast_bridge_join_hook(&caller_features, caller_joined_bridge, agent,
1965 __ao2_cleanup, 0)) {
1966 ao2_ref(agent, -1);
1967 ast_bridge_features_cleanup(&caller_features);
1968 return -1;
1969 }
1970
1971 caller_bridge = ast_bridge_basic_new();
1972 if (!caller_bridge) {
1973 ast_bridge_features_cleanup(&caller_features);
1974 return -1;
1975 }
1976
1977 agent_lock(agent);
1978 switch (agent->state) {
1981 agent_unlock(agent);
1982 ast_bridge_destroy(caller_bridge, 0);
1983 ast_bridge_features_cleanup(&caller_features);
1984 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1985 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1986 return 0;
1988 ao2_ref(caller_bridge, +1);
1989 agent->caller_bridge = caller_bridge;
1990 agent->state = AGENT_STATE_CALL_PRESENT;
1991 agent->devstate = AST_DEVICE_INUSE;
1992 break;
1993 default:
1994 agent_unlock(agent);
1995 ast_bridge_destroy(caller_bridge, 0);
1996 ast_bridge_features_cleanup(&caller_features);
1997 ast_verb(3, "Agent '%s' is busy.\n", agent->username);
1998 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "BUSY");
1999 return 0;
2000 }
2001 agent_unlock(agent);
2002 agent_devstate_changed(agent->username);
2003
2004 /* Get COLP for agent. */
2006 ast_channel_lock(chan);
2008 ast_channel_unlock(chan);
2009
2010 logged = agent_bridge_channel_get_lock(agent);
2011 if (!logged) {
2013 caller_abort_agent(agent);
2014 ast_bridge_destroy(caller_bridge, 0);
2015 ast_bridge_features_cleanup(&caller_features);
2016 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
2017 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "NOT_LOGGED_IN");
2018 return 0;
2019 }
2020
2021 send_colp_to_agent(logged, &connected);
2023 ao2_ref(logged, -1);
2025
2026 if (ast_bridge_join(caller_bridge, chan, NULL, &caller_features, NULL,
2028 caller_abort_agent(agent);
2029 ast_verb(3, "Agent '%s': Caller %s failed to join the bridge.\n",
2030 agent->username, ast_channel_name(chan));
2031 pbx_builtin_setvar_helper(chan, "AGENT_STATUS", "ERROR");
2032 }
2033 ast_bridge_features_cleanup(&caller_features);
2034
2035 /* Determine if we need to continue in the dialplan after the bridge. */
2036 ast_channel_lock(chan);
2038 /*
2039 * The bridge was broken for a hangup that isn't real.
2040 * Don't run the h extension, because the channel isn't
2041 * really hung up. This should really only happen with
2042 * AST_SOFTHANGUP_ASYNCGOTO.
2043 */
2044 res = 0;
2045 } else {
2046 res = ast_check_hangup(chan)
2048 || ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENT_STATUS"));
2049 }
2050 ast_channel_unlock(chan);
2051
2052 return res ? -1 : 0;
2053}
#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:1690
@ AST_BRIDGE_JOIN_PASS_REFERENCE
Definition: bridge.h:539
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:3689
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:3388
@ 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:3344
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
Definition: bridge.c:3722
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
@ AST_FLAG_ZOMBIE
Definition: channel.h:1007
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:444
@ 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:8294
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 1545 of file app_agent_pool.c.

1546{
1547 struct ast_bridge_features features;
1548
1549 if (ast_bridge_features_init(&features)) {
1551 goto agent_run_cleanup;
1552 }
1553 for (;;) {
1554 struct agents_cfg *cfgs;
1555 struct agent_cfg *cfg_new;
1556 struct agent_cfg *cfg_old;
1557 struct ast_bridge *holding;
1558 struct ast_bridge *caller_bridge;
1559
1561
1562 holding = ao2_global_obj_ref(agent_holding);
1563 if (!holding) {
1564 ast_debug(1, "Agent %s: Someone destroyed the agent holding bridge.\n",
1565 agent->username);
1566 break;
1567 }
1568
1569 /*
1570 * When the agent channel leaves the bridging system we usually
1571 * want to put the agent back into the holding bridge for the
1572 * next caller.
1573 */
1574 ast_bridge_join(holding, logged, NULL, &features, NULL,
1576 if (logged != agent->logged) {
1577 /* This channel is no longer the logged in agent. */
1578 break;
1579 }
1580
1581 if (agent->dead) {
1582 /* The agent is no longer configured. */
1583 break;
1584 }
1585
1586 /* Update the agent's config before rejoining the holding bridge. */
1588 if (!cfgs) {
1589 /* There is no agent configuration. All agents were destroyed. */
1590 break;
1591 }
1592 cfg_new = ao2_find(cfgs->agents, agent->username, OBJ_KEY);
1593 ao2_ref(cfgs, -1);
1594 if (!cfg_new) {
1595 /* The agent is no longer configured. */
1596 break;
1597 }
1598 agent_lock(agent);
1599 cfg_old = agent->cfg;
1600 agent->cfg = cfg_new;
1601
1602 agent->last_disconnect = ast_tvnow();
1603
1604 /* Clear out any caller bridge before rejoining the holding bridge. */
1605 caller_bridge = agent->caller_bridge;
1606 agent->caller_bridge = NULL;
1607 agent_unlock(agent);
1608 ao2_ref(cfg_old, -1);
1609 if (caller_bridge) {
1610 ast_bridge_destroy(caller_bridge, 0);
1611 }
1612
1613 if (agent->state == AGENT_STATE_LOGGING_OUT
1614 || agent->deferred_logoff
1615 || ast_check_hangup_locked(logged)) {
1616 /* The agent was requested to logout or hungup. */
1617 break;
1618 }
1619
1620 /*
1621 * It is safe to access agent->waiting_colp without a lock. It
1622 * is only setup on agent login and not changed.
1623 */
1625 }
1626 ast_bridge_features_cleanup(&features);
1627
1628agent_run_cleanup:
1629 agent_lock(agent);
1630 if (logged != agent->logged) {
1631 /*
1632 * We are no longer the agent channel because of local channel
1633 * optimization.
1634 */
1635 agent_unlock(agent);
1636 ast_debug(1, "Agent %s: Channel %s is no longer the agent.\n",
1637 agent->username, ast_channel_name(logged));
1638 return;
1639 }
1640 agent_logout(agent);
1641}
#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:458
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:9094
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 2350 of file app_agent_pool.c.

2351{
2352#define FORMAT_HDR "%-8s %-20s %-11s %-30s %s\n"
2353#define FORMAT_ROW "%-8s %-20s %-11s %-30s %s\n"
2354
2355 struct ao2_iterator iter;
2356 struct agent_pvt *agent;
2357 struct ast_str *out = ast_str_alloca(512);
2358 unsigned int agents_total = 0;
2359 unsigned int agents_logged_in = 0;
2360 unsigned int agents_talking = 0;
2361
2362 ast_cli(a->fd, FORMAT_HDR, "Agent-ID", "Name", "State", "Channel", "Talking with");
2363 iter = ao2_iterator_init(agents, 0);
2364 for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2365 struct ast_channel *logged;
2366
2367 ++agents_total;
2368
2369 agent_lock(agent);
2370 logged = agent_lock_logged(agent);
2371 if (logged) {
2372 const char *talking_with;
2373
2374 ++agents_logged_in;
2375
2376 talking_with = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2377 if (!ast_strlen_zero(talking_with)) {
2378 ++agents_talking;
2379 } else {
2380 talking_with = "";
2381 }
2382 ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
2383 ast_devstate_str(agent->devstate), ast_channel_name(logged), talking_with);
2384 ast_channel_unlock(logged);
2385 ast_channel_unref(logged);
2386 } else {
2387 ast_str_set(&out, 0, FORMAT_ROW, agent->username, agent->cfg->full_name,
2388 ast_devstate_str(agent->devstate), "", "");
2389 }
2390 agent_unlock(agent);
2391
2392 if (!online_only || logged) {
2393 ast_cli(a->fd, "%s", ast_str_buffer(out));
2394 }
2395 }
2396 ao2_iterator_destroy(&iter);
2397
2398 ast_cli(a->fd, "\nDefined agents: %u, Logged in: %u, Talking: %u\n",
2399 agents_total, agents_logged_in, agents_talking);
2400
2401#undef FORMAT_HDR
2402#undef FORMAT_ROW
2403}
#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 926 of file app_agent_pool.c.

927{
928 struct agent_pvt *agent = obj;
929 int cmp = 0;
930
931 agent_lock(agent);
932 if (agent->the_mark) {
933 agent->the_mark = 0;
934 agent->dead = 1;
935 /* Unlink dead agents immediately. */
936 cmp = CMP_MATCH;
937 }
938 agent_unlock(agent);
939 return cmp;
940}

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 557 of file app_agent_pool.c.

558{
559 struct agents_cfg *cfg;
560
561 cfg = ao2_alloc_options(sizeof(*cfg), agents_cfg_destructor,
563 if (!cfg) {
564 return NULL;
565 }
568 if (!cfg->agents) {
569 ao2_ref(cfg, -1);
570 cfg = NULL;
571 }
572 return cfg;
573}
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 537 of file app_agent_pool.c.

538{
539 struct agents_cfg *doomed = vdoomed;
540
541 ao2_cleanup(doomed->agents);
542 doomed->agents = NULL;
543}

References agents_cfg::agents, ao2_cleanup, and NULL.

Referenced by agents_cfg_alloc().

◆ agents_mark()

static void agents_mark ( void  )
static

Definition at line 921 of file app_agent_pool.c.

922{
924}
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 972 of file app_agent_pool.c.

973{
974 struct ao2_iterator iter;
975 struct agent_cfg *cfg;
977
978 ast_assert(cfgs != NULL);
979
980 agents_mark();
981 iter = ao2_iterator_init(cfgs->agents, 0);
982 for (; (cfg = ao2_iterator_next(&iter)); ao2_ref(cfg, -1)) {
983 RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, cfg->username, OBJ_KEY), ao2_cleanup);
984
985 if (agent) {
986 agent_lock(agent);
987 agent->the_mark = 0;
988 if (!agent->logged) {
989 struct agent_cfg *cfg_old;
990
991 /* Replace the config of agents not logged in. */
992 cfg_old = agent->cfg;
993 ao2_ref(cfg, +1);
994 agent->cfg = cfg;
995 ao2_cleanup(cfg_old);
996 }
997 agent_unlock(agent);
998 continue;
999 }
1000 agent = agent_pvt_new(cfg);
1001 if (!agent) {
1002 continue;
1003 }
1004 ao2_link(agents, agent);
1005 ast_debug(1, "Agent %s: Created.\n", agent->username);
1006 agent_devstate_changed(agent->username);
1007 }
1008 ao2_iterator_destroy(&iter);
1009 agents_sweep();
1010}
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:763

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 942 of file app_agent_pool.c.

943{
944 struct ao2_iterator *iter;
945 struct agent_pvt *agent;
946 struct ast_channel *logged;
947
949 if (!iter) {
950 return;
951 }
952 for (; (agent = ao2_iterator_next(iter)); ao2_ref(agent, -1)) {
953 agent_lock(agent);
954 if (agent->logged) {
955 logged = ast_channel_ref(agent->logged);
956 } else {
957 logged = NULL;
958 }
959 agent_unlock(agent);
960 if (!logged) {
961 continue;
962 }
964 "Forced logoff of agent %s(%s). Agent no longer configured.\n",
965 agent->username, ast_channel_name(logged));
967 ast_channel_unref(logged);
968 }
970}
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 2739 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 1118 of file app_agent_pool.c.

1119{
1120 struct agent_pvt *agent = hook_pvt;
1121
1122 agent_lock(agent);
1123 switch (agent->state) {
1125 /* Connect to caller now. */
1126 ast_debug(1, "Agent %s: Acked call.\n", agent->username);
1127 agent_connect_caller(bridge_channel, agent);/* Will unlock agent. */
1128 return 0;
1129 default:
1130 break;
1131 }
1132 agent_unlock(agent);
1133 return 0;
1134}

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 1448 of file app_agent_pool.c.

1449{
1450 RAII_VAR(struct ast_bridge *, holding, ao2_global_obj_ref(agent_holding), ao2_cleanup);
1451
1452 if (!holding) {
1454 holding = ao2_global_obj_ref(agent_holding);
1455 if (!holding) {
1456 holding = bridge_agent_hold_new();
1457 ao2_global_obj_replace_unref(agent_holding, holding);
1458 }
1460 if (!holding) {
1461 ast_log(LOG_ERROR, "Could not create agent holding bridge.\n");
1462 return -1;
1463 }
1464 }
1465 return 0;
1466}
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:197
#define ast_mutex_lock(a)
Definition: lock.h:196

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 1417 of file app_agent_pool.c.

1418{
1419 ao2_global_obj_release(agent_holding);
1421}
#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:988
ast_bridge_dissolving_fn dissolving
Definition: bridge.h:267

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 1136 of file app_agent_pool.c.

1137{
1138 struct agent_pvt *agent = hook_pvt;
1139 int probation_timedout = 0;
1140 int ack_timedout = 0;
1141 int wrapup_timedout = 0;
1142 int deferred_logoff;
1143 unsigned int wrapup_time;
1144 unsigned int auto_logoff;
1145
1146 agent_lock(agent);
1148 if (deferred_logoff) {
1150 }
1151
1152 switch (agent->state) {
1154 probation_timedout =
1155 LOGIN_WAIT_TIMEOUT_TIME <= (time(NULL) - agent->probation_start);
1156 if (probation_timedout) {
1157 /* Now ready for a caller. */
1160 }
1161 break;
1163 /* Check ack call time. */
1164 auto_logoff = agent->cfg->auto_logoff;
1166 auto_logoff = agent->override_auto_logoff;
1167 }
1168 if (auto_logoff) {
1169 auto_logoff *= 1000;
1170 ack_timedout = ast_tvdiff_ms(ast_tvnow(), agent->ack_time) > auto_logoff;
1171 if (ack_timedout) {
1173 }
1174 }
1175 break;
1177 /* Check wrapup time. */
1178 wrapup_time = agent->cfg->wrapup_time;
1180 wrapup_time = agent->override_wrapup_time;
1181 }
1182 wrapup_timedout = ast_tvdiff_ms(ast_tvnow(), agent->last_disconnect) > wrapup_time;
1183 if (wrapup_timedout) {
1186 }
1187 break;
1188 default:
1189 break;
1190 }
1191 agent_unlock(agent);
1192
1193 if (deferred_logoff) {
1194 ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username);
1197 } else if (probation_timedout) {
1198 ast_debug(1, "Agent %s: Login complete.\n", agent->username);
1200 } else if (ack_timedout) {
1201 ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username);
1204 } else if (wrapup_timedout) {
1205 ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username);
1207 }
1208
1209 return 0;
1210}
#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 1425 of file app_agent_pool.c.

1426{
1427 struct ast_bridge *bridge;
1428
1429 bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
1433 "AgentPool", NULL, NULL);
1434 bridge = bridge_register(bridge);
1435 return bridge;
1436}
static struct ast_bridge_methods bridge_agent_hold_v_table
@ AST_BRIDGE_CAPABILITY_HOLDING
Definition: bridge.h:90
@ 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:713
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:783
struct ast_bridge * bridge_alloc(size_t size, const struct ast_bridge_methods *v_table)
Definition: bridge.c:747

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 1400 of file app_agent_pool.c.

1401{
1402 ast_channel_remove_bridge_role(bridge_channel->chan, "holding_participant");
1403 ast_bridge_base_v_table.pull(self, bridge_channel);
1404}
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:271

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 1229 of file app_agent_pool.c.

1230{
1231 int res = 0;
1232 unsigned int wrapup_time;
1233 char dtmf[AST_FEATURE_MAX_LEN];
1234 struct ast_channel *chan;
1235 const char *moh_class;
1236 RAII_VAR(struct agent_pvt *, agent, NULL, ao2_cleanup);
1237
1238 chan = bridge_channel->chan;
1239
1240 agent = ao2_find(agents, swap ? swap->chan : chan, 0);
1241 if (!agent) {
1242 /* Could not find the agent. */
1243 return -1;
1244 }
1245
1246 /* Setup agent entertainment */
1247 agent_lock(agent);
1248 moh_class = ast_strdupa(agent->cfg->moh);
1249 agent_unlock(agent);
1250 res |= ast_channel_add_bridge_role(chan, "holding_participant");
1251 res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "idle_mode", "musiconhold");
1252 res |= ast_channel_set_bridge_role_option(chan, "holding_participant", "moh_class", moh_class);
1253
1254 /* Add DTMF acknowledge hook. */
1255 dtmf[0] = '\0';
1256 agent_lock(agent);
1258 ? agent->override_ack_call : agent->cfg->ack_call) {
1259 const char *dtmf_accept;
1260
1261 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1262 ? agent->override_dtmf_accept : agent->cfg->dtmf_accept;
1263 ast_copy_string(dtmf, dtmf_accept, sizeof(dtmf));
1264 }
1265 agent_unlock(agent);
1266 if (!ast_strlen_zero(dtmf)) {
1267 ao2_ref(agent, +1);
1270 ao2_ref(agent, -1);
1271 res = -1;
1272 }
1273 }
1274
1275 /* Add heartbeat interval hook. */
1276 ao2_ref(agent, +1);
1279 ao2_ref(agent, -1);
1280 res = -1;
1281 }
1282
1283 res |= ast_bridge_base_v_table.push(self, bridge_channel, swap);
1284 if (res) {
1285 ast_channel_remove_bridge_role(chan, "holding_participant");
1286 return -1;
1287 }
1288
1289 if (swap) {
1292 if (res) {
1293 ast_channel_remove_bridge_role(chan, "holding_participant");
1294 return -1;
1295 }
1296
1297 agent_lock(agent);
1298 ast_channel_unref(agent->logged);
1299 agent->logged = ast_channel_ref(chan);
1300 agent_unlock(agent);
1301
1302 /*
1303 * Kick the channel out so it can come back in fully controlled.
1304 * Otherwise, the after bridge callback will linger and the
1305 * agent will have some slightly different behavior in corner
1306 * cases.
1307 */
1310 return 0;
1311 }
1312
1313 agent_lock(agent);
1314 switch (agent->state) {
1316 /*!
1317 * \todo XXX the login probation time should be only if it is needed.
1318 *
1319 * Need to determine if there are any local channels that can
1320 * optimize and wait until they actually do before leaving the
1321 * AGENT_STATE_PROBATION_WAIT state. For now, the blind
1322 * timer of LOGIN_WAIT_TIMEOUT_TIME will do.
1323 */
1324 /*
1325 * Start the login probation timer.
1326 *
1327 * We cannot handle an agent local channel optimization when the
1328 * agent is on a call. The optimization may kick the agent
1329 * channel we know about out of the call without our being able
1330 * to switch to the replacement channel. Get any agent local
1331 * channel optimization out of the way while the agent is in the
1332 * holding bridge.
1333 */
1334 time(&agent->probation_start);
1335 agent->state = AGENT_STATE_PROBATION_WAIT;
1336 agent_unlock(agent);
1337 break;
1339 /* Restart the probation timer. */
1340 time(&agent->probation_start);
1341 agent_unlock(agent);
1342 break;
1344 /*
1345 * Likely someone manually kicked us out of the holding bridge
1346 * and we came right back in.
1347 */
1348 agent_unlock(agent);
1349 break;
1350 default:
1351 /* Unexpected agent state. */
1352 ast_assert(0);
1353 /* Fall through */
1356 agent->state = AGENT_STATE_READY_FOR_CALL;
1357 agent->devstate = AST_DEVICE_NOT_INUSE;
1358 agent_unlock(agent);
1359 ast_debug(1, "Agent %s: Call abort recovery complete.\n", agent->username);
1360 agent_devstate_changed(agent->username);
1361 break;
1364 wrapup_time = agent->cfg->wrapup_time;
1366 wrapup_time = agent->override_wrapup_time;
1367 }
1368 if (wrapup_time) {
1369 agent->state = AGENT_STATE_CALL_WRAPUP;
1370 } else {
1371 agent->state = AGENT_STATE_READY_FOR_CALL;
1372 agent->devstate = AST_DEVICE_NOT_INUSE;
1373 }
1374 agent_unlock(agent);
1375 if (!wrapup_time) {
1376 /* No wrapup time. */
1377 ast_debug(1, "Agent %s: Ready for new call.\n", agent->username);
1378 agent_devstate_changed(agent->username);
1379 }
1380 break;
1381 }
1382
1383 return 0;
1384}
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:3251
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:269
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 1438 of file app_agent_pool.c.

1439{
1440 /* Setup bridge agent_hold subclass v_table. */
1442 bridge_agent_hold_v_table.name = "agent_hold";
1446}
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:263

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 1721 of file app_agent_pool.c.

1722{
1723 struct ast_bridge_channel *logged;
1724
1725 logged = agent_bridge_channel_get_lock(agent);
1726 if (!logged) {
1727 struct ast_bridge *caller_bridge;
1728
1729 ast_debug(1, "Agent '%s' no longer logged in.\n", agent->username);
1730
1731 agent_lock(agent);
1732 caller_bridge = agent->caller_bridge;
1733 agent->caller_bridge = NULL;
1734 agent_unlock(agent);
1735 if (caller_bridge) {
1736 ast_bridge_destroy(caller_bridge, 0);
1737 }
1738 return;
1739 }
1740
1741 /* Kick the agent out of the holding bridge to reset it. */
1745}
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 1872 of file app_agent_pool.c.

1873{
1874 struct agent_pvt *agent = hook_pvt;
1875 struct ast_bridge_channel *logged;
1876 int res;
1877
1878 logged = agent_bridge_channel_get_lock(agent);
1879 if (!logged) {
1880 ast_verb(3, "Agent '%s' not logged in.\n", agent->username);
1881 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_LOGGED_IN");
1882
1884 caller_abort_agent(agent);
1885 return -1;
1886 }
1887
1888 res = send_alert_to_agent(logged, agent->username);
1890 ao2_ref(logged, -1);
1891 if (res) {
1892 ast_verb(3, "Agent '%s': Failed to alert the agent.\n", agent->username);
1893 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
1894
1896 caller_abort_agent(agent);
1897 return -1;
1898 }
1899
1900 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "NOT_CONNECTED");
1901 ast_indicate(bridge_channel->chan, AST_CONTROL_RINGING);
1902 return -1;
1903}
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:4230
@ 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 1747 of file app_agent_pool.c.

1748{
1749 struct agent_pvt *agent = hook_pvt;
1750
1751 if (agent->state == AGENT_STATE_CALL_PRESENT) {
1752 ast_log(LOG_WARNING, "Agent '%s' process did not respond. Safety timeout.\n",
1753 agent->username);
1754 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", "ERROR");
1755
1757 caller_abort_agent(agent);
1758 }
1759
1760 return -1;
1761}

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 1052 of file app_agent_pool.c.

1053{
1054 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", NULL);
1055}

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 2300 of file app_agent_pool.c.

2301{
2302 char *ret;
2303 struct agent_pvt *agent;
2304 struct agent_complete search = {
2305 .state = state,
2306 };
2307
2309 complete_agent_search, (char *) word, &search);
2310 if (!agent) {
2311 return NULL;
2312 }
2313 ret = ast_strdup(agent->username);
2314 ao2_ref(agent, -1);
2315 return ret;
2316}
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:399
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 2332 of file app_agent_pool.c.

2333{
2334 char *ret;
2335 struct agent_pvt *agent;
2336 struct agent_complete search = {
2337 .state = state,
2338 };
2339
2341 complete_agent_logoff_search, (char *) word, &search);
2342 if (!agent) {
2343 return NULL;
2344 }
2345 ret = ast_strdup(agent->username);
2346 ao2_ref(agent, -1);
2347 return ret;
2348}
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 2318 of file app_agent_pool.c.

2319{
2320 struct agent_pvt *agent = obj;
2321 struct agent_complete *search = data;
2322
2323 if (!agent->logged) {
2324 return 0;
2325 }
2326 if (++search->which > search->state) {
2327 return CMP_MATCH;
2328 }
2329 return 0;
2330}

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 2290 of file app_agent_pool.c.

2291{
2292 struct agent_complete *search = data;
2293
2294 if (++search->which > search->state) {
2295 return CMP_MATCH;
2296 }
2297 return 0;
2298}

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 582 of file app_agent_pool.c.

583{
585 aco_info_destroy(&cfg_info);
586}
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 588 of file app_agent_pool.c.

589{
590 if (aco_info_init(&cfg_info)) {
591 return -1;
592 }
593
594 /* Agent options */
595 aco_option_register(&cfg_info, "ackcall", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, ack_call));
596 aco_option_register(&cfg_info, "acceptdtmf", ACO_EXACT, agent_types, "#", OPT_STRINGFIELD_T, 1, STRFLDSET(struct agent_cfg, dtmf_accept));
597 aco_option_register(&cfg_info, "autologoff", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, auto_logoff));
598 aco_option_register(&cfg_info, "wrapuptime", ACO_EXACT, agent_types, "0", OPT_UINT_T, 0, FLDSET(struct agent_cfg, wrapup_time));
599 aco_option_register(&cfg_info, "musiconhold", ACO_EXACT, agent_types, "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, moh));
600 aco_option_register(&cfg_info, "recordagentcalls", ACO_EXACT, agent_types, "no", OPT_BOOL_T, 1, FLDSET(struct agent_cfg, record_agent_calls));
601 aco_option_register(&cfg_info, "custom_beep", ACO_EXACT, agent_types, "beep", OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, beep_sound));
602 aco_option_register(&cfg_info, "fullname", ACO_EXACT, agent_types, NULL, OPT_STRINGFIELD_T, 0, STRFLDSET(struct agent_cfg, full_name));
603
604 if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
605 return -1;
606 }
607
608 return 0;
609}
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 2679 of file app_agent_pool.c.

2680{
2681 int res = 0;
2682
2685 if (!agents) {
2687 }
2688
2689 /* Init agent holding bridge v_table. */
2691
2692 /* Setup to provide Agent:agent-id device state. */
2694
2695 /* CLI Commands */
2697
2698 /* Manager commands */
2701
2702 /* Dialplan Functions */
2704
2705 /* Dialplan applications */
2708
2709 if (res) {
2710 ast_log(LOG_ERROR, "Unable to register application. Not loading module.\n");
2711 unload_module();
2713 }
2714
2715 if (load_config()) {
2716 ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
2717 unload_module();
2719 }
2720
2722}
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:394
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
#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:1562
#define ARRAY_LEN(a)
Definition: utils.h:690

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 2724 of file app_agent_pool.c.

2725{
2726 if (aco_process_config(&cfg_info, 1) == ACO_PROCESS_ERROR) {
2727 /* Just keep the config we already have in place. */
2728 return -1;
2729 }
2730 return 0;
2731}

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 1468 of file app_agent_pool.c.

1469{
1470 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1471
1472 ast_assert(agent != NULL);
1473
1474 blob = ast_json_pack("{s: s}",
1475 "agent", agent);
1476 if (!blob) {
1477 return;
1478 }
1479
1481}
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 1483 of file app_agent_pool.c.

1484{
1485 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
1486
1487 ast_assert(agent != NULL);
1488
1489 blob = ast_json_pack("{s: s, s: I}",
1490 "agent", agent,
1491 "logintime", (ast_json_int_t)logintime);
1492 if (!blob) {
1493 return;
1494 }
1495
1497}
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 1837 of file app_agent_pool.c.

1838{
1839 return ast_bridge_channel_queue_callback(bridge_channel,
1840 AST_BRIDGE_CHANNEL_CB_OPTION_MEDIA, agent_alert, agent_id, strlen(agent_id) + 1);
1841}
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 1843 of file app_agent_pool.c.

1844{
1846 .id.name = 1,
1847 .id.number = 1,
1848 .id.subaddress = 1,
1849 };
1850 unsigned char data[1024]; /* This should be large enough */
1851 size_t datalen;
1852
1853 datalen = ast_connected_line_build_data(data, sizeof(data), connected, &update);
1854 if (datalen == (size_t) -1) {
1855 return 0;
1856 }
1857
1858 return ast_bridge_channel_queue_control_data(bridge_channel,
1859 AST_CONTROL_CONNECTED_LINE, data, datalen);
1860}
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:8698
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 2647 of file app_agent_pool.c.

2648{
2649 struct ast_bridge *holding;
2650
2651 /* Unregister dialplan applications */
2654
2655 /* Unregister dialplan functions */
2657
2658 /* Unregister manager command */
2659 ast_manager_unregister("Agents");
2660 ast_manager_unregister("AgentLogoff");
2661
2662 /* Unregister CLI commands */
2664
2665 ast_devstate_prov_del("Agent");
2666
2667 /* Destroy agent holding bridge. */
2668 holding = ao2_global_obj_replace(agent_holding, NULL);
2669 if (holding) {
2670 ast_bridge_destroy(holding, 0);
2671 }
2672
2675 agents = NULL;
2676 return 0;
2677}
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:421
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7695
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 2739 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 2278 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 1040 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 2124 of file app_agent_pool.c.

Referenced by agent_login_exec().

◆ agent_type

struct aco_type agent_type
static

◆ agent_types

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

Definition at line 520 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 530 of file app_agent_pool.c.

◆ app_agent_login

const char app_agent_login[] = "AgentLogin"
static

Definition at line 395 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 396 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 2739 of file app_agent_pool.c.

◆ bridge_agent_hold_v_table

struct ast_bridge_methods bridge_agent_hold_v_table
static

Definition at line 1423 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 2543 of file app_agent_pool.c.

Referenced by load_module(), and unload_module().

◆ general_type

struct aco_type general_type
static

Definition at line 523 of file app_agent_pool.c.