Asterisk - The Open Source Telephony Project GIT-master-8f1982c
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 704 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 715 of file app_agent_pool.c.

◆ AST_MAX_BUF

#define AST_MAX_BUF   256

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

Enumeration Type Documentation

◆ AGENT_LOGIN_OPT_FLAGS

Enumerator
OPT_SILENT 

Definition at line 2122 of file app_agent_pool.c.

2122 {
2123 OPT_SILENT = (1 << 0),
2124};
@ 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 634 of file app_agent_pool.c.

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

614 {
615 /*! The agent is defined but an agent is not present. */
617 /*! Forced initial login wait to allow any local channel optimizations to happen. */
619 /*! The agent is ready for a call. */
621 /*! The agent has a call waiting to connect. */
623 /*! The agent needs to ack the call. */
625 /*! The agent is connected with a call. */
627 /*! The agent is resting between calls. */
629 /*! The agent is being kicked out. */
631};
@ 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 2742 of file app_agent_pool.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

706{
707 __ao2_lock(agent, AO2_LOCK_REQ_MUTEX, file, function, line, var);
708}
#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 716 of file app_agent_pool.c.

717{
718 __ao2_unlock(agent, file, function, line, var);
719}
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 2631 of file app_agent_pool.c.

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

2554{
2555 const char *id = astman_get_header(m, "ActionID");
2556 char id_text[AST_MAX_BUF];
2557 struct ao2_iterator iter;
2558 struct agent_pvt *agent;
2559 struct ast_str *out = ast_str_alloca(4096);
2560 int num_agents = 0;
2561
2562 if (!ast_strlen_zero(id)) {
2563 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
2564 } else {
2565 id_text[0] = '\0';
2566 }
2567 astman_send_listack(s, m, "Agents will follow", "start");
2568
2569 iter = ao2_iterator_init(agents, 0);
2570 for (; (agent = ao2_iterator_next(&iter)); ao2_ref(agent, -1)) {
2571 struct ast_channel *logged;
2572
2573 agent_lock(agent);
2574 logged = agent_lock_logged(agent);
2575
2576 /*
2577 * Status Values:
2578 * AGENT_LOGGEDOFF - Agent isn't logged in
2579 * AGENT_IDLE - Agent is logged in, and waiting for call
2580 * AGENT_ONCALL - Agent is logged in, and on a call
2581 * AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this.
2582 */
2583 ast_str_set(&out, 0, "Agent: %s\r\n", agent->username);
2584 ast_str_append(&out, 0, "Name: %s\r\n", agent->cfg->full_name);
2585
2586 if (logged) {
2587 const char *talking_to_chan;
2588 struct ast_str *logged_headers;
2589 RAII_VAR(struct ast_channel_snapshot *, logged_snapshot, ast_channel_snapshot_create(logged), ao2_cleanup);
2590
2591 if (!logged_snapshot
2592 || !(logged_headers =
2593 ast_manager_build_channel_state_string(logged_snapshot))) {
2594 ast_channel_unlock(logged);
2595 ast_channel_unref(logged);
2596 agent_unlock(agent);
2597 continue;
2598 }
2599
2600 talking_to_chan = pbx_builtin_getvar_helper(logged, "BRIDGEPEER");
2601 if (!ast_strlen_zero(talking_to_chan)) {
2602 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_ONCALL");
2603 ast_str_append(&out, 0, "TalkingToChan: %s\r\n", talking_to_chan);
2604 ast_str_append(&out, 0, "CallStarted: %ld\n", (long) agent->call_start);
2605 } else {
2606 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_IDLE");
2607 }
2608 ast_str_append(&out, 0, "LoggedInTime: %ld\r\n", (long) agent->login_start);
2609 ast_str_append(&out, 0, "%s", ast_str_buffer(logged_headers));
2610 ast_channel_unlock(logged);
2611 ast_channel_unref(logged);
2612 ast_free(logged_headers);
2613 } else {
2614 ast_str_append(&out, 0, "Status: %s\r\n", "AGENT_LOGGEDOFF");
2615 }
2616
2617 agent_unlock(agent);
2618
2619 astman_append(s, "Event: Agents\r\n"
2620 "%s%s\r\n",
2621 ast_str_buffer(out), id_text);
2622 ++num_agents;
2623 }
2624 ao2_iterator_destroy(&iter);
2625
2626 astman_send_list_complete_start(s, m, "AgentsComplete", num_agents);
2628 return 0;
2629}
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:2028
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:2064
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_alloca(init_len)
Definition: strings.h:848
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
const ast_string_field full_name
Structure representing an agent.
const ast_string_field username
time_t call_start
time_t login_start
struct agent_cfg * cfg
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Structure representing a snapshot of channel state.
Main Channel structure associated with a channel.
Support for dynamic strings.
Definition: strings.h:623
FILE * out
Definition: utils/frame.c:33
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941

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

Referenced by load_module().

◆ agent_after_bridge_cb()

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

Definition at line 1646 of file app_agent_pool.c.

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

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

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

1689{
1690 struct ast_channel *logged;
1691 struct ast_bridge_channel *bc;
1692
1693 for (;;) {
1694 agent_lock(agent);
1695 logged = agent->logged;
1696 if (!logged) {
1697 agent_unlock(agent);
1698 return NULL;
1699 }
1700 ast_channel_ref(logged);
1701 agent_unlock(agent);
1702
1703 ast_channel_lock(logged);
1705 ast_channel_unlock(logged);
1706 ast_channel_unref(logged);
1707 if (!bc) {
1708 if (agent->logged != logged) {
1709 continue;
1710 }
1711 return NULL;
1712 }
1713
1715 if (bc->chan != logged || agent->logged != logged) {
1717 ao2_ref(bc, -1);
1718 continue;
1719 }
1720 return bc;
1721 }
1722}
#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:10587
#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 488 of file app_agent_pool.c.

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

482{
483 struct agent_cfg *doomed = vdoomed;
484
486}
#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 502 of file app_agent_pool.c.

503{
504 return ao2_find(agents, username, OBJ_KEY);
505}

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

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

1071{
1072 struct ast_bridge *caller_bridge;
1073 int record_agent_calls;
1074 int res;
1075
1076 record_agent_calls = agent->cfg->record_agent_calls;
1077 caller_bridge = agent->caller_bridge;
1078 agent->caller_bridge = NULL;
1079 agent->state = AGENT_STATE_ON_CALL;
1080 time(&agent->call_start);
1081 agent_unlock(agent);
1082
1083 if (!caller_bridge) {
1084 /* Reset agent. */
1087 return;
1088 }
1089 res = ast_bridge_move(caller_bridge, bridge_channel->bridge, bridge_channel->chan,
1090 NULL, 0);
1091 if (res) {
1092 /* Reset agent. */
1093 ast_bridge_destroy(caller_bridge, 0);
1096 return;
1097 }
1100 if (res) {
1101 /* Reset agent. */
1102 ast_bridge_destroy(caller_bridge, 0);
1103 return;
1104 }
1105
1106 if (record_agent_calls) {
1108 .start_stop = AUTO_MONITOR_START,
1109 };
1110
1111 /*
1112 * The agent is in the new bridge so we can invoke the
1113 * mixmonitor hook to only start recording.
1114 */
1116 }
1117
1118 ao2_t_ref(caller_bridge, -1, "Agent successfully in caller_bridge");
1119}
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 796 of file app_agent_pool.c.

797{
799}
@ 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 2210 of file app_agent_pool.c.

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

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

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

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

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

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

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

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

2067{
2068 struct ast_flags opts = { 0 };
2070 unsigned int override_ack_call = 0;
2071 unsigned int override_auto_logoff = 0;
2072 unsigned int override_wrapup_time = 0;
2073 const char *override_dtmf_accept = NULL;
2074 const char *var;
2075
2077
2078 /* Get config values from channel. */
2079 ast_channel_lock(chan);
2081
2082 var = pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2083 if (!ast_strlen_zero(var)) {
2084 override_ack_call = ast_true(var) ? 1 : 0;
2086 }
2087
2088 var = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2089 if (!ast_strlen_zero(var)) {
2090 override_dtmf_accept = ast_strdupa(var);
2092 }
2093
2094 var = pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2095 if (!ast_strlen_zero(var)) {
2096 if (sscanf(var, "%u", &override_auto_logoff) == 1) {
2098 }
2099 }
2100
2101 var = pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2102 if (!ast_strlen_zero(var)) {
2103 if (sscanf(var, "%u", &override_wrapup_time) == 1) {
2105 }
2106 }
2107 ast_channel_unlock(chan);
2108
2109 /* Set config values on agent. */
2110 agent_lock(agent);
2112 agent->waiting_colp = connected;
2113
2114 ast_string_field_set(agent, override_dtmf_accept, override_dtmf_accept);
2115 ast_copy_flags(agent, &opts, AST_FLAGS_ALL);
2116 agent->override_auto_logoff = override_auto_logoff;
2117 agent->override_wrapup_time = override_wrapup_time;
2118 agent->override_ack_call = override_ack_call;
2119 agent_unlock(agent);
2120}
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:199
Connected Line/Party information.
Definition: channel.h:458
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ast_copy_flags(dest, src, flagz)
Definition: utils.h:84
#define AST_FLAGS_ALL
Definition: utils.h:196

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

Referenced by agent_login_exec().

◆ agent_login_exec()

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

Dialplan AgentLogin application to log in an agent.

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

Definition at line 2138 of file app_agent_pool.c.

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

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

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

Referenced by action_agent_logoff(), and agent_handle_logoff_cmd().

◆ agent_logout()

static void agent_logout ( struct agent_pvt agent)
static

Definition at line 1511 of file app_agent_pool.c.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

561{
562 struct agents_cfg *cfg;
563
564 cfg = ao2_alloc_options(sizeof(*cfg), agents_cfg_destructor,
566 if (!cfg) {
567 return NULL;
568 }
571 if (!cfg->agents) {
572 ao2_ref(cfg, -1);
573 cfg = NULL;
574 }
575 return cfg;
576}
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 540 of file app_agent_pool.c.

541{
542 struct agents_cfg *doomed = vdoomed;
543
544 ao2_cleanup(doomed->agents);
545 doomed->agents = NULL;
546}

References agents_cfg::agents, ao2_cleanup, and NULL.

Referenced by agents_cfg_alloc().

◆ agents_mark()

static void agents_mark ( void  )
static

Definition at line 924 of file app_agent_pool.c.

925{
927}
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 975 of file app_agent_pool.c.

976{
977 struct ao2_iterator iter;
978 struct agent_cfg *cfg;
980
981 ast_assert(cfgs != NULL);
982
983 agents_mark();
984 iter = ao2_iterator_init(cfgs->agents, 0);
985 for (; (cfg = ao2_iterator_next(&iter)); ao2_ref(cfg, -1)) {
986 RAII_VAR(struct agent_pvt *, agent, ao2_find(agents, cfg->username, OBJ_KEY), ao2_cleanup);
987
988 if (agent) {
989 agent_lock(agent);
990 agent->the_mark = 0;
991 if (!agent->logged) {
992 struct agent_cfg *cfg_old;
993
994 /* Replace the config of agents not logged in. */
995 cfg_old = agent->cfg;
996 ao2_ref(cfg, +1);
997 agent->cfg = cfg;
998 ao2_cleanup(cfg_old);
999 }
1000 agent_unlock(agent);
1001 continue;
1002 }
1003 agent = agent_pvt_new(cfg);
1004 if (!agent) {
1005 continue;
1006 }
1007 ao2_link(agents, agent);
1008 ast_debug(1, "Agent %s: Created.\n", agent->username);
1009 agent_devstate_changed(agent->username);
1010 }
1011 ao2_iterator_destroy(&iter);
1012 agents_sweep();
1013}
static struct agent_pvt * agent_pvt_new(struct agent_cfg *cfg)
static void agents_mark(void)
static void agents_sweep(void)
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ast_assert(a)
Definition: utils.h:739

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

◆ agents_sweep()

static void agents_sweep ( void  )
static

Definition at line 945 of file app_agent_pool.c.

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

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

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

1452{
1453 RAII_VAR(struct ast_bridge *, holding, ao2_global_obj_ref(agent_holding), ao2_cleanup);
1454
1455 if (!holding) {
1457 holding = ao2_global_obj_ref(agent_holding);
1458 if (!holding) {
1459 holding = bridge_agent_hold_new();
1460 ao2_global_obj_replace_unref(agent_holding, holding);
1461 }
1463 if (!holding) {
1464 ast_log(LOG_ERROR, "Could not create agent holding bridge.\n");
1465 return -1;
1466 }
1467 }
1468 return 0;
1469}
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 1420 of file app_agent_pool.c.

1421{
1422 ao2_global_obj_release(agent_holding);
1424}
#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 1139 of file app_agent_pool.c.

1140{
1141 struct agent_pvt *agent = hook_pvt;
1142 int probation_timedout = 0;
1143 int ack_timedout = 0;
1144 int wrapup_timedout = 0;
1145 int deferred_logoff;
1146 unsigned int wrapup_time;
1147 unsigned int auto_logoff;
1148
1149 agent_lock(agent);
1151 if (deferred_logoff) {
1153 }
1154
1155 switch (agent->state) {
1157 probation_timedout =
1158 LOGIN_WAIT_TIMEOUT_TIME <= (time(NULL) - agent->probation_start);
1159 if (probation_timedout) {
1160 /* Now ready for a caller. */
1163 }
1164 break;
1166 /* Check ack call time. */
1167 auto_logoff = agent->cfg->auto_logoff;
1169 auto_logoff = agent->override_auto_logoff;
1170 }
1171 if (auto_logoff) {
1172 auto_logoff *= 1000;
1173 ack_timedout = ast_tvdiff_ms(ast_tvnow(), agent->ack_time) > auto_logoff;
1174 if (ack_timedout) {
1176 }
1177 }
1178 break;
1180 /* Check wrapup time. */
1181 wrapup_time = agent->cfg->wrapup_time;
1183 wrapup_time = agent->override_wrapup_time;
1184 }
1185 wrapup_timedout = ast_tvdiff_ms(ast_tvnow(), agent->last_disconnect) > wrapup_time;
1186 if (wrapup_timedout) {
1189 }
1190 break;
1191 default:
1192 break;
1193 }
1194 agent_unlock(agent);
1195
1196 if (deferred_logoff) {
1197 ast_debug(1, "Agent %s: Deferred logoff.\n", agent->username);
1200 } else if (probation_timedout) {
1201 ast_debug(1, "Agent %s: Login complete.\n", agent->username);
1203 } else if (ack_timedout) {
1204 ast_debug(1, "Agent %s: Ack call timeout.\n", agent->username);
1207 } else if (wrapup_timedout) {
1208 ast_debug(1, "Agent %s: Wrapup timeout. Ready for new call.\n", agent->username);
1210 }
1211
1212 return 0;
1213}
#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 1428 of file app_agent_pool.c.

1429{
1430 struct ast_bridge *bridge;
1431
1432 bridge = bridge_alloc(sizeof(struct ast_bridge), &bridge_agent_hold_v_table);
1436 "AgentPool", NULL, NULL);
1437 bridge = bridge_register(bridge);
1438 return bridge;
1439}
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 1403 of file app_agent_pool.c.

1404{
1405 ast_channel_remove_bridge_role(bridge_channel->chan, "holding_participant");
1406 ast_bridge_base_v_table.pull(self, bridge_channel);
1407}
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 1232 of file app_agent_pool.c.

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

1442{
1443 /* Setup bridge agent_hold subclass v_table. */
1445 bridge_agent_hold_v_table.name = "agent_hold";
1449}
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 1724 of file app_agent_pool.c.

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

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

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

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

1056{
1057 pbx_builtin_setvar_helper(bridge_channel->chan, "AGENT_STATUS", NULL);
1058}

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

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

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

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

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

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

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

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

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

2683{
2684 int res = 0;
2685
2688 if (!agents) {
2690 }
2691
2692 /* Init agent holding bridge v_table. */
2694
2695 /* Setup to provide Agent:agent-id device state. */
2697
2698 /* CLI Commands */
2700
2701 /* Manager commands */
2704
2705 /* Dialplan Functions */
2707
2708 /* Dialplan applications */
2711
2712 if (res) {
2713 ast_log(LOG_ERROR, "Unable to register application. Not loading module.\n");
2714 unload_module();
2716 }
2717
2718 if (load_config()) {
2719 ast_log(LOG_ERROR, "Unable to load config. Not loading module.\n");
2720 unload_module();
2722 }
2723
2725}
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:1559
#define ARRAY_LEN(a)
Definition: utils.h:666

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

◆ reload()

static int reload ( void  )
static

Definition at line 2727 of file app_agent_pool.c.

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

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

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

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

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

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

2651{
2652 struct ast_bridge *holding;
2653
2654 /* Unregister dialplan applications */
2657
2658 /* Unregister dialplan functions */
2660
2661 /* Unregister manager command */
2662 ast_manager_unregister("Agents");
2663 ast_manager_unregister("AgentLogoff");
2664
2665 /* Unregister CLI commands */
2667
2668 ast_devstate_prov_del("Agent");
2669
2670 /* Destroy agent holding bridge. */
2671 holding = ao2_global_obj_replace(agent_holding, NULL);
2672 if (holding) {
2673 ast_bridge_destroy(holding, 0);
2674 }
2675
2678 agents = NULL;
2679 return 0;
2680}
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:7697
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 2742 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 2281 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 1043 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 2127 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 523 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 533 of file app_agent_pool.c.

◆ app_agent_login

const char app_agent_login[] = "AgentLogin"
static

Definition at line 398 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 399 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 2742 of file app_agent_pool.c.

◆ bridge_agent_hold_v_table

struct ast_bridge_methods bridge_agent_hold_v_table
static

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

Referenced by load_module(), and unload_module().

◆ general_type

struct aco_type general_type
static

Definition at line 526 of file app_agent_pool.c.