52 #include "asterisk/features_config.h"
55 #include "asterisk/stasis_channels.h"
342 #define AST_MAX_BUF 256
345 #define CALLER_SAFETY_TIMEOUT_TIME (2 * 60 * 1000)
348 #define LOGIN_WAIT_TIMEOUT_TIME 5
350 static const char app_agent_login[] =
"AgentLogin";
351 static const char app_agent_request[] =
"AgentRequest";
411 static int agent_cfg_sort_cmp(
const void *obj_left,
const void *obj_right,
int flags)
413 const struct agent_cfg *cfg_left = obj_left;
414 const struct agent_cfg *cfg_right = obj_right;
415 const char *right_key = obj_right;
424 cmp = strcmp(cfg_left->
username, right_key);
427 cmp = strncmp(cfg_left->
username, right_key, strlen(right_key));
433 static void agent_cfg_destructor(
void *vdoomed)
440 static void *agent_cfg_alloc(
const char *name)
444 cfg = ao2_alloc_options(
sizeof(*cfg), agent_cfg_destructor,
456 return ao2_find(agents, username,
OBJ_KEY);
465 static struct aco_type agent_type = {
469 .category =
"general",
470 .item_alloc = agent_cfg_alloc,
471 .item_find = agent_cfg_find,
478 static struct aco_type general_type = {
482 .category =
"general",
485 static struct aco_file agents_conf = {
487 .types =
ACO_TYPES(&general_type, &agent_type),
492 static void agents_cfg_destructor(
void *vdoomed)
496 ao2_cleanup(doomed->
agents);
512 static void *agents_cfg_alloc(
void)
516 cfg = ao2_alloc_options(
sizeof(*cfg), agents_cfg_destructor,
530 static void agents_post_apply_config(
void);
533 .files = ACO_FILES(&agents_conf),
534 .post_apply_config = agents_post_apply_config,
537 static void destroy_config(
void)
543 static int load_config(
void)
587 AGENT_FLAG_ACK_CALL = (1 << 0),
588 AGENT_FLAG_DTMF_ACCEPT = (1 << 1),
589 AGENT_FLAG_AUTO_LOGOFF = (1 << 2),
590 AGENT_FLAG_WRAPUP_TIME = (1 << 3),
656 #define agent_lock(agent) _agent_lock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
657 static inline void _agent_lock(
struct agent_pvt *agent,
const char *file,
const char *
function,
int line,
const char *var)
667 #define agent_unlock(agent) _agent_unlock(agent, __FILE__, __PRETTY_FUNCTION__, __LINE__, #agent)
668 static inline void _agent_unlock(
struct agent_pvt *agent,
const char *file,
const char *
function,
int line,
const char *var)
698 ast_channel_lock(logged);
702 if (logged != agent->
logged) {
704 ast_channel_unlock(logged);
731 agent = ao2_find(agents, agent_id,
OBJ_KEY);
748 static void agent_devstate_changed(
const char *agent_id)
753 static void agent_pvt_destructor(
void *vdoomed)
758 if (!ast_strlen_zero(doomed->
username)) {
760 agent_devstate_changed(doomed->
username);
771 ao2_cleanup(doomed->
cfg);
780 agent = ao2_alloc(
sizeof(*agent), agent_pvt_destructor);
812 static int agent_pvt_sort_cmp(
const void *obj_left,
const void *obj_right,
int flags)
814 const struct agent_pvt *agent_left = obj_left;
815 const struct agent_pvt *agent_right = obj_right;
816 const char *right_key = obj_right;
825 cmp = strcmp(agent_left->
username, right_key);
828 cmp = strncmp(agent_left->
username, right_key, strlen(right_key));
844 static int agent_pvt_cmp(
void *obj,
void *arg,
int flags)
856 if (agent->
logged == arg) {
866 static int agent_mark(
void *obj,
void *arg,
int flags)
876 static void agents_mark(
void)
881 static int agent_sweep(
void *obj,
void *arg,
int flags)
897 static void agents_sweep(
void)
907 for (; (agent = ao2_iterator_next(iter));
ao2_ref(agent, -1)) {
919 "Forced logoff of agent %s(%s). Agent no longer configured.\n",
920 agent->
username, ast_channel_name(logged));
927 static void agents_post_apply_config(
void)
933 ast_assert(cfgs != NULL);
937 for (; (cfg = ao2_iterator_next(&iter));
ao2_ref(cfg, -1)) {
947 cfg_old = agent->
cfg;
950 ao2_cleanup(cfg_old);
955 agent = agent_pvt_new(cfg);
961 agent_devstate_changed(agent->
username);
967 static int agent_logoff_request(
const char *agent_id,
int soft)
977 logged = agent_lock_logged(agent);
984 ast_channel_unlock(logged);
1025 int record_agent_calls;
1035 if (!caller_bridge) {
1038 AST_CAUSE_NORMAL_CLEARING);
1047 AST_CAUSE_NORMAL_CLEARING);
1058 if (record_agent_calls) {
1070 ao2_t_ref(caller_bridge, -1,
"Agent successfully in caller_bridge");
1073 static int bridge_agent_hold_ack(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt)
1078 switch (agent->
state) {
1082 agent_connect_caller(bridge_channel, agent);
1091 static int bridge_agent_hold_heartbeat(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt)
1094 int probation_timedout = 0;
1095 int ack_timedout = 0;
1096 int wrapup_timedout = 0;
1098 unsigned int wrapup_time;
1099 unsigned int auto_logoff;
1103 if (deferred_logoff) {
1107 switch (agent->
state) {
1109 probation_timedout =
1111 if (probation_timedout) {
1120 if (ast_test_flag(agent, AGENT_FLAG_AUTO_LOGOFF)) {
1124 auto_logoff *= 1000;
1134 if (ast_test_flag(agent, AGENT_FLAG_WRAPUP_TIME)) {
1138 if (wrapup_timedout) {
1148 if (deferred_logoff) {
1151 AST_CAUSE_NORMAL_CLEARING);
1152 }
else if (probation_timedout) {
1154 agent_devstate_changed(agent->
username);
1155 }
else if (ack_timedout) {
1158 AST_CAUSE_NORMAL_CLEARING);
1159 }
else if (wrapup_timedout) {
1160 ast_debug(1,
"Agent %s: Wrapup timeout. Ready for new call.\n", agent->
username);
1161 agent_devstate_changed(agent->
username);
1167 static void agent_after_bridge_cb(
struct ast_channel *chan,
void *data);
1187 unsigned int wrapup_time;
1188 char dtmf[AST_FEATURE_MAX_LEN];
1190 const char *moh_class;
1193 chan = bridge_channel->
chan;
1195 agent = ao2_find(agents, swap ? swap->
chan : chan, 0);
1212 if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL)
1214 const char *dtmf_accept;
1216 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1221 if (!ast_strlen_zero(dtmf)) {
1246 agent_after_bridge_cb_failed, chan);
1264 AST_CAUSE_NORMAL_CLEARING);
1269 switch (agent->
state) {
1315 agent_devstate_changed(agent->
username);
1320 if (ast_test_flag(agent, AGENT_FLAG_WRAPUP_TIME)) {
1333 agent_devstate_changed(agent->
username);
1380 static struct ast_bridge *bridge_agent_hold_new(
void)
1384 bridge = bridge_alloc(
sizeof(
struct ast_bridge), &bridge_agent_hold_v_table);
1388 "AgentPool", NULL, NULL);
1393 static void bridge_init_agent_hold(
void)
1397 bridge_agent_hold_v_table.
name =
"agent_hold";
1400 bridge_agent_hold_v_table.
pull = bridge_agent_hold_pull;
1403 static int bridge_agent_hold_deferred_create(
void)
1411 holding = bridge_agent_hold_new();
1416 ast_log(LOG_ERROR,
"Could not create agent holding bridge.\n");
1423 static void send_agent_login(
struct ast_channel *chan,
const char *agent)
1427 ast_assert(agent != NULL);
1438 static void send_agent_logoff(
struct ast_channel *chan,
const char *agent,
long logintime)
1442 ast_assert(agent != NULL);
1463 static void agent_logout(
struct agent_pvt *agent)
1467 long time_logged_in;
1476 ast_clear_flag(agent, AST_FLAGS_ALL);
1478 agent_devstate_changed(agent->
username);
1480 if (caller_bridge) {
1484 ast_channel_lock(logged);
1485 send_agent_logoff(logged, agent->
username, time_logged_in);
1486 ast_channel_unlock(logged);
1487 ast_verb(2,
"Agent '%s' logged out. Logged in for %ld seconds.\n",
1505 ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING);
1506 goto agent_run_cleanup;
1515 ast_channel_hangupcause_set(logged, AST_CAUSE_NORMAL_CLEARING);
1519 ast_debug(1,
"Agent %s: Someone destroyed the agent holding bridge.\n",
1531 if (logged != agent->
logged) {
1554 cfg_old = agent->
cfg;
1555 agent->
cfg = cfg_new;
1564 if (caller_bridge) {
1570 || ast_check_hangup_locked(logged)) {
1585 if (logged != agent->
logged) {
1591 ast_debug(1,
"Agent %s: Channel %s is no longer the agent.\n",
1592 agent->
username, ast_channel_name(logged));
1595 agent_logout(agent);
1598 static void agent_after_bridge_cb(
struct ast_channel *chan,
void *data)
1602 agent = ao2_find(agents, chan, 0);
1607 ast_debug(1,
"Agent %s: New agent channel %s.\n",
1608 agent->
username, ast_channel_name(chan));
1609 agent_run(agent, chan);
1618 agent = ao2_find(agents, chan, 0);
1622 ast_log(LOG_WARNING,
"Agent %s: Forced logout. Lost control of %s because: %s\n",
1623 agent->
username, ast_channel_name(chan),
1626 agent_logout(agent);
1655 ast_channel_lock(logged);
1657 ast_channel_unlock(logged);
1660 if (agent->
logged != logged) {
1667 if (bc->
chan != logged || agent->
logged != logged) {
1676 static void caller_abort_agent(
struct agent_pvt *agent)
1680 logged = agent_bridge_channel_get_lock(agent);
1690 if (caller_bridge) {
1698 AST_CAUSE_NORMAL_CLEARING);
1702 static int caller_safety_timeout(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt)
1707 ast_log(LOG_WARNING,
"Agent '%s' process did not respond. Safety timeout.\n",
1712 caller_abort_agent(agent);
1718 static void agent_alert(
struct ast_bridge_channel *bridge_channel,
const void *payload,
size_t payload_size)
1720 const char *agent_id = payload;
1721 const char *playfile;
1722 const char *dtmf_accept;
1727 agent = ao2_find(agents, agent_id,
OBJ_KEY);
1729 ast_debug(1,
"Agent '%s' does not exist. Where did it go?\n", agent_id);
1744 if (ast_test_flag(agent, AGENT_FLAG_ACK_CALL)
1746 dtmf_accept = ast_test_flag(agent, AGENT_FLAG_DTMF_ACCEPT)
1750 dtmf[0] = *dtmf_accept;
1760 ast_strlen_zero(dtmf_accept) ? AST_DIGIT_ANY : dtmf_accept);
1764 switch (agent->
state) {
1766 if (!ast_strlen_zero(dtmf_accept)) {
1782 agent_connect_caller(bridge_channel, agent);
1792 static int send_alert_to_agent(
struct ast_bridge_channel *bridge_channel,
const char *agent_id)
1805 unsigned char data[1024];
1809 if (datalen == (
size_t) -1) {
1827 static int caller_joined_bridge(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt)
1833 logged = agent_bridge_channel_get_lock(agent);
1835 ast_verb(3,
"Agent '%s' not logged in.\n", agent->
username);
1839 caller_abort_agent(agent);
1843 res = send_alert_to_agent(logged, agent->
username);
1847 ast_verb(3,
"Agent '%s': Failed to alert the agent.\n", agent->
username);
1851 caller_abort_agent(agent);
1884 if (bridge_agent_hold_deferred_create()) {
1891 if (ast_strlen_zero(args.agent_id)) {
1892 ast_log(LOG_WARNING,
"AgentRequest requires an AgentId\n");
1897 agent = ao2_find(agents, args.agent_id,
OBJ_KEY);
1899 ast_verb(3,
"Agent '%s' does not exist.\n", args.agent_id);
1927 if (!caller_bridge) {
1933 switch (agent->
state) {
1939 ast_verb(3,
"Agent '%s' not logged in.\n", agent->
username);
1952 ast_verb(3,
"Agent '%s' is busy.\n", agent->
username);
1957 agent_devstate_changed(agent->
username);
1961 ast_channel_lock(chan);
1963 ast_channel_unlock(chan);
1965 logged = agent_bridge_channel_get_lock(agent);
1968 caller_abort_agent(agent);
1971 ast_verb(3,
"Agent '%s' not logged in.\n", agent->
username);
1976 send_colp_to_agent(logged, &connected);
1981 if (
ast_bridge_join(caller_bridge, chan, NULL, &caller_features, NULL,
1983 caller_abort_agent(agent);
1984 ast_verb(3,
"Agent '%s': Caller %s failed to join the bridge.\n",
1985 agent->
username, ast_channel_name(chan));
1991 ast_channel_lock(chan);
2005 ast_channel_unlock(chan);
2007 return res ? -1 : 0;
2022 unsigned int override_ack_call = 0;
2023 unsigned int override_auto_logoff = 0;
2024 unsigned int override_wrapup_time = 0;
2025 const char *override_dtmf_accept = NULL;
2031 ast_channel_lock(chan);
2035 if (!ast_strlen_zero(var)) {
2036 override_ack_call =
ast_true(var) ? 1 : 0;
2037 ast_set_flag(&opts, AGENT_FLAG_ACK_CALL);
2041 if (!ast_strlen_zero(var)) {
2043 ast_set_flag(&opts, AGENT_FLAG_DTMF_ACCEPT);
2047 if (!ast_strlen_zero(var)) {
2048 if (sscanf(var,
"%u", &override_auto_logoff) == 1) {
2049 ast_set_flag(&opts, AGENT_FLAG_AUTO_LOGOFF);
2054 if (!ast_strlen_zero(var)) {
2055 if (sscanf(var,
"%u", &override_wrapup_time) == 1) {
2056 ast_set_flag(&opts, AGENT_FLAG_WRAPUP_TIME);
2059 ast_channel_unlock(chan);
2067 ast_copy_flags(agent, &opts, AST_FLAGS_ALL);
2074 enum AGENT_LOGIN_OPT_FLAGS {
2075 OPT_SILENT = (1 << 0),
2102 if (bridge_agent_hold_deferred_create()) {
2113 if (ast_strlen_zero(args.agent_id)) {
2114 ast_log(LOG_WARNING,
"AgentLogin requires an AgentId\n");
2124 agent = ao2_find(agents, args.agent_id,
OBJ_KEY);
2126 ast_verb(3,
"Agent '%s' does not exist.\n", args.agent_id);
2135 ast_verb(3,
"Agent '%s' already logged in.\n", agent->
username);
2145 agent_login_channel_config(agent, chan);
2147 if (!ast_test_flag(&opts, OPT_SILENT)) {
2151 ast_verb(2,
"Agent '%s' logged in (format %s/%s)\n", agent->
username,
2154 ast_channel_lock(chan);
2155 send_agent_login(chan, agent->
username);
2156 ast_channel_unlock(chan);
2158 agent_run(agent, chan);
2162 static int agent_function_read(
struct ast_channel *chan,
const char *cmd,
char *data,
char *buf,
size_t len)
2177 if (ast_strlen_zero(args.agentid)) {
2178 ast_log(LOG_WARNING,
"The AGENT function requires an argument - agentid!\n");
2182 args.item =
"status";
2185 agent = ao2_find(agents, args.agentid,
OBJ_KEY);
2187 ast_log(LOG_WARNING,
"Agent '%s' not found!\n", args.agentid);
2192 if (!strcasecmp(args.item,
"status")) {
2196 status =
"LOGGEDIN";
2198 status =
"LOGGEDOUT";
2201 }
else if (!strcasecmp(args.item,
"name")) {
2203 }
else if (!strcasecmp(args.item,
"mohclass")) {
2205 }
else if (!strcasecmp(args.item,
"channel")) {
2206 logged = agent_lock_logged(agent);
2211 ast_channel_unlock(logged);
2214 pos = strrchr(buf,
'-');
2219 }
else if (!strcasecmp(args.item,
"fullchannel")) {
2220 logged = agent_lock_logged(agent);
2223 ast_channel_unlock(logged);
2235 .read = agent_function_read,
2245 static int complete_agent_search(
void *obj,
void *arg,
void *data,
int flags)
2255 static char *complete_agent(
const char *word,
int state)
2263 agent = ao2_callback_data(agents, ast_strlen_zero(word) ? 0 :
OBJ_PARTIAL_KEY,
2264 complete_agent_search, (
char *) word, &search);
2273 static int complete_agent_logoff_search(
void *obj,
void *arg,
void *data,
int flags)
2287 static char *complete_agent_logoff(
const char *word,
int state)
2295 agent = ao2_callback_data(agents, ast_strlen_zero(word) ? 0 : OBJ_PARTIAL_KEY,
2296 complete_agent_logoff_search, (
char *) word, &search);
2305 static void agent_show_requested(
struct ast_cli_args *a,
int online_only)
2307 #define FORMAT_HDR "%-8s %-20s %-11s %-30s %s\n"
2308 #define FORMAT_ROW "%-8s %-20s %-11s %-30s %s\n"
2312 struct ast_str *out = ast_str_alloca(512);
2313 unsigned int agents_total = 0;
2314 unsigned int agents_logged_in = 0;
2315 unsigned int agents_talking = 0;
2317 ast_cli(a->fd, FORMAT_HDR,
"Agent-ID",
"Name",
"State",
"Channel",
"Talking with");
2319 for (; (agent = ao2_iterator_next(&iter));
ao2_ref(agent, -1)) {
2325 logged = agent_lock_logged(agent);
2327 const char *talking_with;
2332 if (!ast_strlen_zero(talking_with)) {
2339 ast_channel_unlock(logged);
2347 if (!online_only || logged) {
2353 ast_cli(a->fd,
"\nDefined agents: %u, Logged in: %u, Talking: %u\n",
2354 agents_total, agents_logged_in, agents_talking);
2364 e->
command =
"agent show online";
2366 "Usage: agent show online\n"
2367 " Provides summary information for logged in agents.\n";
2374 return CLI_SHOWUSAGE;
2377 agent_show_requested(a, 1);
2386 e->
command =
"agent show all";
2388 "Usage: agent show all\n"
2389 " Provides summary information for all agents.\n";
2396 return CLI_SHOWUSAGE;
2399 agent_show_requested(a, 0);
2408 struct ast_str *out = ast_str_alloca(4096);
2414 "Usage: agent show <agent-id>\n"
2415 " Show information about the <agent-id> agent\n";
2419 return complete_agent(a->word, a->n);
2425 return CLI_SHOWUSAGE;
2428 agent = ao2_find(agents, a->argv[2],
OBJ_KEY);
2430 ast_cli(a->fd,
"Agent '%s' not found\n", a->argv[2]);
2435 logged = agent_lock_logged(agent);
2443 const char *talking_with;
2445 ast_str_append(&out, 0,
"LoggedInChannel: %s\n", ast_channel_name(logged));
2448 if (!ast_strlen_zero(talking_with)) {
2452 ast_channel_unlock(logged);
2469 "Usage: agent logoff <agent-id> [soft]\n"
2470 " Sets an agent as no longer logged in.\n"
2471 " If 'soft' is specified, do not hangup existing calls.\n";
2475 return complete_agent_logoff(a->word, a->n);
2476 }
else if (a->pos == 3 && a->n == 0
2477 && (ast_strlen_zero(a->word)
2478 || !strncasecmp(
"soft", a->word, strlen(a->word)))) {
2484 if (a->argc < 3 || 4 < a->argc) {
2485 return CLI_SHOWUSAGE;
2487 if (a->argc == 4 && strcasecmp(a->argv[3],
"soft")) {
2488 return CLI_SHOWUSAGE;
2491 if (!agent_logoff_request(a->argv[2], a->argc == 4)) {
2492 ast_cli(a->fd,
"Logging out %s\n", a->argv[2]);
2499 AST_CLI_DEFINE(agent_handle_show_online,
"Show status of online agents"),
2500 AST_CLI_DEFINE(agent_handle_show_all,
"Show status of all agents"),
2501 AST_CLI_DEFINE(agent_handle_show_specific,
"Show information about an agent"),
2502 AST_CLI_DEFINE(agent_handle_logoff_cmd,
"Sets an agent offline"),
2508 char id_text[AST_MAX_BUF];
2511 struct ast_str *out = ast_str_alloca(4096);
2514 if (!ast_strlen_zero(
id)) {
2515 snprintf(id_text,
sizeof(id_text),
"ActionID: %s\r\n",
id);
2522 for (; (agent = ao2_iterator_next(&iter));
ao2_ref(agent, -1)) {
2526 logged = agent_lock_logged(agent);
2539 const char *talking_to_chan;
2540 struct ast_str *logged_headers;
2543 if (!logged_snapshot
2544 || !(logged_headers =
2546 ast_channel_unlock(logged);
2553 if (!ast_strlen_zero(talking_to_chan)) {
2555 ast_str_append(&out, 0,
"TalkingToChan: %s\r\n", talking_to_chan);
2562 ast_channel_unlock(logged);
2564 ast_free(logged_headers);
2588 if (ast_strlen_zero(agent)) {
2593 if (!agent_logoff_request(agent,
ast_true(soft_s))) {
2602 static int unload_module(
void)
2629 ao2_cleanup(agents);
2634 static int load_module(
void)
2645 bridge_init_agent_hold();
2665 ast_log(LOG_ERROR,
"Unable to register application. Not loading module.\n");
2670 if (load_config()) {
2671 ast_log(LOG_ERROR,
"Unable to load config. Not loading module.\n");
2679 static int reload(
void)
2688 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"Call center agent pool applications",
2689 .support_level = AST_MODULE_SUPPORT_CORE,
2690 .load = load_module,
2691 .unload = unload_module,
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Main Channel structure associated with a channel.
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
const ast_string_field username
ast_device_state
Device States.
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.
void ast_bridge_channel_clear_roles(struct ast_bridge_channel *bridge_channel)
Clear all roles from a bridge_channel's role list.
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
struct ast_bridge_features * features
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.
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.
const ast_string_field override_dtmf_accept
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
#define CALLER_SAFETY_TIMEOUT_TIME
struct ast_bridge * bridge_register(struct ast_bridge *bridge)
Register the new bridge with the system.
const ast_string_field full_name
#define agent_unlock(agent)
Unlock the agent.
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).
Structure that contains features information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define ast_channel_unref(c)
Decrease channel reference count.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
const ast_string_field beep_sound
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
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.
void ast_channel_remove_bridge_role(struct ast_channel *chan, const char *role_name)
Removes a bridge role from a channel.
int ast_softhangup(struct ast_channel *chan, int cause)
Softly hangup up a channel.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
unsigned int deferred_logoff
descriptor for a cli entry.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
static AO2_GLOBAL_OBJ_STATIC(agent_holding)
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.
struct ao2_container * agents
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
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.
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
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.
void __ao2_cleanup(void *obj)
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
struct ast_channel * logged
Structure representing a snapshot of channel state.
int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var)
Unlock an object.
int ast_devstate_prov_del(const char *label)
Remove device state provider.
ast_channel_state
ast_channel states
int ack_call
TRUE if agent needs to ack a call to accept it.
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
ast_bridge_dissolving_fn dissolving
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
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.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_devstate_prov_add(const char *label, ast_devstate_prov_cb_type callback)
Add device state provider.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
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.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
#define ast_strdup(str)
A wrapper for strdup()
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
int ast_channel_add_bridge_role(struct ast_channel *chan, const char *role_name)
Adds a bridge role to a channel.
static ast_mutex_t agent_holding_lock
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.
The representation of a single configuration file to be processed.
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...
int ast_unregister_application(const char *app)
Unregister an application.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
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.
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...
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
struct ast_bridge * bridge
Bridge this channel is participating in.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
struct ast_bridge_methods ast_bridge_base_v_table
Bridge base class virtual method table.
const ast_string_field dtmf_accept
DTMF string for an agent to accept a call. * *.
struct ast_bridge * caller_bridge
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
ast_bridge_after_cb_reason
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.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
enum ast_device_state devstate
#define agent_lock(agent)
Lock the agent.
struct ast_bridge_channel * bridge_channel
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define ast_bridge_channel_lock(bridge_channel)
Lock the bridge_channel.
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.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
General Asterisk PBX channel definitions.
static int agent_request_exec(struct ast_channel *chan, const char *data)
Dialplan AgentRequest application to locate an agent to talk with.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Type for default option handler for unsigned integers.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Data structure associated with a custom dialplan function.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_STRING_FIELD(name)
Declare a string field.
const ast_string_field username
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
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.
unsigned int auto_logoff
Number of seconds for agent to ack a call before being logged off.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
#define ast_debug(level,...)
Log a DEBUG message.
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
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.
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
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.
Their was an error and no changes were applied.
const char * ast_devstate_str(enum ast_device_state devstate) attribute_pure
Convert device state to text string that is easier to parse.
#define ast_bridge_channel_unlock(bridge_channel)
Unlock the bridge_channel.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Configuration option-handling.
Structure that contains information about a bridge.
unsigned int wrapup_time
Time after a call in ms before the agent can get a new call.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
Structure representing an agent.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Type for default option handler for bools (ast_true/ast_false)
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
struct timeval last_disconnect
Connected Line/Party information.
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_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.
const ast_string_field moh
Bridge virtual methods table definition.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
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.
static int agent_login_exec(struct ast_channel *chan, const char *data)
Dialplan AgentLogin application to log in an agent.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
unsigned int dead
TRUE if the agent is no longer configured and is being destroyed.
Basic bridge subclass API.
unsigned int override_wrapup_time
Structure used to handle boolean flags.
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.
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)
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel's bridge pointer.
Indicate what information in ast_party_connected_line should be set.
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...
static void bridge_agent_hold_dissolving(struct ast_bridge *self)
The bridge is being dissolved.
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
struct ast_set_party_id id
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
struct ast_channel * chan
Replace objects with duplicate keys in container.
Structure that contains information regarding a channel in a bridge.
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.
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.
After Bridge Execution API.
#define ast_channel_ref(c)
Increase channel reference count.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
Type information about a category-level configurable object.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
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.
unsigned int override_auto_logoff
#define LOGIN_WAIT_TIMEOUT_TIME
int ast_answer(struct ast_channel *chan)
Answer a channel.
Internal Asterisk hangup causes.
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
ast_bridge_pull_channel_fn pull
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
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.
ast_bridge_push_channel_fn push
Reject objects with duplicate keys in container.
#define AST_CLI_YESNO(x)
Return Yes or No depending on the argument.
void ast_channel_publish_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
#define ASTERISK_GPL_KEY
The text the key() function should return.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
enum ast_bridge_features_monitor start_stop
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define CONFIG_INFO_STANDARD(name, arr, alloc,...)
Declare an aco_info struct with default module and preload values.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
struct ast_party_connected_line waiting_colp
#define ao2_global_obj_replace(holder, obj)
Replace an ao2 object in the global holder.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ast_custom_function_register(acf)
Register a custom function.
unsigned int override_ack_call
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
static int bridge_agent_hold_push(struct ast_bridge *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap)
#define AST_APP_ARG(name)
Define an application argument.
static struct ao2_container * agents
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
#define ao2_link(container, obj)
Add an object to a container.