#include "asterisk.h"
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"
#include "asterisk/data.h"
Go to the source code of this file.
Data Structures | |
struct | agent_pvt |
Structure representing an agent. More... | |
struct | agents |
Defines | |
#define | AST_MAX_AGENT 80 |
#define | AST_MAX_BUF 256 |
#define | AST_MAX_FILENAME_LEN 256 |
#define | CHECK_FORMATS(ast, p) |
#define | CLEANUP(ast, p) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
#define | DATA_EXPORT_AGENT(MEMBER) |
#define | DEFAULT_ACCEPTDTMF '#' |
#define | DEFAULT_ENDDTMF '*' |
#define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
#define | PA_MAX_LEN 2048 |
Enumerations | |
enum | { AGENT_FLAG_ACKCALL = (1 << 0), AGENT_FLAG_AUTOLOGOFF = (1 << 1), AGENT_FLAG_WRAPUPTIME = (1 << 2), AGENT_FLAG_ACCEPTDTMF = (1 << 3), AGENT_FLAG_ENDDTMF = (1 << 4) } |
Functions | |
static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | action_agent_logoff (struct mansession *s, const struct message *m) |
static int | action_agents (struct mansession *s, const struct message *m) |
static struct agent_pvt * | add_agent (const char *agent, int pending) |
static int | agent_ack_sleep (void *data) |
static int | agent_answer (struct ast_channel *ast) |
static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
static int | agent_cleanup (struct agent_pvt *p) |
static int | agent_cont_sleep (void *data) |
static int | agent_devicestate (void *data) |
Part of PBX channel interface. | |
static int | agent_digit_begin (struct ast_channel *ast, char digit) |
static int | agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
static struct ast_channel * | agent_get_base_channel (struct ast_channel *chan) |
return the channel or base channel if one exists. This function assumes the channel it is called on is already locked | |
static int | agent_hangup (struct ast_channel *ast) |
static int | agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
static int | agent_logoff (const char *agent, int soft) |
static char * | agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static struct ast_channel * | agent_new (struct agent_pvt *p, int state, const char *linkedid) |
Create new agent channel. | |
static struct ast_frame * | agent_read (struct ast_channel *ast) |
static struct ast_channel * | agent_request (const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause) |
Part of the Asterisk PBX interface. | |
static int | agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen) |
static int | agent_sendtext (struct ast_channel *ast, const char *text) |
static int | agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base) |
static int | agent_start_monitoring (struct ast_channel *ast, int needlock) |
static int | agent_write (struct ast_channel *ast, struct ast_frame *f) |
static int | agentmonitoroutgoing_exec (struct ast_channel *chan, const char *data) |
Called by the AgentMonitorOutgoing application (from the dial plan). | |
static int | agents_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root) |
static char * | agents_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | agents_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
AST_DATA_STRUCTURE (agent_pvt, DATA_EXPORT_AGENT) | |
static int | check_availability (struct agent_pvt *newlyavailable, int needlock) |
static int | check_beep (struct agent_pvt *newlyavailable, int needlock) |
static char * | complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state) |
static struct agent_pvt * | find_agent (char *agentid) |
static int | function_agent (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | load_module (void) |
Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file. | |
static int | login_exec (struct ast_channel *chan, const char *data) |
Log in agent application. | |
static force_inline int | powerof (unsigned int d) |
static int | read_agent_config (int reload) |
static int | reload (void) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Agent Proxy Channel" , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } |
static char | acceptdtmf = DEFAULT_ACCEPTDTMF |
static int | ackcall |
static struct ast_custom_function | agent_function |
static const char | agent_logoff_usage [] |
static struct ast_channel_tech | agent_tech |
Channel interface description for PBX integration. | |
static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye" |
static struct ast_data_handler | agents_data_provider |
static struct ast_data_entry | agents_data_providers [] |
static const char | app [] = "AgentLogin" |
static const char | app3 [] = "AgentMonitorOutgoing" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static int | autologoff |
static int | autologoffunavail = 0 |
static char | beep [AST_MAX_BUF] = "beep" |
static struct ast_cli_entry | cli_agents [] |
static const char | config [] = "agents.conf" |
static int | endcall |
static char | enddtmf = DEFAULT_ENDDTMF |
static ast_group_t | group |
static int | maxlogintries = 3 |
static char | moh [80] = "default" |
static int | multiplelogin = 1 |
static const char | pa_family [] = "Agents" |
static int | recordagentcalls = 0 |
static char | recordformat [AST_MAX_BUF] = "" |
static char | recordformatext [AST_MAX_BUF] = "" |
static char | savecallsin [AST_MAX_BUF] = "" |
static const char | tdesc [] = "Call Agent Proxy Channel" |
static int | updatecdr = 0 |
static char | urlprefix [AST_MAX_BUF] = "" |
static int | wrapuptime |
Definition in file chan_agent.c.
#define AST_MAX_AGENT 80 |
Agent ID or Password max length
Definition at line 210 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().
#define AST_MAX_BUF 256 |
Definition at line 211 of file chan_agent.c.
Referenced by __agent_start_monitoring(), agentmonitoroutgoing_exec(), agents_show(), and agents_show_online().
#define AST_MAX_FILENAME_LEN 256 |
#define CHECK_FORMATS | ( | ast, | |||
p | ) |
#define CLEANUP | ( | ast, | |||
p | ) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
Definition at line 320 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
#define DATA_EXPORT_AGENT | ( | MEMBER | ) |
Definition at line 283 of file chan_agent.c.
#define DEFAULT_ACCEPTDTMF '#' |
Definition at line 217 of file chan_agent.c.
#define DEFAULT_ENDDTMF '*' |
Definition at line 218 of file chan_agent.c.
#define GETAGENTBYCALLERID "AGENTBYCALLERID" |
#define PA_MAX_LEN 2048 |
The maximum length of each persistent member agent database entry
Definition at line 215 of file chan_agent.c.
anonymous enum |
AGENT_FLAG_ACKCALL | |
AGENT_FLAG_AUTOLOGOFF | |
AGENT_FLAG_WRAPUPTIME | |
AGENT_FLAG_ACCEPTDTMF | |
AGENT_FLAG_ENDDTMF |
Definition at line 243 of file chan_agent.c.
00243 { 00244 AGENT_FLAG_ACKCALL = (1 << 0), 00245 AGENT_FLAG_AUTOLOGOFF = (1 << 1), 00246 AGENT_FLAG_WRAPUPTIME = (1 << 2), 00247 AGENT_FLAG_ACCEPTDTMF = (1 << 3), 00248 AGENT_FLAG_ENDDTMF = (1 << 4), 00249 };
static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
struct agent_pvt * | p, | |||
int | needlock | |||
) | [static] |
Definition at line 514 of file chan_agent.c.
References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose, ast_channel::cdr, LOG_ERROR, ast_channel::monitor, ast_channel::uniqueid, X_REC_IN, and X_REC_OUT.
Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().
00515 { 00516 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00517 char filename[AST_MAX_BUF]; 00518 int res = -1; 00519 if (!p) 00520 return -1; 00521 if (!ast->monitor) { 00522 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00523 /* substitute . for - */ 00524 if ((pointer = strchr(filename, '.'))) 00525 *pointer = '-'; 00526 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00527 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT); 00528 ast_monitor_setjoinfiles(ast, 1); 00529 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00530 #if 0 00531 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00532 #endif 00533 if (!ast->cdr) 00534 ast->cdr = ast_cdr_alloc(); 00535 ast_cdr_setuserfield(ast, tmp2); 00536 res = 0; 00537 } else 00538 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00539 return res; 00540 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 2489 of file chan_agent.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2489 of file chan_agent.c.
static int action_agent_logoff | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Sets an agent as no longer logged in in the Manager API. It is registered on load_module() and it gets called by the manager backend.
s | ||
m |
Definition at line 1632 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
01633 { 01634 const char *agent = astman_get_header(m, "Agent"); 01635 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01636 int soft; 01637 int ret; /* return value of agent_logoff */ 01638 01639 if (ast_strlen_zero(agent)) { 01640 astman_send_error(s, m, "No agent specified"); 01641 return 0; 01642 } 01643 01644 soft = ast_true(soft_s) ? 1 : 0; 01645 ret = agent_logoff(agent, soft); 01646 if (ret == 0) 01647 astman_send_ack(s, m, "Agent logged out"); 01648 else 01649 astman_send_error(s, m, "No such agent"); 01650 01651 return 0; 01652 }
static int action_agents | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.
s | ||
m |
Definition at line 1482 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::agent, ast_bridged_channel(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, agent_pvt::chan, ast_party_caller::id, agent_pvt::list, agent_pvt::lock, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, ast_party_id::number, agent_pvt::owner, S_COR, S_OR, status, ast_party_number::str, and ast_party_number::valid.
Referenced by load_module().
01483 { 01484 const char *id = astman_get_header(m,"ActionID"); 01485 char idText[256] = ""; 01486 struct agent_pvt *p; 01487 char *username = NULL; 01488 char *loginChan = NULL; 01489 char *talkingto = NULL; 01490 char *talkingtoChan = NULL; 01491 char *status = NULL; 01492 01493 if (!ast_strlen_zero(id)) 01494 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01495 astman_send_ack(s, m, "Agents will follow"); 01496 AST_LIST_LOCK(&agents); 01497 AST_LIST_TRAVERSE(&agents, p, list) { 01498 ast_mutex_lock(&p->lock); 01499 01500 /* Status Values: 01501 AGENT_LOGGEDOFF - Agent isn't logged in 01502 AGENT_IDLE - Agent is logged in, and waiting for call 01503 AGENT_ONCALL - Agent is logged in, and on a call 01504 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01505 01506 username = S_OR(p->name, "None"); 01507 01508 /* Set a default status. It 'should' get changed. */ 01509 status = "AGENT_UNKNOWN"; 01510 01511 if (p->chan) { 01512 loginChan = ast_strdupa(p->chan->name); 01513 if (p->owner && p->owner->_bridge) { 01514 talkingto = S_COR(p->chan->caller.id.number.valid, 01515 p->chan->caller.id.number.str, "n/a"); 01516 if (ast_bridged_channel(p->owner)) 01517 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name); 01518 else 01519 talkingtoChan = "n/a"; 01520 status = "AGENT_ONCALL"; 01521 } else { 01522 talkingto = "n/a"; 01523 talkingtoChan = "n/a"; 01524 status = "AGENT_IDLE"; 01525 } 01526 } else { 01527 loginChan = "n/a"; 01528 talkingto = "n/a"; 01529 talkingtoChan = "n/a"; 01530 status = "AGENT_LOGGEDOFF"; 01531 } 01532 01533 astman_append(s, "Event: Agents\r\n" 01534 "Agent: %s\r\n" 01535 "Name: %s\r\n" 01536 "Status: %s\r\n" 01537 "LoggedInChan: %s\r\n" 01538 "LoggedInTime: %d\r\n" 01539 "TalkingTo: %s\r\n" 01540 "TalkingToChan: %s\r\n" 01541 "%s" 01542 "\r\n", 01543 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01544 ast_mutex_unlock(&p->lock); 01545 } 01546 AST_LIST_UNLOCK(&agents); 01547 astman_append(s, "Event: AgentsComplete\r\n" 01548 "%s" 01549 "\r\n",idText); 01550 return 0; 01551 }
static struct agent_pvt* add_agent | ( | const char * | agent, | |
int | pending | |||
) | [static] |
Adds an agent to the global list of agents.
agent | A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" | |
pending | If it is pending or not. |
Definition at line 384 of file chan_agent.c.
References agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::agent, AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, args, AST_APP_ARG, ast_calloc, ast_cond_init, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::enddtmf, agent_pvt::lastdisc, agent_pvt::list, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00385 { 00386 char *parse; 00387 AST_DECLARE_APP_ARGS(args, 00388 AST_APP_ARG(agt); 00389 AST_APP_ARG(password); 00390 AST_APP_ARG(name); 00391 ); 00392 char *password = NULL; 00393 char *name = NULL; 00394 char *agt = NULL; 00395 struct agent_pvt *p; 00396 00397 parse = ast_strdupa(agent); 00398 00399 /* Extract username (agt), password and name from agent (args). */ 00400 AST_STANDARD_APP_ARGS(args, parse); 00401 00402 if(args.argc == 0) { 00403 ast_log(LOG_WARNING, "A blank agent line!\n"); 00404 return NULL; 00405 } 00406 00407 if(ast_strlen_zero(args.agt) ) { 00408 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00409 return NULL; 00410 } else 00411 agt = args.agt; 00412 00413 if(!ast_strlen_zero(args.password)) { 00414 password = args.password; 00415 while (*password && *password < 33) password++; 00416 } 00417 if(!ast_strlen_zero(args.name)) { 00418 name = args.name; 00419 while (*name && *name < 33) name++; 00420 } 00421 00422 /* Are we searching for the agent here ? To see if it exists already ? */ 00423 AST_LIST_TRAVERSE(&agents, p, list) { 00424 if (!pending && !strcmp(p->agent, agt)) 00425 break; 00426 } 00427 if (!p) { 00428 // Build the agent. 00429 if (!(p = ast_calloc(1, sizeof(*p)))) 00430 return NULL; 00431 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00432 ast_mutex_init(&p->lock); 00433 ast_mutex_init(&p->app_lock); 00434 ast_cond_init(&p->app_complete_cond, NULL); 00435 p->app_lock_flag = 0; 00436 p->app_sleep_cond = 1; 00437 p->group = group; 00438 p->pending = pending; 00439 AST_LIST_INSERT_TAIL(&agents, p, list); 00440 } 00441 00442 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00443 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00444 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00445 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) { 00446 p->ackcall = ackcall; 00447 } 00448 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) { 00449 p->autologoff = autologoff; 00450 } 00451 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) { 00452 p->acceptdtmf = acceptdtmf; 00453 } 00454 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) { 00455 p->enddtmf = enddtmf; 00456 } 00457 00458 /* If someone reduces the wrapuptime and reloads, we want it 00459 * to change the wrapuptime immediately on all calls */ 00460 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) { 00461 struct timeval now = ast_tvnow(); 00462 /* XXX check what is this exactly */ 00463 00464 /* We won't be pedantic and check the tv_usec val */ 00465 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00466 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00467 p->lastdisc.tv_usec = now.tv_usec; 00468 } 00469 } 00470 p->wrapuptime = wrapuptime; 00471 00472 if (pending) 00473 p->dead = 1; 00474 else 00475 p->dead = 0; 00476 return p; 00477 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 971 of file chan_agent.c.
References agent_pvt::acceptdtmf, agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_waitfor(), agent_pvt::chan, f, and agent_pvt::lock.
Referenced by login_exec().
00972 { 00973 struct agent_pvt *p; 00974 int res=0; 00975 int to = 1000; 00976 struct ast_frame *f; 00977 00978 /* Wait a second and look for something */ 00979 00980 p = (struct agent_pvt *) data; 00981 if (!p->chan) 00982 return -1; 00983 00984 for(;;) { 00985 to = ast_waitfor(p->chan, to); 00986 if (to < 0) 00987 return -1; 00988 if (!to) 00989 return 0; 00990 f = ast_read(p->chan); 00991 if (!f) 00992 return -1; 00993 if (f->frametype == AST_FRAME_DTMF) 00994 res = f->subclass.integer; 00995 else 00996 res = 0; 00997 ast_frfree(f); 00998 ast_mutex_lock(&p->lock); 00999 if (!p->app_sleep_cond) { 01000 ast_mutex_unlock(&p->lock); 01001 return 0; 01002 } else if (res == p->acceptdtmf) { 01003 ast_mutex_unlock(&p->lock); 01004 return 1; 01005 } 01006 ast_mutex_unlock(&p->lock); 01007 res = 0; 01008 } 01009 return res; 01010 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 508 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00509 { 00510 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00511 return -1; 00512 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Definition at line 1012 of file chan_agent.c.
References ast_debug, ast_channel::bridge, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.
01013 { 01014 struct agent_pvt *p = bridge->tech_pvt; 01015 struct ast_channel *ret = NULL; 01016 01017 if (p) { 01018 if (chan == p->chan) 01019 ret = bridge->_bridge; 01020 else if (chan == bridge->_bridge) 01021 ret = p->chan; 01022 } 01023 01024 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 01025 return ret; 01026 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 772 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_best_codec(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_verb, ast_waitstream(), agent_pvt::chan, CLEANUP, ast_channel::language, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.
00773 { 00774 struct agent_pvt *p = ast->tech_pvt; 00775 int res = -1; 00776 int newstate=0; 00777 ast_mutex_lock(&p->lock); 00778 p->acknowledged = 0; 00779 if (!p->chan) { 00780 if (p->pending) { 00781 ast_debug(1, "Pretending to dial on pending agent\n"); 00782 newstate = AST_STATE_DIALING; 00783 res = 0; 00784 } else { 00785 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00786 res = -1; 00787 } 00788 ast_mutex_unlock(&p->lock); 00789 if (newstate) 00790 ast_setstate(ast, newstate); 00791 return res; 00792 } 00793 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00794 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language); 00795 res = ast_streamfile(p->chan, beep, p->chan->language); 00796 ast_debug(3, "Played beep, result '%d'\n", res); 00797 if (!res) { 00798 res = ast_waitstream(p->chan, ""); 00799 ast_debug(3, "Waited for stream, result '%d'\n", res); 00800 } 00801 if (!res) { 00802 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00803 ast_debug(3, "Set read format, result '%d'\n", res); 00804 if (res) 00805 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00806 } else { 00807 /* Agent hung-up */ 00808 p->chan = NULL; 00809 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00810 } 00811 00812 if (!res) { 00813 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00814 ast_debug(3, "Set write format, result '%d'\n", res); 00815 if (res) 00816 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00817 } 00818 if(!res) { 00819 /* Call is immediately up, or might need ack */ 00820 if (p->ackcall) { 00821 newstate = AST_STATE_RINGING; 00822 } else { 00823 newstate = AST_STATE_UP; 00824 if (recordagentcalls) 00825 agent_start_monitoring(ast, 0); 00826 p->acknowledged = 1; 00827 } 00828 res = 0; 00829 } 00830 CLEANUP(ast, p); 00831 ast_mutex_unlock(&p->lock); 00832 if (newstate) 00833 ast_setstate(ast, newstate); 00834 return res; 00835 }
static int agent_cleanup | ( | struct agent_pvt * | p | ) | [static] |
Deletes an agent after doing some clean up. Further documentation: How safe is this function ? What state should the agent be to be cleaned.
p | Agent to be deleted. |
Definition at line 485 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_release(), ast_cond_destroy, ast_cond_signal, ast_free, ast_mutex_destroy, agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00486 { 00487 struct ast_channel *chan = p->owner; 00488 p->owner = NULL; 00489 chan->tech_pvt = NULL; 00490 p->app_sleep_cond = 1; 00491 /* Release ownership of the agent to other threads (presumably running the login app). */ 00492 p->app_lock_flag = 0; 00493 ast_cond_signal(&p->app_complete_cond); 00494 if (chan) { 00495 chan = ast_channel_release(chan); 00496 } 00497 if (p->dead) { 00498 ast_mutex_destroy(&p->lock); 00499 ast_mutex_destroy(&p->app_lock); 00500 ast_cond_destroy(&p->app_complete_cond); 00501 ast_free(p); 00502 } 00503 return 0; 00504 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 950 of file chan_agent.c.
References agent_pvt::app_sleep_cond, ast_debug, ast_mutex_lock, ast_mutex_unlock, ast_tvdiff_ms(), ast_tvnow(), agent_pvt::lastdisc, and agent_pvt::lock.
Referenced by login_exec().
00951 { 00952 struct agent_pvt *p; 00953 int res; 00954 00955 p = (struct agent_pvt *)data; 00956 00957 ast_mutex_lock(&p->lock); 00958 res = p->app_sleep_cond; 00959 if (p->lastdisc.tv_sec) { 00960 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 00961 res = 1; 00962 } 00963 ast_mutex_unlock(&p->lock); 00964 00965 if (!res) 00966 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 00967 00968 return res; 00969 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2211 of file chan_agent.c.
References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::group, agent_pvt::list, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.
02212 { 02213 struct agent_pvt *p; 02214 char *s; 02215 ast_group_t groupmatch; 02216 int groupoff; 02217 int res = AST_DEVICE_INVALID; 02218 02219 s = data; 02220 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) 02221 groupmatch = (1 << groupoff); 02222 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02223 groupmatch = (1 << groupoff); 02224 } else 02225 groupmatch = 0; 02226 02227 /* Check actual logged in agents first */ 02228 AST_LIST_LOCK(&agents); 02229 AST_LIST_TRAVERSE(&agents, p, list) { 02230 ast_mutex_lock(&p->lock); 02231 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02232 if (p->owner) { 02233 if (res != AST_DEVICE_INUSE) 02234 res = AST_DEVICE_BUSY; 02235 } else { 02236 if (res == AST_DEVICE_BUSY) 02237 res = AST_DEVICE_INUSE; 02238 if (p->chan) { 02239 if (res == AST_DEVICE_INVALID) 02240 res = AST_DEVICE_UNKNOWN; 02241 } else if (res == AST_DEVICE_INVALID) 02242 res = AST_DEVICE_UNAVAILABLE; 02243 } 02244 if (!strcmp(data, p->agent)) { 02245 ast_mutex_unlock(&p->lock); 02246 break; 02247 } 02248 } 02249 ast_mutex_unlock(&p->lock); 02250 } 02251 AST_LIST_UNLOCK(&agents); 02252 return res; 02253 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 750 of file chan_agent.c.
References ast_mutex_lock, ast_mutex_unlock, ast_senddigit_begin(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00751 { 00752 struct agent_pvt *p = ast->tech_pvt; 00753 ast_mutex_lock(&p->lock); 00754 if (p->chan) { 00755 ast_senddigit_begin(p->chan, digit); 00756 } 00757 ast_mutex_unlock(&p->lock); 00758 return 0; 00759 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 761 of file chan_agent.c.
References ast_mutex_lock, ast_mutex_unlock, ast_senddigit_end(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00762 { 00763 struct agent_pvt *p = ast->tech_pvt; 00764 ast_mutex_lock(&p->lock); 00765 if (p->chan) { 00766 ast_senddigit_end(p->chan, digit, duration); 00767 } 00768 ast_mutex_unlock(&p->lock); 00769 return 0; 00770 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 712 of file chan_agent.c.
References ast_log(), ast_mutex_lock, ast_mutex_unlock, agent_pvt::lock, LOG_WARNING, agent_pvt::owner, and ast_channel::tech_pvt.
00713 { 00714 struct agent_pvt *p = newchan->tech_pvt; 00715 ast_mutex_lock(&p->lock); 00716 if (p->owner != oldchan) { 00717 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00718 ast_mutex_unlock(&p->lock); 00719 return -1; 00720 } 00721 p->owner = newchan; 00722 ast_mutex_unlock(&p->lock); 00723 return 0; 00724 }
struct ast_channel * agent_get_base_channel | ( | struct ast_channel * | chan | ) | [static] |
return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
Definition at line 838 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00839 { 00840 struct agent_pvt *p = NULL; 00841 struct ast_channel *base = chan; 00842 00843 /* chan is locked by the calling function */ 00844 if (!chan || !chan->tech_pvt) { 00845 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL); 00846 return NULL; 00847 } 00848 p = chan->tech_pvt; 00849 if (p->chan) 00850 base = p->chan; 00851 return base; 00852 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 871 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_signal, AST_CONTROL_HOLD, ast_debug, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), ast_free, ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), ast_tvnow(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, agent_pvt::logincallerid, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::owner, agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.
00872 { 00873 struct agent_pvt *p = ast->tech_pvt; 00874 int howlong = 0; 00875 00876 ast_mutex_lock(&p->lock); 00877 p->owner = NULL; 00878 ast->tech_pvt = NULL; 00879 p->app_sleep_cond = 1; 00880 p->acknowledged = 0; 00881 00882 /* if they really are hung up then set start to 0 so the test 00883 * later if we're called on an already downed channel 00884 * doesn't cause an agent to be logged out like when 00885 * agent_request() is followed immediately by agent_hangup() 00886 * as in apps/app_chanisavail.c:chanavail_exec() 00887 */ 00888 00889 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00890 if (p->start && (ast->_state != AST_STATE_UP)) { 00891 howlong = time(NULL) - p->start; 00892 p->start = 0; 00893 } else if (ast->_state == AST_STATE_RESERVED) 00894 howlong = 0; 00895 else 00896 p->start = 0; 00897 if (p->chan) { 00898 p->chan->_bridge = NULL; 00899 /* If they're dead, go ahead and hang up on the agent now */ 00900 if (p->dead) { 00901 ast_channel_lock(p->chan); 00902 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00903 ast_channel_unlock(p->chan); 00904 } else if (p->loginstart) { 00905 ast_channel_lock(p->chan); 00906 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00907 S_OR(p->moh, NULL), 00908 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00909 ast_channel_unlock(p->chan); 00910 } 00911 } 00912 ast_mutex_unlock(&p->lock); 00913 00914 /* Only register a device state change if the agent is still logged in */ 00915 if (!p->loginstart) { 00916 p->logincallerid[0] = '\0'; 00917 } else { 00918 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00919 } 00920 00921 if (p->pending) { 00922 AST_LIST_LOCK(&agents); 00923 AST_LIST_REMOVE(&agents, p, list); 00924 AST_LIST_UNLOCK(&agents); 00925 } 00926 if (p->abouttograb) { 00927 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00928 kill it later */ 00929 p->abouttograb = 0; 00930 } else if (p->dead) { 00931 ast_mutex_destroy(&p->lock); 00932 ast_mutex_destroy(&p->app_lock); 00933 ast_cond_destroy(&p->app_complete_cond); 00934 ast_free(p); 00935 } else { 00936 if (p->chan) { 00937 /* Not dead -- check availability now */ 00938 ast_mutex_lock(&p->lock); 00939 /* Store last disconnect time */ 00940 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00941 ast_mutex_unlock(&p->lock); 00942 } 00943 /* Release ownership of the agent to other threads (presumably running the login app). */ 00944 p->app_lock_flag = 0; 00945 ast_cond_signal(&p->app_complete_cond); 00946 } 00947 return 0; 00948 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 726 of file chan_agent.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_log(), ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, LOG_ERROR, ast_channel::tech, and ast_channel::tech_pvt.
00727 { 00728 struct agent_pvt *p = ast->tech_pvt; 00729 int res = -1; 00730 ast_mutex_lock(&p->lock); 00731 if (p->chan && !ast_check_hangup(p->chan)) { 00732 while (ast_channel_trylock(p->chan)) { 00733 int res; 00734 if ((res = ast_channel_unlock(ast))) { 00735 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res)); 00736 ast_mutex_unlock(&p->lock); 00737 return -1; 00738 } 00739 usleep(1); 00740 ast_channel_lock(ast); 00741 } 00742 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00743 ast_channel_unlock(p->chan); 00744 } else 00745 res = 0; 00746 ast_mutex_unlock(&p->lock); 00747 return res; 00748 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1553 of file chan_agent.c.
References agent_pvt::agent, ast_channel_trylock, ast_channel_unlock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, DEADLOCK_AVOIDANCE, agent_pvt::deferlogoff, agent_pvt::list, agent_pvt::lock, and agent_pvt::owner.
Referenced by action_agent_logoff(), and agent_logoff_cmd().
01554 { 01555 struct agent_pvt *p; 01556 int ret = -1; /* Return -1 if no agent if found */ 01557 01558 AST_LIST_LOCK(&agents); 01559 AST_LIST_TRAVERSE(&agents, p, list) { 01560 if (!strcasecmp(p->agent, agent)) { 01561 ret = 0; 01562 if (p->owner || p->chan) { 01563 if (!soft) { 01564 ast_mutex_lock(&p->lock); 01565 01566 while (p->owner && ast_channel_trylock(p->owner)) { 01567 DEADLOCK_AVOIDANCE(&p->lock); 01568 } 01569 if (p->owner) { 01570 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01571 ast_channel_unlock(p->owner); 01572 } 01573 01574 while (p->chan && ast_channel_trylock(p->chan)) { 01575 DEADLOCK_AVOIDANCE(&p->lock); 01576 } 01577 if (p->chan) { 01578 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01579 ast_channel_unlock(p->chan); 01580 } 01581 01582 ast_mutex_unlock(&p->lock); 01583 } else 01584 p->deferlogoff = 1; 01585 } 01586 break; 01587 } 01588 } 01589 AST_LIST_UNLOCK(&agents); 01590 01591 return ret; 01592 }
static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1594 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_agent_logoff_cmd(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
01595 { 01596 int ret; 01597 const char *agent; 01598 01599 switch (cmd) { 01600 case CLI_INIT: 01601 e->command = "agent logoff"; 01602 e->usage = 01603 "Usage: agent logoff <channel> [soft]\n" 01604 " Sets an agent as no longer logged in.\n" 01605 " If 'soft' is specified, do not hangup existing calls.\n"; 01606 return NULL; 01607 case CLI_GENERATE: 01608 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01609 } 01610 01611 if (a->argc < 3 || a->argc > 4) 01612 return CLI_SHOWUSAGE; 01613 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01614 return CLI_SHOWUSAGE; 01615 01616 agent = a->argv[2] + 6; 01617 ret = agent_logoff(agent, a->argc == 4); 01618 if (ret == 0) 01619 ast_cli(a->fd, "Logging out %s\n", agent); 01620 01621 return CLI_SUCCESS; 01622 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state, | |||
const char * | linkedid | |||
) | [static] |
Create new agent channel.
Definition at line 1029 of file chan_agent.c.
References agent_pvt::agent, agent_tech, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_alloc, ast_channel_release(), ast_cond_signal, AST_CONTROL_UNHOLD, ast_copy_string(), AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.
Referenced by agent_request(), and check_availability().
01030 { 01031 struct ast_channel *tmp; 01032 int alreadylocked; 01033 #if 0 01034 if (!p->chan) { 01035 ast_log(LOG_WARNING, "No channel? :(\n"); 01036 return NULL; 01037 } 01038 #endif 01039 if (p->pending) 01040 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff); 01041 else 01042 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent); 01043 if (!tmp) { 01044 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01045 return NULL; 01046 } 01047 01048 tmp->tech = &agent_tech; 01049 if (p->chan) { 01050 tmp->nativeformats = p->chan->nativeformats; 01051 tmp->writeformat = p->chan->writeformat; 01052 tmp->rawwriteformat = p->chan->writeformat; 01053 tmp->readformat = p->chan->readformat; 01054 tmp->rawreadformat = p->chan->readformat; 01055 ast_string_field_set(tmp, language, p->chan->language); 01056 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01057 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01058 /* XXX Is this really all we copy form the originating channel?? */ 01059 } else { 01060 tmp->nativeformats = AST_FORMAT_SLINEAR; 01061 tmp->writeformat = AST_FORMAT_SLINEAR; 01062 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01063 tmp->readformat = AST_FORMAT_SLINEAR; 01064 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01065 } 01066 /* Safe, agentlock already held */ 01067 tmp->tech_pvt = p; 01068 p->owner = tmp; 01069 tmp->priority = 1; 01070 /* Wake up and wait for other applications (by definition the login app) 01071 * to release this channel). Takes ownership of the agent channel 01072 * to this thread only. 01073 * For signalling the other thread, ast_queue_frame is used until we 01074 * can safely use signals for this purpose. The pselect() needs to be 01075 * implemented in the kernel for this. 01076 */ 01077 p->app_sleep_cond = 0; 01078 01079 alreadylocked = p->app_lock_flag; 01080 p->app_lock_flag = 1; 01081 01082 if (alreadylocked) { 01083 if (p->chan) { 01084 ast_queue_frame(p->chan, &ast_null_frame); 01085 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01086 p->app_lock_flag = 1; 01087 ast_mutex_lock(&p->lock); 01088 } else { 01089 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01090 p->owner = NULL; 01091 tmp->tech_pvt = NULL; 01092 p->app_sleep_cond = 1; 01093 tmp = ast_channel_release(tmp); 01094 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01095 p->app_lock_flag = 0; 01096 ast_cond_signal(&p->app_complete_cond); 01097 return NULL; 01098 } 01099 } 01100 if (p->chan) 01101 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01102 return tmp; 01103 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 547 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_ANSWER, ast_copy_flags, ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_read(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, AST_TIMING_FD, ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, agent_pvt::enddtmf, f, ast_channel::fdno, agent_pvt::lock, LOG_NOTICE, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::start, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.
00548 { 00549 struct agent_pvt *p = ast->tech_pvt; 00550 struct ast_frame *f = NULL; 00551 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; 00552 int cur_time = time(NULL); 00553 ast_mutex_lock(&p->lock); 00554 CHECK_FORMATS(ast, p); 00555 if (!p->start) { 00556 p->start = cur_time; 00557 } 00558 if (p->chan) { 00559 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00560 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00561 f = ast_read(p->chan); 00562 } else 00563 f = &ast_null_frame; 00564 if (!f) { 00565 /* If there's a channel, make it NULL */ 00566 if (p->chan) { 00567 p->chan->_bridge = NULL; 00568 p->chan = NULL; 00569 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00570 p->acknowledged = 0; 00571 } 00572 } else { 00573 /* if acknowledgement is not required, and the channel is up, we may have missed 00574 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00575 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00576 p->acknowledged = 1; 00577 } 00578 00579 if (!p->acknowledged) { 00580 int howlong = cur_time - p->start; 00581 if (p->autologoff && (howlong >= p->autologoff)) { 00582 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00583 if (p->owner || p->chan) { 00584 while (p->owner && ast_channel_trylock(p->owner)) { 00585 DEADLOCK_AVOIDANCE(&p->lock); 00586 } 00587 if (p->owner) { 00588 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 00589 ast_channel_unlock(p->owner); 00590 } 00591 00592 while (p->chan && ast_channel_trylock(p->chan)) { 00593 DEADLOCK_AVOIDANCE(&p->lock); 00594 } 00595 if (p->chan) { 00596 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00597 ast_channel_unlock(p->chan); 00598 } 00599 } 00600 } 00601 } 00602 switch (f->frametype) { 00603 case AST_FRAME_CONTROL: 00604 if (f->subclass.integer == AST_CONTROL_ANSWER) { 00605 if (p->ackcall) { 00606 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); 00607 /* Don't pass answer along */ 00608 ast_frfree(f); 00609 f = &ast_null_frame; 00610 } else { 00611 p->acknowledged = 1; 00612 /* Use the builtin answer frame for the 00613 recording start check below. */ 00614 ast_frfree(f); 00615 f = &answer_frame; 00616 } 00617 } 00618 break; 00619 case AST_FRAME_DTMF_BEGIN: 00620 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00621 if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){ 00622 ast_frfree(f); 00623 f = &ast_null_frame; 00624 } 00625 break; 00626 case AST_FRAME_DTMF_END: 00627 if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) { 00628 ast_verb(3, "%s acknowledged\n", p->chan->name); 00629 p->acknowledged = 1; 00630 ast_frfree(f); 00631 f = &answer_frame; 00632 } else if (f->subclass.integer == p->enddtmf && endcall) { 00633 /* terminates call */ 00634 ast_frfree(f); 00635 f = NULL; 00636 } 00637 break; 00638 case AST_FRAME_VOICE: 00639 case AST_FRAME_VIDEO: 00640 /* don't pass voice or video until the call is acknowledged */ 00641 if (!p->acknowledged) { 00642 ast_frfree(f); 00643 f = &ast_null_frame; 00644 } 00645 default: 00646 /* pass everything else on through */ 00647 break; 00648 } 00649 } 00650 00651 CLEANUP(ast,p); 00652 if (p->chan && !p->chan->_bridge) { 00653 if (strcasecmp(p->chan->tech->type, "Local")) { 00654 p->chan->_bridge = ast; 00655 if (p->chan) 00656 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00657 } 00658 } 00659 ast_mutex_unlock(&p->lock); 00660 if (recordagentcalls && f == &answer_frame) 00661 agent_start_monitoring(ast,0); 00662 return f; 00663 }
static struct ast_channel * agent_request | ( | const char * | type, | |
format_t | format, | |||
const struct ast_channel * | requestor, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of the Asterisk PBX interface.
Definition at line 1377 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_STATE_DOWN, ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, ast_channel::linkedid, agent_pvt::list, agent_pvt::lock, LOG_WARNING, agent_pvt::owner, and agent_pvt::pending.
01378 { 01379 struct agent_pvt *p; 01380 struct ast_channel *chan = NULL; 01381 char *s; 01382 ast_group_t groupmatch; 01383 int groupoff; 01384 int waitforagent=0; 01385 int hasagent = 0; 01386 struct timeval now; 01387 01388 s = data; 01389 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01390 groupmatch = (1 << groupoff); 01391 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01392 groupmatch = (1 << groupoff); 01393 waitforagent = 1; 01394 } else 01395 groupmatch = 0; 01396 01397 /* Check actual logged in agents first */ 01398 AST_LIST_LOCK(&agents); 01399 AST_LIST_TRAVERSE(&agents, p, list) { 01400 ast_mutex_lock(&p->lock); 01401 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01402 if (p->chan) 01403 hasagent++; 01404 now = ast_tvnow(); 01405 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01406 p->lastdisc = ast_tv(0, 0); 01407 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01408 if (!p->owner && p->chan) { 01409 /* Fixed agent */ 01410 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01411 } 01412 if (chan) { 01413 ast_mutex_unlock(&p->lock); 01414 break; 01415 } 01416 } 01417 } 01418 ast_mutex_unlock(&p->lock); 01419 } 01420 if (!p) { 01421 AST_LIST_TRAVERSE(&agents, p, list) { 01422 ast_mutex_lock(&p->lock); 01423 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01424 if (p->chan) { 01425 hasagent++; 01426 } 01427 now = ast_tvnow(); 01428 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01429 p->lastdisc = ast_tv(0, 0); 01430 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01431 if (!p->owner && p->chan) { 01432 /* Could still get a fixed agent */ 01433 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01434 } 01435 if (chan) { 01436 ast_mutex_unlock(&p->lock); 01437 break; 01438 } 01439 } 01440 } 01441 ast_mutex_unlock(&p->lock); 01442 } 01443 } 01444 01445 if (!chan && waitforagent) { 01446 /* No agent available -- but we're requesting to wait for one. 01447 Allocate a place holder */ 01448 if (hasagent) { 01449 ast_debug(1, "Creating place holder for '%s'\n", s); 01450 p = add_agent(data, 1); 01451 p->group = groupmatch; 01452 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01453 if (!chan) 01454 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01455 } else { 01456 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01457 } 01458 } 01459 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01460 AST_LIST_UNLOCK(&agents); 01461 return chan; 01462 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 665 of file chan_agent.c.
References ast_channel_sendhtml(), ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00666 { 00667 struct agent_pvt *p = ast->tech_pvt; 00668 int res = -1; 00669 ast_mutex_lock(&p->lock); 00670 if (p->chan) 00671 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00672 ast_mutex_unlock(&p->lock); 00673 return res; 00674 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 676 of file chan_agent.c.
References ast_mutex_lock, ast_mutex_unlock, ast_sendtext(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00677 { 00678 struct agent_pvt *p = ast->tech_pvt; 00679 int res = -1; 00680 ast_mutex_lock(&p->lock); 00681 if (p->chan) 00682 res = ast_sendtext(p->chan, text); 00683 ast_mutex_unlock(&p->lock); 00684 return res; 00685 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 854 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.
00855 { 00856 struct agent_pvt *p = NULL; 00857 00858 if (!chan || !base) { 00859 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00860 return -1; 00861 } 00862 p = chan->tech_pvt; 00863 if (!p) { 00864 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00865 return -1; 00866 } 00867 p->chan = base; 00868 return 0; 00869 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 542 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00543 { 00544 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00545 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 687 of file chan_agent.c.
References ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock, ast_mutex_unlock, ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, f, agent_pvt::lock, ast_channel::name, ast_channel::tech_pvt, and ast_channel::writeformat.
00688 { 00689 struct agent_pvt *p = ast->tech_pvt; 00690 int res = -1; 00691 CHECK_FORMATS(ast, p); 00692 ast_mutex_lock(&p->lock); 00693 if (!p->chan) 00694 res = 0; 00695 else { 00696 if ((f->frametype != AST_FRAME_VOICE) || 00697 (f->frametype != AST_FRAME_VIDEO) || 00698 (f->subclass.codec == p->chan->writeformat)) { 00699 res = ast_write(p->chan, f); 00700 } else { 00701 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00702 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00703 ast->name, p->chan->name); 00704 res = 0; 00705 } 00706 } 00707 CLEANUP(ast, p); 00708 ast_mutex_unlock(&p->lock); 00709 return res; 00710 }
static int agentmonitoroutgoing_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Called by the AgentMonitorOutgoing application (from the dial plan).
chan | ||
data |
Definition at line 2158 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_strlen_zero(), ast_channel::caller, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, GETAGENTBYCALLERID, ast_party_caller::id, agent_pvt::list, LOG_WARNING, ast_party_id::number, pbx_builtin_getvar_helper(), ast_party_number::str, and ast_party_number::valid.
Referenced by load_module().
02159 { 02160 int exitifnoagentid = 0; 02161 int nowarnings = 0; 02162 int changeoutgoing = 0; 02163 int res = 0; 02164 char agent[AST_MAX_AGENT]; 02165 02166 if (data) { 02167 if (strchr(data, 'd')) 02168 exitifnoagentid = 1; 02169 if (strchr(data, 'n')) 02170 nowarnings = 1; 02171 if (strchr(data, 'c')) 02172 changeoutgoing = 1; 02173 } 02174 if (chan->caller.id.number.valid 02175 && !ast_strlen_zero(chan->caller.id.number.str)) { 02176 const char *tmp; 02177 char agentvar[AST_MAX_BUF]; 02178 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, 02179 chan->caller.id.number.str); 02180 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02181 struct agent_pvt *p; 02182 ast_copy_string(agent, tmp, sizeof(agent)); 02183 AST_LIST_LOCK(&agents); 02184 AST_LIST_TRAVERSE(&agents, p, list) { 02185 if (!strcasecmp(p->agent, tmp)) { 02186 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02187 __agent_start_monitoring(chan, p, 1); 02188 break; 02189 } 02190 } 02191 AST_LIST_UNLOCK(&agents); 02192 02193 } else { 02194 res = -1; 02195 if (!nowarnings) 02196 ast_log(LOG_WARNING, "Couldn't find the global variable %s, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n", agentvar); 02197 } 02198 } else { 02199 res = -1; 02200 if (!nowarnings) 02201 ast_log(LOG_WARNING, "There is no callerid on that call, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n"); 02202 } 02203 if (res) { 02204 if (exitifnoagentid) 02205 return res; 02206 } 02207 return 0; 02208 }
static int agents_data_provider_get | ( | const struct ast_data_search * | search, | |
struct ast_data * | data_root | |||
) | [static] |
Definition at line 2349 of file chan_agent.c.
References agent_pvt::agent, ast_bridged_channel(), ast_channel_data_add_structure(), ast_data_add_bool(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::list, agent_pvt::lock, agent_pvt::moh, agent_pvt::owner, and agent_pvt::pending.
02351 { 02352 struct agent_pvt *p; 02353 struct ast_data *data_agent, *data_channel, *data_talkingto; 02354 02355 AST_LIST_LOCK(&agents); 02356 AST_LIST_TRAVERSE(&agents, p, list) { 02357 data_agent = ast_data_add_node(data_root, "agent"); 02358 if (!data_agent) { 02359 continue; 02360 } 02361 02362 ast_mutex_lock(&p->lock); 02363 if (!(p->pending)) { 02364 ast_data_add_str(data_agent, "id", p->agent); 02365 ast_data_add_structure(agent_pvt, data_agent, p); 02366 02367 ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0); 02368 if (p->chan) { 02369 data_channel = ast_data_add_node(data_agent, "loggedon"); 02370 if (!data_channel) { 02371 ast_mutex_unlock(&p->lock); 02372 ast_data_remove_node(data_root, data_agent); 02373 continue; 02374 } 02375 ast_channel_data_add_structure(data_channel, p->chan, 0); 02376 if (p->owner && ast_bridged_channel(p->owner)) { 02377 data_talkingto = ast_data_add_node(data_agent, "talkingto"); 02378 if (!data_talkingto) { 02379 ast_mutex_unlock(&p->lock); 02380 ast_data_remove_node(data_root, data_agent); 02381 continue; 02382 } 02383 ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(p->owner), 0); 02384 } 02385 } else { 02386 ast_data_add_node(data_agent, "talkingto"); 02387 ast_data_add_node(data_agent, "loggedon"); 02388 } 02389 ast_data_add_str(data_agent, "musiconhold", p->moh); 02390 } 02391 ast_mutex_unlock(&p->lock); 02392 02393 /* if this agent doesn't match remove the added agent. */ 02394 if (!ast_data_search_match(search, data_agent)) { 02395 ast_data_remove_node(data_root, data_agent); 02396 } 02397 } 02398 AST_LIST_UNLOCK(&agents); 02399 02400 return 0; 02401 }
static char* agents_show | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Show agents in cli.
< Number of agents configured
< Number of online agents
< Number of offline agents
Definition at line 1681 of file chan_agent.c.
References agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, count_agents(), ast_cli_args::fd, agent_pvt::group, agent_pvt::list, agent_pvt::lock, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.
01682 { 01683 struct agent_pvt *p; 01684 char username[AST_MAX_BUF]; 01685 char location[AST_MAX_BUF] = ""; 01686 char talkingto[AST_MAX_BUF] = ""; 01687 char music[AST_MAX_BUF]; 01688 int count_agents = 0; /*!< Number of agents configured */ 01689 int online_agents = 0; /*!< Number of online agents */ 01690 int offline_agents = 0; /*!< Number of offline agents */ 01691 01692 switch (cmd) { 01693 case CLI_INIT: 01694 e->command = "agent show"; 01695 e->usage = 01696 "Usage: agent show\n" 01697 " Provides summary information on agents.\n"; 01698 return NULL; 01699 case CLI_GENERATE: 01700 return NULL; 01701 } 01702 01703 if (a->argc != 2) 01704 return CLI_SHOWUSAGE; 01705 01706 AST_LIST_LOCK(&agents); 01707 AST_LIST_TRAVERSE(&agents, p, list) { 01708 ast_mutex_lock(&p->lock); 01709 if (p->pending) { 01710 if (p->group) 01711 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01712 else 01713 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01714 } else { 01715 if (!ast_strlen_zero(p->name)) 01716 snprintf(username, sizeof(username), "(%s) ", p->name); 01717 else 01718 username[0] = '\0'; 01719 if (p->chan) { 01720 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01721 if (p->owner && ast_bridged_channel(p->owner)) 01722 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01723 else 01724 strcpy(talkingto, " is idle"); 01725 online_agents++; 01726 } else { 01727 strcpy(location, "not logged in"); 01728 talkingto[0] = '\0'; 01729 offline_agents++; 01730 } 01731 if (!ast_strlen_zero(p->moh)) 01732 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01733 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01734 username, location, talkingto, music); 01735 count_agents++; 01736 } 01737 ast_mutex_unlock(&p->lock); 01738 } 01739 AST_LIST_UNLOCK(&agents); 01740 if ( !count_agents ) 01741 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01742 else 01743 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01744 ast_cli(a->fd, "\n"); 01745 01746 return CLI_SUCCESS; 01747 }
static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1750 of file chan_agent.c.
References agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, count_agents(), ast_cli_args::fd, agent_pvt::list, agent_pvt::lock, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.
01751 { 01752 struct agent_pvt *p; 01753 char username[AST_MAX_BUF]; 01754 char location[AST_MAX_BUF] = ""; 01755 char talkingto[AST_MAX_BUF] = ""; 01756 char music[AST_MAX_BUF]; 01757 int count_agents = 0; /* Number of agents configured */ 01758 int online_agents = 0; /* Number of online agents */ 01759 int agent_status = 0; /* 0 means offline, 1 means online */ 01760 01761 switch (cmd) { 01762 case CLI_INIT: 01763 e->command = "agent show online"; 01764 e->usage = 01765 "Usage: agent show online\n" 01766 " Provides a list of all online agents.\n"; 01767 return NULL; 01768 case CLI_GENERATE: 01769 return NULL; 01770 } 01771 01772 if (a->argc != 3) 01773 return CLI_SHOWUSAGE; 01774 01775 AST_LIST_LOCK(&agents); 01776 AST_LIST_TRAVERSE(&agents, p, list) { 01777 agent_status = 0; /* reset it to offline */ 01778 ast_mutex_lock(&p->lock); 01779 if (!ast_strlen_zero(p->name)) 01780 snprintf(username, sizeof(username), "(%s) ", p->name); 01781 else 01782 username[0] = '\0'; 01783 if (p->chan) { 01784 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01785 if (p->owner && ast_bridged_channel(p->owner)) 01786 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01787 else 01788 strcpy(talkingto, " is idle"); 01789 agent_status = 1; 01790 online_agents++; 01791 } 01792 if (!ast_strlen_zero(p->moh)) 01793 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01794 if (agent_status) 01795 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01796 count_agents++; 01797 ast_mutex_unlock(&p->lock); 01798 } 01799 AST_LIST_UNLOCK(&agents); 01800 if (!count_agents) 01801 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01802 else 01803 ast_cli(a->fd, "%d agents online\n", online_agents); 01804 ast_cli(a->fd, "\n"); 01805 return CLI_SUCCESS; 01806 }
AST_DATA_STRUCTURE | ( | agent_pvt | , | |
DATA_EXPORT_AGENT | ||||
) |
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1275 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), ast_copy_string(), ast_debug, AST_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, ast_channel::language, ast_channel::linkedid, agent_pvt::list, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01276 { 01277 struct ast_channel *chan=NULL, *parent=NULL; 01278 struct agent_pvt *p; 01279 int res; 01280 01281 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01282 if (needlock) 01283 AST_LIST_LOCK(&agents); 01284 AST_LIST_TRAVERSE(&agents, p, list) { 01285 if (p == newlyavailable) { 01286 continue; 01287 } 01288 ast_mutex_lock(&p->lock); 01289 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01290 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01291 /* We found a pending call, time to merge */ 01292 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL); 01293 parent = p->owner; 01294 p->abouttograb = 1; 01295 ast_mutex_unlock(&p->lock); 01296 break; 01297 } 01298 ast_mutex_unlock(&p->lock); 01299 } 01300 if (needlock) 01301 AST_LIST_UNLOCK(&agents); 01302 if (parent && chan) { 01303 if (newlyavailable->ackcall) { 01304 /* Don't do beep here */ 01305 res = 0; 01306 } else { 01307 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01308 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01309 ast_debug(3, "Played beep, result '%d'\n", res); 01310 if (!res) { 01311 res = ast_waitstream(newlyavailable->chan, ""); 01312 ast_debug(1, "Waited for stream, result '%d'\n", res); 01313 } 01314 } 01315 if (!res) { 01316 /* Note -- parent may have disappeared */ 01317 if (p->abouttograb) { 01318 newlyavailable->acknowledged = 1; 01319 /* Safe -- agent lock already held */ 01320 ast_setstate(parent, AST_STATE_UP); 01321 ast_setstate(chan, AST_STATE_UP); 01322 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01323 /* Go ahead and mark the channel as a zombie so that masquerade will 01324 destroy it for us, and we need not call ast_hangup */ 01325 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01326 ast_channel_masquerade(parent, chan); 01327 p->abouttograb = 0; 01328 } else { 01329 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01330 agent_cleanup(newlyavailable); 01331 } 01332 } else { 01333 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01334 agent_cleanup(newlyavailable); 01335 } 01336 } 01337 return 0; 01338 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1340 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::agent, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, ast_channel::language, agent_pvt::list, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01341 { 01342 struct agent_pvt *p; 01343 int res=0; 01344 01345 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01346 if (needlock) 01347 AST_LIST_LOCK(&agents); 01348 AST_LIST_TRAVERSE(&agents, p, list) { 01349 if (p == newlyavailable) { 01350 continue; 01351 } 01352 ast_mutex_lock(&p->lock); 01353 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01354 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01355 ast_mutex_unlock(&p->lock); 01356 break; 01357 } 01358 ast_mutex_unlock(&p->lock); 01359 } 01360 if (needlock) 01361 AST_LIST_UNLOCK(&agents); 01362 if (p) { 01363 ast_mutex_unlock(&newlyavailable->lock); 01364 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01365 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01366 ast_debug(1, "Played beep, result '%d'\n", res); 01367 if (!res) { 01368 res = ast_waitstream(newlyavailable->chan, ""); 01369 ast_debug(1, "Waited for stream, result '%d'\n", res); 01370 } 01371 ast_mutex_lock(&newlyavailable->lock); 01372 } 01373 return res; 01374 }
static char * complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1654 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_AGENT, ast_strdup, len(), agent_pvt::list, agent_pvt::loginstart, and agent_pvt::name.
Referenced by agent_logoff_cmd().
01655 { 01656 char *ret = NULL; 01657 01658 if (pos == 2) { 01659 struct agent_pvt *p; 01660 char name[AST_MAX_AGENT]; 01661 int which = 0, len = strlen(word); 01662 01663 AST_LIST_LOCK(&agents); 01664 AST_LIST_TRAVERSE(&agents, p, list) { 01665 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01666 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01667 ret = ast_strdup(name); 01668 break; 01669 } 01670 } 01671 AST_LIST_UNLOCK(&agents); 01672 } else if (pos == 3 && state == 0) 01673 return ast_strdup("soft"); 01674 01675 return ret; 01676 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2258 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_TRAVERSE, and agent_pvt::list.
Referenced by function_agent().
02259 { 02260 struct agent_pvt *cur; 02261 02262 AST_LIST_TRAVERSE(&agents, cur, list) { 02263 if (!strcmp(cur->agent, agentid)) 02264 break; 02265 } 02266 02267 return cur; 02268 }
static int function_agent | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2270 of file chan_agent.c.
References agent_pvt::agent, args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_agent(), LOG_WARNING, parse(), and status.
02271 { 02272 char *parse; 02273 AST_DECLARE_APP_ARGS(args, 02274 AST_APP_ARG(agentid); 02275 AST_APP_ARG(item); 02276 ); 02277 char *tmp; 02278 struct agent_pvt *agent; 02279 02280 buf[0] = '\0'; 02281 02282 if (ast_strlen_zero(data)) { 02283 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02284 return -1; 02285 } 02286 02287 parse = ast_strdupa(data); 02288 02289 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02290 if (!args.item) 02291 args.item = "status"; 02292 02293 AST_LIST_LOCK(&agents); 02294 02295 if (!(agent = find_agent(args.agentid))) { 02296 AST_LIST_UNLOCK(&agents); 02297 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02298 return -1; 02299 } 02300 02301 if (!strcasecmp(args.item, "status")) { 02302 char *status = "LOGGEDOUT"; 02303 if (agent->chan) { 02304 status = "LOGGEDIN"; 02305 } 02306 ast_copy_string(buf, status, len); 02307 } else if (!strcasecmp(args.item, "password")) 02308 ast_copy_string(buf, agent->password, len); 02309 else if (!strcasecmp(args.item, "name")) 02310 ast_copy_string(buf, agent->name, len); 02311 else if (!strcasecmp(args.item, "mohclass")) 02312 ast_copy_string(buf, agent->moh, len); 02313 else if (!strcasecmp(args.item, "channel")) { 02314 if (agent->chan) { 02315 ast_channel_lock(agent->chan); 02316 ast_copy_string(buf, agent->chan->name, len); 02317 ast_channel_unlock(agent->chan); 02318 tmp = strrchr(buf, '-'); 02319 if (tmp) 02320 *tmp = '\0'; 02321 } 02322 } else if (!strcasecmp(args.item, "fullchannel")) { 02323 if (agent->chan) { 02324 ast_channel_lock(agent->chan); 02325 ast_copy_string(buf, agent->chan->name, len); 02326 ast_channel_unlock(agent->chan); 02327 } 02328 } else if (!strcasecmp(args.item, "exten")) { 02329 buf[0] = '\0'; 02330 } 02331 02332 AST_LIST_UNLOCK(&agents); 02333 02334 return 0; 02335 }
static int load_module | ( | void | ) | [static] |
Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.
Definition at line 2419 of file chan_agent.c.
References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), agents_data_providers, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), and read_agent_config().
02420 { 02421 /* Make sure we can register our agent channel type */ 02422 if (ast_channel_register(&agent_tech)) { 02423 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02424 return AST_MODULE_LOAD_FAILURE; 02425 } 02426 /* Read in the config */ 02427 if (!read_agent_config(0)) 02428 return AST_MODULE_LOAD_DECLINE; 02429 /* Dialplan applications */ 02430 ast_register_application_xml(app, login_exec); 02431 ast_register_application_xml(app3, agentmonitoroutgoing_exec); 02432 02433 /* data tree */ 02434 ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers)); 02435 02436 /* Manager commands */ 02437 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents); 02438 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff); 02439 02440 /* CLI Commands */ 02441 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02442 02443 /* Dialplan Functions */ 02444 ast_custom_function_register(&agent_function); 02445 02446 return AST_MODULE_LOAD_SUCCESS; 02447 }
static int login_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Log in agent application.
Called by the AgentLogin application (from the dial plan).
chan | ||
data |
Definition at line 1829 of file chan_agent.c.
References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_wait, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, agent_pvt::chan, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::name, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, update_cdr, and agent_pvt::wrapuptime.
Referenced by load_module().
01830 { 01831 int res=0; 01832 int tries = 0; 01833 int max_login_tries = maxlogintries; 01834 struct agent_pvt *p; 01835 struct ast_module_user *u; 01836 int login_state = 0; 01837 char user[AST_MAX_AGENT] = ""; 01838 char pass[AST_MAX_AGENT]; 01839 char agent[AST_MAX_AGENT] = ""; 01840 char xpass[AST_MAX_AGENT] = ""; 01841 char *errmsg; 01842 char *parse; 01843 AST_DECLARE_APP_ARGS(args, 01844 AST_APP_ARG(agent_id); 01845 AST_APP_ARG(options); 01846 AST_APP_ARG(extension); 01847 ); 01848 const char *tmpoptions = NULL; 01849 int play_announcement = 1; 01850 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01851 int update_cdr = updatecdr; 01852 char *filename = "agent-loginok"; 01853 01854 u = ast_module_user_add(chan); 01855 01856 parse = ast_strdupa(data); 01857 01858 AST_STANDARD_APP_ARGS(args, parse); 01859 01860 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01861 01862 ast_channel_lock(chan); 01863 /* Set Channel Specific Login Overrides */ 01864 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01865 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01866 if (max_login_tries < 0) 01867 max_login_tries = 0; 01868 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01869 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 01870 } 01871 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01872 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01873 update_cdr = 1; 01874 else 01875 update_cdr = 0; 01876 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01877 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01878 } 01879 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01880 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01881 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01882 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01883 } 01884 ast_channel_unlock(chan); 01885 /* End Channel Specific Login Overrides */ 01886 01887 if (!ast_strlen_zero(args.options)) { 01888 if (strchr(args.options, 's')) { 01889 play_announcement = 0; 01890 } 01891 } 01892 01893 if (chan->_state != AST_STATE_UP) 01894 res = ast_answer(chan); 01895 if (!res) { 01896 if (!ast_strlen_zero(args.agent_id)) 01897 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01898 else 01899 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01900 } 01901 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01902 tries++; 01903 /* Check for password */ 01904 AST_LIST_LOCK(&agents); 01905 AST_LIST_TRAVERSE(&agents, p, list) { 01906 if (!strcmp(p->agent, user) && !p->pending) 01907 ast_copy_string(xpass, p->password, sizeof(xpass)); 01908 } 01909 AST_LIST_UNLOCK(&agents); 01910 if (!res) { 01911 if (!ast_strlen_zero(xpass)) 01912 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01913 else 01914 pass[0] = '\0'; 01915 } 01916 errmsg = "agent-incorrect"; 01917 01918 #if 0 01919 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01920 #endif 01921 01922 /* Check again for accuracy */ 01923 AST_LIST_LOCK(&agents); 01924 AST_LIST_TRAVERSE(&agents, p, list) { 01925 int unlock_channel = 1; 01926 ast_channel_lock(chan); 01927 ast_mutex_lock(&p->lock); 01928 if (!strcmp(p->agent, user) && 01929 !strcmp(p->password, pass) && !p->pending) { 01930 login_state = 1; /* Successful Login */ 01931 01932 /* Ensure we can't be gotten until we're done */ 01933 p->lastdisc = ast_tvnow(); 01934 p->lastdisc.tv_sec++; 01935 01936 /* Set Channel Specific Agent Overrides */ 01937 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01938 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01939 p->ackcall = 1; 01940 } else { 01941 p->ackcall = 0; 01942 } 01943 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01944 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 01945 ast_set_flag(p, AGENT_FLAG_ACKCALL); 01946 } else { 01947 p->ackcall = ackcall; 01948 } 01949 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01950 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01951 if (p->autologoff < 0) 01952 p->autologoff = 0; 01953 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 01954 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 01955 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 01956 } else { 01957 p->autologoff = autologoff; 01958 } 01959 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 01960 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 01961 if (p->wrapuptime < 0) 01962 p->wrapuptime = 0; 01963 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 01964 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 01965 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 01966 } else { 01967 p->wrapuptime = wrapuptime; 01968 } 01969 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF"); 01970 if (!ast_strlen_zero(tmpoptions)) { 01971 p->acceptdtmf = *tmpoptions; 01972 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 01973 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 01974 } 01975 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 01976 if (!ast_strlen_zero(tmpoptions)) { 01977 p->enddtmf = *tmpoptions; 01978 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 01979 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 01980 } 01981 ast_channel_unlock(chan); 01982 unlock_channel = 0; 01983 /* End Channel Specific Agent Overrides */ 01984 if (!p->chan) { 01985 long logintime; 01986 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01987 01988 p->logincallerid[0] = '\0'; 01989 p->acknowledged = 0; 01990 01991 ast_mutex_unlock(&p->lock); 01992 AST_LIST_UNLOCK(&agents); 01993 if( !res && play_announcement==1 ) 01994 res = ast_streamfile(chan, filename, chan->language); 01995 if (!res) 01996 ast_waitstream(chan, ""); 01997 AST_LIST_LOCK(&agents); 01998 ast_mutex_lock(&p->lock); 01999 if (!res) { 02000 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02001 if (res) 02002 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats))); 02003 } 02004 if (!res) { 02005 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02006 if (res) 02007 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats))); 02008 } 02009 /* Check once more just in case */ 02010 if (p->chan) 02011 res = -1; 02012 if (!res) { 02013 ast_indicate_data(chan, AST_CONTROL_HOLD, 02014 S_OR(p->moh, NULL), 02015 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02016 if (p->loginstart == 0) 02017 time(&p->loginstart); 02018 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02019 "Agent: %s\r\n" 02020 "Channel: %s\r\n" 02021 "Uniqueid: %s\r\n", 02022 p->agent, chan->name, chan->uniqueid); 02023 if (update_cdr && chan->cdr) 02024 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02025 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02026 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 02027 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02028 /* Login this channel and wait for it to go away */ 02029 p->chan = chan; 02030 if (p->ackcall) { 02031 check_beep(p, 0); 02032 } else { 02033 check_availability(p, 0); 02034 } 02035 ast_mutex_unlock(&p->lock); 02036 AST_LIST_UNLOCK(&agents); 02037 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02038 while (res >= 0) { 02039 ast_mutex_lock(&p->lock); 02040 if (p->deferlogoff && p->chan) { 02041 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02042 p->deferlogoff = 0; 02043 } 02044 if (p->chan != chan) 02045 res = -1; 02046 ast_mutex_unlock(&p->lock); 02047 /* Yield here so other interested threads can kick in. */ 02048 sched_yield(); 02049 if (res) 02050 break; 02051 02052 AST_LIST_LOCK(&agents); 02053 ast_mutex_lock(&p->lock); 02054 if (p->lastdisc.tv_sec) { 02055 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02056 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02057 p->lastdisc = ast_tv(0, 0); 02058 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02059 if (p->ackcall) { 02060 check_beep(p, 0); 02061 } else { 02062 check_availability(p, 0); 02063 } 02064 } 02065 } 02066 ast_mutex_unlock(&p->lock); 02067 AST_LIST_UNLOCK(&agents); 02068 /* Synchronize channel ownership between call to agent and itself. */ 02069 ast_mutex_lock(&p->app_lock); 02070 if (p->app_lock_flag == 1) { 02071 ast_cond_wait(&p->app_complete_cond, &p->app_lock); 02072 } 02073 ast_mutex_unlock(&p->app_lock); 02074 ast_mutex_lock(&p->lock); 02075 ast_mutex_unlock(&p->lock); 02076 if (p->ackcall) { 02077 res = agent_ack_sleep(p); 02078 } else { 02079 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02080 } 02081 if (p->ackcall && (res == 1)) { 02082 AST_LIST_LOCK(&agents); 02083 ast_mutex_lock(&p->lock); 02084 check_availability(p, 0); 02085 ast_mutex_unlock(&p->lock); 02086 AST_LIST_UNLOCK(&agents); 02087 res = 0; 02088 } 02089 sched_yield(); 02090 } 02091 ast_mutex_lock(&p->lock); 02092 if (res && p->owner) 02093 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02094 /* Log us off if appropriate */ 02095 if (p->chan == chan) { 02096 p->chan = NULL; 02097 } 02098 p->acknowledged = 0; 02099 logintime = time(NULL) - p->loginstart; 02100 p->loginstart = 0; 02101 ast_mutex_unlock(&p->lock); 02102 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02103 "Agent: %s\r\n" 02104 "Logintime: %ld\r\n" 02105 "Uniqueid: %s\r\n", 02106 p->agent, logintime, chan->uniqueid); 02107 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02108 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02109 /* If there is no owner, go ahead and kill it now */ 02110 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02111 if (p->dead && !p->owner) { 02112 ast_mutex_destroy(&p->lock); 02113 ast_mutex_destroy(&p->app_lock); 02114 ast_cond_destroy(&p->app_complete_cond); 02115 ast_free(p); 02116 } 02117 } 02118 else { 02119 ast_mutex_unlock(&p->lock); 02120 p = NULL; 02121 } 02122 res = -1; 02123 } else { 02124 ast_mutex_unlock(&p->lock); 02125 errmsg = "agent-alreadyon"; 02126 p = NULL; 02127 } 02128 break; 02129 } 02130 ast_mutex_unlock(&p->lock); 02131 if (unlock_channel) { 02132 ast_channel_unlock(chan); 02133 } 02134 } 02135 if (!p) 02136 AST_LIST_UNLOCK(&agents); 02137 02138 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02139 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02140 } 02141 02142 if (!res) 02143 res = ast_safe_sleep(chan, 500); 02144 02145 ast_module_user_remove(u); 02146 02147 return -1; 02148 }
static force_inline int powerof | ( | unsigned int | d | ) | [static] |
Definition at line 1464 of file chan_agent.c.
Referenced by __ast_register_translator(), agents_show(), ast_translate_available_formats(), ast_translate_path_steps(), ast_translator_build_path(), and handle_cli_core_show_translation().
static int read_agent_config | ( | int | reload | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1111 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, agent_pvt::app_lock, ast_category_browse(), ast_cond_destroy, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_get_group(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), agent_pvt::chan, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, agent_pvt::dead, agent_pvt::list, agent_pvt::lock, LOG_ERROR, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01112 { 01113 struct ast_config *cfg; 01114 struct ast_config *ucfg; 01115 struct ast_variable *v; 01116 struct agent_pvt *p; 01117 const char *catname; 01118 const char *hasagent; 01119 int genhasagent; 01120 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01121 01122 group = 0; 01123 autologoff = 0; 01124 wrapuptime = 0; 01125 ackcall = 0; 01126 endcall = 1; 01127 cfg = ast_config_load(config, config_flags); 01128 if (!cfg) { 01129 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01130 return 0; 01131 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 01132 return -1; 01133 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 01134 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config); 01135 return 0; 01136 } 01137 if ((ucfg = ast_config_load("users.conf", config_flags))) { 01138 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { 01139 ucfg = NULL; 01140 } else if (ucfg == CONFIG_STATUS_FILEINVALID) { 01141 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n"); 01142 return 0; 01143 } 01144 } 01145 01146 AST_LIST_LOCK(&agents); 01147 AST_LIST_TRAVERSE(&agents, p, list) { 01148 p->dead = 1; 01149 } 01150 strcpy(moh, "default"); 01151 /* set the default recording values */ 01152 recordagentcalls = 0; 01153 strcpy(recordformat, "wav"); 01154 strcpy(recordformatext, "wav"); 01155 urlprefix[0] = '\0'; 01156 savecallsin[0] = '\0'; 01157 01158 /* Read in [general] section for persistence */ 01159 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01160 01161 /* Read in the [agents] section */ 01162 v = ast_variable_browse(cfg, "agents"); 01163 while(v) { 01164 /* Create the interface list */ 01165 if (!strcasecmp(v->name, "agent")) { 01166 add_agent(v->value, 0); 01167 } else if (!strcasecmp(v->name, "group")) { 01168 group = ast_get_group(v->value); 01169 } else if (!strcasecmp(v->name, "autologoff")) { 01170 autologoff = atoi(v->value); 01171 if (autologoff < 0) 01172 autologoff = 0; 01173 } else if (!strcasecmp(v->name, "ackcall")) { 01174 if (ast_true(v->value) || !strcasecmp(v->value, "always")) { 01175 ackcall = 1; 01176 } 01177 } else if (!strcasecmp(v->name, "endcall")) { 01178 endcall = ast_true(v->value); 01179 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01180 acceptdtmf = *(v->value); 01181 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01182 } else if (!strcasecmp(v->name, "enddtmf")) { 01183 enddtmf = *(v->value); 01184 } else if (!strcasecmp(v->name, "wrapuptime")) { 01185 wrapuptime = atoi(v->value); 01186 if (wrapuptime < 0) 01187 wrapuptime = 0; 01188 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01189 maxlogintries = atoi(v->value); 01190 if (maxlogintries < 0) 01191 maxlogintries = 0; 01192 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01193 strcpy(agentgoodbye,v->value); 01194 } else if (!strcasecmp(v->name, "musiconhold")) { 01195 ast_copy_string(moh, v->value, sizeof(moh)); 01196 } else if (!strcasecmp(v->name, "updatecdr")) { 01197 if (ast_true(v->value)) 01198 updatecdr = 1; 01199 else 01200 updatecdr = 0; 01201 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01202 if (ast_true(v->value)) 01203 autologoffunavail = 1; 01204 else 01205 autologoffunavail = 0; 01206 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01207 recordagentcalls = ast_true(v->value); 01208 } else if (!strcasecmp(v->name, "recordformat")) { 01209 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01210 if (!strcasecmp(v->value, "wav49")) 01211 strcpy(recordformatext, "WAV"); 01212 else 01213 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01214 } else if (!strcasecmp(v->name, "urlprefix")) { 01215 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01216 if (urlprefix[strlen(urlprefix) - 1] != '/') 01217 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01218 } else if (!strcasecmp(v->name, "savecallsin")) { 01219 if (v->value[0] == '/') 01220 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01221 else 01222 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01223 if (savecallsin[strlen(savecallsin) - 1] != '/') 01224 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01225 } else if (!strcasecmp(v->name, "custom_beep")) { 01226 ast_copy_string(beep, v->value, sizeof(beep)); 01227 } 01228 v = v->next; 01229 } 01230 if (ucfg) { 01231 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01232 catname = ast_category_browse(ucfg, NULL); 01233 while(catname) { 01234 if (strcasecmp(catname, "general")) { 01235 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01236 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01237 char tmp[256]; 01238 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01239 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01240 if (!fullname) 01241 fullname = ""; 01242 if (!secret) 01243 secret = ""; 01244 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01245 add_agent(tmp, 0); 01246 } 01247 } 01248 catname = ast_category_browse(ucfg, catname); 01249 } 01250 ast_config_destroy(ucfg); 01251 } 01252 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01253 if (p->dead) { 01254 AST_LIST_REMOVE_CURRENT(list); 01255 /* Destroy if appropriate */ 01256 if (!p->owner) { 01257 if (!p->chan) { 01258 ast_mutex_destroy(&p->lock); 01259 ast_mutex_destroy(&p->app_lock); 01260 ast_cond_destroy(&p->app_complete_cond); 01261 ast_free(p); 01262 } else { 01263 /* Cause them to hang up */ 01264 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01265 } 01266 } 01267 } 01268 } 01269 AST_LIST_TRAVERSE_SAFE_END; 01270 AST_LIST_UNLOCK(&agents); 01271 ast_config_destroy(cfg); 01272 return 1; 01273 }
static int reload | ( | void | ) | [static] |
Definition at line 2449 of file chan_agent.c.
References read_agent_config().
02450 { 02451 return read_agent_config(1); 02452 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2454 of file chan_agent.c.
References agent_function, agent_tech, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_data_unregister, ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), cli_agents, agent_pvt::list, and agent_pvt::owner.
02455 { 02456 struct agent_pvt *p; 02457 /* First, take us out of the channel loop */ 02458 ast_channel_unregister(&agent_tech); 02459 /* Unregister dialplan functions */ 02460 ast_custom_function_unregister(&agent_function); 02461 /* Unregister CLI commands */ 02462 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02463 /* Unregister dialplan applications */ 02464 ast_unregister_application(app); 02465 ast_unregister_application(app3); 02466 /* Unregister manager command */ 02467 ast_manager_unregister("Agents"); 02468 ast_manager_unregister("AgentLogoff"); 02469 /* Unregister the data tree */ 02470 ast_data_unregister(NULL); 02471 /* Unregister channel */ 02472 AST_LIST_LOCK(&agents); 02473 /* Hangup all interfaces if they have an owner */ 02474 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02475 if (p->owner) 02476 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02477 ast_free(p); 02478 } 02479 AST_LIST_UNLOCK(&agents); 02480 return 0; 02481 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Agent Proxy Channel" , .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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } [static] |
Definition at line 2489 of file chan_agent.c.
char acceptdtmf = DEFAULT_ACCEPTDTMF [static] |
int ackcall [static] |
Definition at line 223 of file chan_agent.c.
struct ast_custom_function agent_function [static] |
Initial value:
{ .name = "AGENT", .read = function_agent, }
Definition at line 2337 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char agent_logoff_usage[] [static] |
Initial value:
"Usage: agent logoff <channel> [soft]\n" " Sets an agent as no longer logged in.\n" " If 'soft' is specified, do not hangup existing calls.\n"
Definition at line 1808 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 352 of file chan_agent.c.
Referenced by agent_new(), load_module(), and unload_module().
char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye" [static] |
Definition at line 231 of file chan_agent.c.
struct ast_data_handler agents_data_provider [static] |
Initial value:
{ .version = AST_DATA_HANDLER_VERSION, .get = agents_data_provider_get }
Definition at line 2403 of file chan_agent.c.
struct ast_data_entry agents_data_providers[] [static] |
Initial value:
{ AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider), }
Definition at line 2408 of file chan_agent.c.
Referenced by load_module().
const char app[] = "AgentLogin" [static] |
Definition at line 205 of file chan_agent.c.
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 206 of file chan_agent.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2489 of file chan_agent.c.
int autologoff [static] |
Definition at line 221 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 226 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 239 of file chan_agent.c.
struct ast_cli_entry cli_agents[] [static] |
Initial value:
{ { .handler = agents_show , .summary = "Show status of agents" ,__VA_ARGS__ }, { .handler = agents_show_online , .summary = "Show all online agents" ,__VA_ARGS__ }, { .handler = agent_logoff_cmd , .summary = "Sets an agent offline" ,__VA_ARGS__ }, }
Definition at line 1813 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char config[] = "agents.conf" [static] |
Definition at line 203 of file chan_agent.c.
int endcall [static] |
Definition at line 224 of file chan_agent.c.
char enddtmf = DEFAULT_ENDDTMF [static] |
Definition at line 228 of file chan_agent.c.
ast_group_t group [static] |
int maxlogintries = 3 [static] |
Definition at line 230 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 208 of file chan_agent.c.
Referenced by _get_mohbyname(), _moh_register(), dial_exec_full(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().
int multiplelogin = 1 [static] |
Definition at line 225 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 214 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 233 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 234 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 235 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 237 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 202 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 238 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
int wrapuptime [static] |
Definition at line 222 of file chan_agent.c.