#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 struct ast_channel * | agent_lock_owner (struct agent_pvt *pvt) |
Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed. | |
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 = "ac1f6a56484a8820659555499174e588" , .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 211 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().
#define AST_MAX_BUF 256 |
Definition at line 212 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 321 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
#define DATA_EXPORT_AGENT | ( | MEMBER | ) |
Definition at line 284 of file chan_agent.c.
#define DEFAULT_ACCEPTDTMF '#' |
Definition at line 218 of file chan_agent.c.
#define DEFAULT_ENDDTMF '*' |
Definition at line 219 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 216 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 244 of file chan_agent.c.
00244 { 00245 AGENT_FLAG_ACKCALL = (1 << 0), 00246 AGENT_FLAG_AUTOLOGOFF = (1 << 1), 00247 AGENT_FLAG_WRAPUPTIME = (1 << 2), 00248 AGENT_FLAG_ACCEPTDTMF = (1 << 3), 00249 AGENT_FLAG_ENDDTMF = (1 << 4), 00250 };
static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
struct agent_pvt * | p, | |||
int | needlock | |||
) | [static] |
Definition at line 563 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().
00564 { 00565 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00566 char filename[AST_MAX_BUF]; 00567 int res = -1; 00568 if (!p) 00569 return -1; 00570 if (!ast->monitor) { 00571 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00572 /* substitute . for - */ 00573 if ((pointer = strchr(filename, '.'))) 00574 *pointer = '-'; 00575 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00576 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT); 00577 ast_monitor_setjoinfiles(ast, 1); 00578 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00579 #if 0 00580 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00581 #endif 00582 if (!ast->cdr) 00583 ast->cdr = ast_cdr_alloc(); 00584 ast_cdr_setuserfield(ast, tmp2); 00585 res = 0; 00586 } else 00587 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00588 return res; 00589 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 2619 of file chan_agent.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2619 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 1719 of file chan_agent.c.
References agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
01720 { 01721 const char *agent = astman_get_header(m, "Agent"); 01722 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01723 int soft; 01724 int ret; /* return value of agent_logoff */ 01725 01726 if (ast_strlen_zero(agent)) { 01727 astman_send_error(s, m, "No agent specified"); 01728 return 0; 01729 } 01730 01731 soft = ast_true(soft_s) ? 1 : 0; 01732 ret = agent_logoff(agent, soft); 01733 if (ret == 0) 01734 astman_send_ack(s, m, "Agent logged out"); 01735 else 01736 astman_send_error(s, m, "No such agent"); 01737 01738 return 0; 01739 }
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. This function locks both the pvt and the channel that owns it for a while, but does not keep these locks.
s | ||
m |
Definition at line 1560 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::agent, agent_lock_owner(), ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, 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::bridge, ast_channel::caller, agent_pvt::chan, ast_party_caller::id, agent_pvt::lock, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, ast_party_id::number, S_COR, S_OR, status, ast_party_number::str, and ast_party_number::valid.
Referenced by load_module().
01561 { 01562 const char *id = astman_get_header(m,"ActionID"); 01563 char idText[256] = ""; 01564 struct agent_pvt *p; 01565 char *username = NULL; 01566 char *loginChan = NULL; 01567 char *talkingto = NULL; 01568 char *talkingtoChan = NULL; 01569 char *status = NULL; 01570 struct ast_channel *bridge; 01571 01572 if (!ast_strlen_zero(id)) 01573 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01574 astman_send_ack(s, m, "Agents will follow"); 01575 AST_LIST_LOCK(&agents); 01576 AST_LIST_TRAVERSE(&agents, p, list) { 01577 struct ast_channel *owner; 01578 ast_mutex_lock(&p->lock); 01579 owner = agent_lock_owner(p); 01580 01581 /* Status Values: 01582 AGENT_LOGGEDOFF - Agent isn't logged in 01583 AGENT_IDLE - Agent is logged in, and waiting for call 01584 AGENT_ONCALL - Agent is logged in, and on a call 01585 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01586 01587 username = S_OR(p->name, "None"); 01588 01589 /* Set a default status. It 'should' get changed. */ 01590 status = "AGENT_UNKNOWN"; 01591 01592 if (p->chan) { 01593 loginChan = ast_strdupa(p->chan->name); 01594 if (owner && owner->_bridge) { 01595 talkingto = S_COR(p->chan->caller.id.number.valid, 01596 p->chan->caller.id.number.str, "n/a"); 01597 if ((bridge = ast_bridged_channel(owner))) { 01598 talkingtoChan = ast_strdupa(bridge->name); 01599 } else { 01600 talkingtoChan = "n/a"; 01601 } 01602 status = "AGENT_ONCALL"; 01603 } else { 01604 talkingto = "n/a"; 01605 talkingtoChan = "n/a"; 01606 status = "AGENT_IDLE"; 01607 } 01608 } else { 01609 loginChan = "n/a"; 01610 talkingto = "n/a"; 01611 talkingtoChan = "n/a"; 01612 status = "AGENT_LOGGEDOFF"; 01613 } 01614 01615 if (owner) { 01616 ast_channel_unlock(owner); 01617 owner = ast_channel_unref(owner); 01618 } 01619 01620 astman_append(s, "Event: Agents\r\n" 01621 "Agent: %s\r\n" 01622 "Name: %s\r\n" 01623 "Status: %s\r\n" 01624 "LoggedInChan: %s\r\n" 01625 "LoggedInTime: %d\r\n" 01626 "TalkingTo: %s\r\n" 01627 "TalkingToChan: %s\r\n" 01628 "%s" 01629 "\r\n", 01630 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01631 ast_mutex_unlock(&p->lock); 01632 } 01633 AST_LIST_UNLOCK(&agents); 01634 astman_append(s, "Event: AgentsComplete\r\n" 01635 "%s" 01636 "\r\n",idText); 01637 return 0; 01638 }
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 422 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, name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00423 { 00424 char *parse; 00425 AST_DECLARE_APP_ARGS(args, 00426 AST_APP_ARG(agt); 00427 AST_APP_ARG(password); 00428 AST_APP_ARG(name); 00429 ); 00430 char *password = NULL; 00431 char *name = NULL; 00432 char *agt = NULL; 00433 struct agent_pvt *p; 00434 00435 parse = ast_strdupa(agent); 00436 00437 /* Extract username (agt), password and name from agent (args). */ 00438 AST_STANDARD_APP_ARGS(args, parse); 00439 00440 if(args.argc == 0) { 00441 ast_log(LOG_WARNING, "A blank agent line!\n"); 00442 return NULL; 00443 } 00444 00445 if(ast_strlen_zero(args.agt) ) { 00446 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00447 return NULL; 00448 } else 00449 agt = args.agt; 00450 00451 if(!ast_strlen_zero(args.password)) { 00452 password = args.password; 00453 while (*password && *password < 33) password++; 00454 } 00455 if(!ast_strlen_zero(args.name)) { 00456 name = args.name; 00457 while (*name && *name < 33) name++; 00458 } 00459 00460 /* Are we searching for the agent here ? To see if it exists already ? */ 00461 AST_LIST_TRAVERSE(&agents, p, list) { 00462 if (!pending && !strcmp(p->agent, agt)) 00463 break; 00464 } 00465 if (!p) { 00466 // Build the agent. 00467 if (!(p = ast_calloc(1, sizeof(*p)))) 00468 return NULL; 00469 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00470 ast_mutex_init(&p->lock); 00471 ast_cond_init(&p->app_complete_cond, NULL); 00472 ast_cond_init(&p->login_wait_cond, NULL); 00473 p->app_lock_flag = 0; 00474 p->app_sleep_cond = 1; 00475 p->group = group; 00476 p->pending = pending; 00477 AST_LIST_INSERT_TAIL(&agents, p, list); 00478 } 00479 00480 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00481 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00482 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00483 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) { 00484 p->ackcall = ackcall; 00485 } 00486 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) { 00487 p->autologoff = autologoff; 00488 } 00489 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) { 00490 p->acceptdtmf = acceptdtmf; 00491 } 00492 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) { 00493 p->enddtmf = enddtmf; 00494 } 00495 00496 /* If someone reduces the wrapuptime and reloads, we want it 00497 * to change the wrapuptime immediately on all calls */ 00498 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) { 00499 struct timeval now = ast_tvnow(); 00500 /* XXX check what is this exactly */ 00501 00502 /* We won't be pedantic and check the tv_usec val */ 00503 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00504 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00505 p->lastdisc.tv_usec = now.tv_usec; 00506 } 00507 } 00508 p->wrapuptime = wrapuptime; 00509 00510 if (pending) 00511 p->dead = 1; 00512 else 00513 p->dead = 0; 00514 return p; 00515 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 1043 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().
01044 { 01045 struct agent_pvt *p; 01046 int res=0; 01047 int to = 1000; 01048 struct ast_frame *f; 01049 01050 /* Wait a second and look for something */ 01051 01052 p = (struct agent_pvt *) data; 01053 if (!p->chan) 01054 return -1; 01055 01056 for(;;) { 01057 to = ast_waitfor(p->chan, to); 01058 if (to < 0) 01059 return -1; 01060 if (!to) 01061 return 0; 01062 f = ast_read(p->chan); 01063 if (!f) 01064 return -1; 01065 if (f->frametype == AST_FRAME_DTMF) 01066 res = f->subclass.integer; 01067 else 01068 res = 0; 01069 ast_frfree(f); 01070 ast_mutex_lock(&p->lock); 01071 if (!p->app_sleep_cond) { 01072 ast_mutex_unlock(&p->lock); 01073 return 0; 01074 } else if (res == p->acceptdtmf) { 01075 ast_mutex_unlock(&p->lock); 01076 return 1; 01077 } 01078 ast_mutex_unlock(&p->lock); 01079 res = 0; 01080 } 01081 return res; 01082 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 557 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00558 { 00559 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00560 return -1; 00561 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Definition at line 1084 of file chan_agent.c.
References ast_debug, ast_channel::bridge, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.
01085 { 01086 struct agent_pvt *p = bridge->tech_pvt; 01087 struct ast_channel *ret = NULL; 01088 01089 if (p) { 01090 if (chan == p->chan) 01091 ret = bridge->_bridge; 01092 else if (chan == bridge->_bridge) 01093 ret = p->chan; 01094 } 01095 01096 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 01097 return ret; 01098 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 830 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_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.
00831 { 00832 struct agent_pvt *p = ast->tech_pvt; 00833 int res = -1; 00834 int newstate=0; 00835 struct ast_channel *chan; 00836 00837 ast_mutex_lock(&p->lock); 00838 p->acknowledged = 0; 00839 00840 if (p->pending) { 00841 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00842 ast_mutex_unlock(&p->lock); 00843 ast_setstate(ast, AST_STATE_DIALING); 00844 return 0; 00845 } 00846 00847 if (!p->chan) { 00848 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 00849 ast_mutex_unlock(&p->lock); 00850 return res; 00851 } 00852 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00853 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language); 00854 00855 chan = p->chan; 00856 ast_mutex_unlock(&p->lock); 00857 00858 res = ast_streamfile(chan, beep, chan->language); 00859 ast_debug(3, "Played beep, result '%d'\n", res); 00860 if (!res) { 00861 res = ast_waitstream(chan, ""); 00862 ast_debug(3, "Waited for stream, result '%d'\n", res); 00863 } 00864 00865 ast_mutex_lock(&p->lock); 00866 if (!p->chan) { 00867 /* chan went away while we were streaming, this shouldn't be possible */ 00868 res = -1; 00869 } 00870 00871 if (!res) { 00872 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00873 ast_debug(3, "Set read format, result '%d'\n", res); 00874 if (res) 00875 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00876 } else { 00877 /* Agent hung-up */ 00878 p->chan = NULL; 00879 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00880 } 00881 00882 if (!res) { 00883 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00884 ast_debug(3, "Set write format, result '%d'\n", res); 00885 if (res) 00886 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00887 } 00888 if(!res) { 00889 /* Call is immediately up, or might need ack */ 00890 if (p->ackcall) { 00891 newstate = AST_STATE_RINGING; 00892 } else { 00893 newstate = AST_STATE_UP; 00894 if (recordagentcalls) 00895 agent_start_monitoring(ast, 0); 00896 p->acknowledged = 1; 00897 } 00898 res = 0; 00899 } 00900 CLEANUP(ast, p); 00901 ast_mutex_unlock(&p->lock); 00902 if (newstate) 00903 ast_setstate(ast, newstate); 00904 return res; 00905 }
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 528 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_release(), ast_cond_destroy, ast_cond_signal, ast_free, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, agent_pvt::dead, agent_pvt::lock, agent_pvt::login_wait_cond, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00529 { 00530 struct ast_channel *chan; 00531 00532 ast_mutex_lock(&p->lock); 00533 chan = p->owner; 00534 p->owner = NULL; 00535 /* Release ownership of the agent to other threads (presumably running the login app). */ 00536 p->app_sleep_cond = 1; 00537 p->app_lock_flag = 0; 00538 ast_cond_signal(&p->app_complete_cond); 00539 if (chan) { 00540 chan->tech_pvt = NULL; 00541 chan = ast_channel_release(chan); 00542 } 00543 if (p->dead) { 00544 ast_mutex_unlock(&p->lock); 00545 ast_mutex_destroy(&p->lock); 00546 ast_cond_destroy(&p->app_complete_cond); 00547 ast_cond_destroy(&p->login_wait_cond); 00548 ast_free(p); 00549 } else { 00550 ast_mutex_unlock(&p->lock); 00551 } 00552 return 0; 00553 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 1022 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().
01023 { 01024 struct agent_pvt *p; 01025 int res; 01026 01027 p = (struct agent_pvt *)data; 01028 01029 ast_mutex_lock(&p->lock); 01030 res = p->app_sleep_cond; 01031 if (p->lastdisc.tv_sec) { 01032 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 01033 res = 1; 01034 } 01035 ast_mutex_unlock(&p->lock); 01036 01037 if (!res) 01038 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 01039 01040 return res; 01041 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2323 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.
02324 { 02325 struct agent_pvt *p; 02326 char *s; 02327 ast_group_t groupmatch; 02328 int groupoff; 02329 int res = AST_DEVICE_INVALID; 02330 02331 s = data; 02332 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) 02333 groupmatch = (1 << groupoff); 02334 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02335 groupmatch = (1 << groupoff); 02336 } else 02337 groupmatch = 0; 02338 02339 /* Check actual logged in agents first */ 02340 AST_LIST_LOCK(&agents); 02341 AST_LIST_TRAVERSE(&agents, p, list) { 02342 ast_mutex_lock(&p->lock); 02343 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02344 if (p->owner) { 02345 if (res != AST_DEVICE_INUSE) 02346 res = AST_DEVICE_BUSY; 02347 } else { 02348 if (res == AST_DEVICE_BUSY) 02349 res = AST_DEVICE_INUSE; 02350 if (p->chan) { 02351 if (res == AST_DEVICE_INVALID) 02352 res = AST_DEVICE_UNKNOWN; 02353 } else if (res == AST_DEVICE_INVALID) 02354 res = AST_DEVICE_UNAVAILABLE; 02355 } 02356 if (!strcmp(data, p->agent)) { 02357 ast_mutex_unlock(&p->lock); 02358 break; 02359 } 02360 } 02361 ast_mutex_unlock(&p->lock); 02362 } 02363 AST_LIST_UNLOCK(&agents); 02364 return res; 02365 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 808 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.
00809 { 00810 struct agent_pvt *p = ast->tech_pvt; 00811 ast_mutex_lock(&p->lock); 00812 if (p->chan) { 00813 ast_senddigit_begin(p->chan, digit); 00814 } 00815 ast_mutex_unlock(&p->lock); 00816 return 0; 00817 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 819 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.
00820 { 00821 struct agent_pvt *p = ast->tech_pvt; 00822 ast_mutex_lock(&p->lock); 00823 if (p->chan) { 00824 ast_senddigit_end(p->chan, digit, duration); 00825 } 00826 ast_mutex_unlock(&p->lock); 00827 return 0; 00828 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 770 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.
00771 { 00772 struct agent_pvt *p = newchan->tech_pvt; 00773 ast_mutex_lock(&p->lock); 00774 if (p->owner != oldchan) { 00775 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00776 ast_mutex_unlock(&p->lock); 00777 return -1; 00778 } 00779 p->owner = newchan; 00780 ast_mutex_unlock(&p->lock); 00781 return 0; 00782 }
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 908 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00909 { 00910 struct agent_pvt *p = NULL; 00911 struct ast_channel *base = chan; 00912 00913 /* chan is locked by the calling function */ 00914 if (!chan || !chan->tech_pvt) { 00915 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); 00916 return NULL; 00917 } 00918 p = chan->tech_pvt; 00919 if (p->chan) 00920 base = p->chan; 00921 return base; 00922 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 941 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_flag, agent_pvt::app_sleep_cond, ast_channel_ref, ast_channel_unref, 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_UP, ast_strdupa, ast_strlen_zero(), ast_tvadd(), ast_tvnow(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::login_wait_cond, 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.
Referenced by agent_request().
00942 { 00943 struct agent_pvt *p = ast->tech_pvt; 00944 struct ast_channel *indicate_chan = NULL; 00945 char *tmp_moh; /* moh buffer for indicating after unlocking p */ 00946 00947 if (p->pending) { 00948 AST_LIST_LOCK(&agents); 00949 AST_LIST_REMOVE(&agents, p, list); 00950 AST_LIST_UNLOCK(&agents); 00951 } 00952 00953 ast_mutex_lock(&p->lock); 00954 p->owner = NULL; 00955 ast->tech_pvt = NULL; 00956 p->app_sleep_cond = 1; 00957 p->acknowledged = 0; 00958 00959 /* Release ownership of the agent to other threads (presumably running the login app). */ 00960 p->app_lock_flag = 0; 00961 ast_cond_signal(&p->app_complete_cond); 00962 00963 /* if they really are hung up then set start to 0 so the test 00964 * later if we're called on an already downed channel 00965 * doesn't cause an agent to be logged out like when 00966 * agent_request() is followed immediately by agent_hangup() 00967 * as in apps/app_chanisavail.c:chanavail_exec() 00968 */ 00969 00970 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00971 if (p->start && (ast->_state != AST_STATE_UP)) { 00972 p->start = 0; 00973 } else 00974 p->start = 0; 00975 if (p->chan) { 00976 p->chan->_bridge = NULL; 00977 /* If they're dead, go ahead and hang up on the agent now */ 00978 if (p->dead) { 00979 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00980 } else if (p->loginstart) { 00981 indicate_chan = ast_channel_ref(p->chan); 00982 tmp_moh = ast_strdupa(p->moh); 00983 } 00984 } 00985 ast_mutex_unlock(&p->lock); 00986 00987 if (indicate_chan) { 00988 ast_indicate_data(indicate_chan, AST_CONTROL_HOLD, 00989 S_OR(tmp_moh, NULL), 00990 !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0); 00991 indicate_chan = ast_channel_unref(indicate_chan); 00992 } 00993 00994 /* Only register a device state change if the agent is still logged in */ 00995 if (!p->loginstart) { 00996 p->logincallerid[0] = '\0'; 00997 } else { 00998 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00999 } 01000 01001 if (p->abouttograb) { 01002 /* Let the "about to grab" thread know this isn't valid anymore, and let it 01003 kill it later */ 01004 p->abouttograb = 0; 01005 } else if (p->dead) { 01006 ast_mutex_destroy(&p->lock); 01007 ast_cond_destroy(&p->app_complete_cond); 01008 ast_cond_destroy(&p->login_wait_cond); 01009 ast_free(p); 01010 } else { 01011 if (p->chan) { 01012 /* Not dead -- check availability now */ 01013 ast_mutex_lock(&p->lock); 01014 /* Store last disconnect time */ 01015 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 01016 ast_mutex_unlock(&p->lock); 01017 } 01018 } 01019 return 0; 01020 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 784 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.
00785 { 00786 struct agent_pvt *p = ast->tech_pvt; 00787 int res = -1; 00788 ast_mutex_lock(&p->lock); 00789 if (p->chan && !ast_check_hangup(p->chan)) { 00790 while (ast_channel_trylock(p->chan)) { 00791 int res; 00792 if ((res = ast_channel_unlock(ast))) { 00793 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", res > 0 ? strerror(res) : "Bad ao2obj data"); 00794 ast_mutex_unlock(&p->lock); 00795 return -1; 00796 } 00797 usleep(1); 00798 ast_channel_lock(ast); 00799 } 00800 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00801 ast_channel_unlock(p->chan); 00802 } else 00803 res = 0; 00804 ast_mutex_unlock(&p->lock); 00805 return res; 00806 }
static struct ast_channel* agent_lock_owner | ( | struct agent_pvt * | pvt | ) | [static] |
Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed.
pvt | Pointer to the LOCKED agent_pvt for which the owner is needed locked channel which owns the pvt at the time of completion. NULL if not available. |
Definition at line 387 of file chan_agent.c.
References ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, ast_mutex_lock, ast_mutex_unlock, agent_pvt::lock, and agent_pvt::owner.
Referenced by action_agents(), agent_logoff(), agent_read(), agents_data_provider_get(), agents_show(), and agents_show_online().
00388 { 00389 struct ast_channel *owner; 00390 00391 for (;;) { 00392 if (!pvt->owner) { /* No owner. Nothing to do. */ 00393 return NULL; 00394 } 00395 00396 /* If we don't ref the owner, it could be killed when we unlock the pvt. */ 00397 owner = ast_channel_ref(pvt->owner); 00398 00399 /* Locking order requires us to lock channel, then pvt. */ 00400 ast_mutex_unlock(&pvt->lock); 00401 ast_channel_lock(owner); 00402 ast_mutex_lock(&pvt->lock); 00403 00404 /* Check if owner changed during pvt unlock period */ 00405 if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */ 00406 ast_channel_unlock(owner); 00407 owner = ast_channel_unref(owner); 00408 } else { /* Channel stayed the same. Return it. */ 00409 return owner; 00410 } 00411 } 00412 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1640 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_channel_trylock, ast_channel_unlock, ast_channel_unref, 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().
01641 { 01642 struct agent_pvt *p; 01643 int ret = -1; /* Return -1 if no agent if found */ 01644 01645 AST_LIST_LOCK(&agents); 01646 AST_LIST_TRAVERSE(&agents, p, list) { 01647 if (!strcasecmp(p->agent, agent)) { 01648 ret = 0; 01649 if (p->owner || p->chan) { 01650 if (!soft) { 01651 struct ast_channel *owner; 01652 ast_mutex_lock(&p->lock); 01653 owner = agent_lock_owner(p); 01654 01655 if (owner) { 01656 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT); 01657 ast_channel_unlock(owner); 01658 owner = ast_channel_unref(owner); 01659 } 01660 01661 while (p->chan && ast_channel_trylock(p->chan)) { 01662 DEADLOCK_AVOIDANCE(&p->lock); 01663 } 01664 if (p->chan) { 01665 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01666 ast_channel_unlock(p->chan); 01667 } 01668 01669 ast_mutex_unlock(&p->lock); 01670 } else 01671 p->deferlogoff = 1; 01672 } 01673 break; 01674 } 01675 } 01676 AST_LIST_UNLOCK(&agents); 01677 01678 return ret; 01679 }
static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1681 of file chan_agent.c.
References 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.
01682 { 01683 int ret; 01684 const char *agent; 01685 01686 switch (cmd) { 01687 case CLI_INIT: 01688 e->command = "agent logoff"; 01689 e->usage = 01690 "Usage: agent logoff <channel> [soft]\n" 01691 " Sets an agent as no longer logged in.\n" 01692 " If 'soft' is specified, do not hangup existing calls.\n"; 01693 return NULL; 01694 case CLI_GENERATE: 01695 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01696 } 01697 01698 if (a->argc < 3 || a->argc > 4) 01699 return CLI_SHOWUSAGE; 01700 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01701 return CLI_SHOWUSAGE; 01702 01703 agent = a->argv[2] + 6; 01704 ret = agent_logoff(agent, a->argc == 4); 01705 if (ret == 0) 01706 ast_cli(a->fd, "Logging out %s\n", agent); 01707 01708 return CLI_SUCCESS; 01709 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state, | |||
const char * | linkedid | |||
) | [static] |
Create new agent channel.
Definition at line 1101 of file chan_agent.c.
References agent_pvt::agent, agent_tech, ast_channel_alloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_log(), ast_random(), ast_string_field_set, agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, 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().
01102 { 01103 struct ast_channel *tmp; 01104 #if 0 01105 if (!p->chan) { 01106 ast_log(LOG_WARNING, "No channel? :(\n"); 01107 return NULL; 01108 } 01109 #endif 01110 if (p->pending) 01111 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); 01112 else 01113 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent); 01114 if (!tmp) { 01115 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01116 return NULL; 01117 } 01118 01119 tmp->tech = &agent_tech; 01120 if (p->chan) { 01121 tmp->nativeformats = p->chan->nativeformats; 01122 tmp->writeformat = p->chan->writeformat; 01123 tmp->rawwriteformat = p->chan->writeformat; 01124 tmp->readformat = p->chan->readformat; 01125 tmp->rawreadformat = p->chan->readformat; 01126 ast_string_field_set(tmp, language, p->chan->language); 01127 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01128 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01129 /* XXX Is this really all we copy form the originating channel?? */ 01130 } else { 01131 tmp->nativeformats = AST_FORMAT_SLINEAR; 01132 tmp->writeformat = AST_FORMAT_SLINEAR; 01133 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01134 tmp->readformat = AST_FORMAT_SLINEAR; 01135 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01136 } 01137 /* Safe, agentlock already held */ 01138 tmp->tech_pvt = p; 01139 p->owner = tmp; 01140 tmp->priority = 1; 01141 return tmp; 01142 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 596 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_lock_owner(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, 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::start, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.
00597 { 00598 struct agent_pvt *p = ast->tech_pvt; 00599 struct ast_frame *f = NULL; 00600 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; 00601 int cur_time = time(NULL); 00602 struct ast_channel *owner; 00603 00604 ast_mutex_lock(&p->lock); 00605 owner = agent_lock_owner(p); 00606 00607 CHECK_FORMATS(ast, p); 00608 if (!p->start) { 00609 p->start = cur_time; 00610 } 00611 if (p->chan) { 00612 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00613 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00614 f = ast_read(p->chan); 00615 } else 00616 f = &ast_null_frame; 00617 if (!f) { 00618 /* If there's a channel, make it NULL */ 00619 if (p->chan) { 00620 p->chan->_bridge = NULL; 00621 p->chan = NULL; 00622 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00623 p->acknowledged = 0; 00624 } 00625 } else { 00626 /* if acknowledgement is not required, and the channel is up, we may have missed 00627 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00628 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00629 p->acknowledged = 1; 00630 } 00631 00632 if (!p->acknowledged) { 00633 int howlong = cur_time - p->start; 00634 if (p->autologoff && (howlong >= p->autologoff)) { 00635 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00636 if (owner || p->chan) { 00637 if (owner) { 00638 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT); 00639 ast_channel_unlock(owner); 00640 owner = ast_channel_unref(owner); 00641 } 00642 00643 while (p->chan && ast_channel_trylock(p->chan)) { 00644 DEADLOCK_AVOIDANCE(&p->lock); 00645 } 00646 if (p->chan) { 00647 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00648 ast_channel_unlock(p->chan); 00649 } 00650 } 00651 } 00652 } 00653 switch (f->frametype) { 00654 case AST_FRAME_CONTROL: 00655 if (f->subclass.integer == AST_CONTROL_ANSWER) { 00656 if (p->ackcall) { 00657 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); 00658 /* Don't pass answer along */ 00659 ast_frfree(f); 00660 f = &ast_null_frame; 00661 } else { 00662 p->acknowledged = 1; 00663 /* Use the builtin answer frame for the 00664 recording start check below. */ 00665 ast_frfree(f); 00666 f = &answer_frame; 00667 } 00668 } 00669 break; 00670 case AST_FRAME_DTMF_BEGIN: 00671 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00672 if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){ 00673 ast_frfree(f); 00674 f = &ast_null_frame; 00675 } 00676 break; 00677 case AST_FRAME_DTMF_END: 00678 if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) { 00679 if (p->chan) { 00680 ast_verb(3, "%s acknowledged\n", p->chan->name); 00681 } 00682 p->acknowledged = 1; 00683 ast_frfree(f); 00684 f = &answer_frame; 00685 } else if (f->subclass.integer == p->enddtmf && endcall) { 00686 /* terminates call */ 00687 ast_frfree(f); 00688 f = NULL; 00689 } 00690 break; 00691 case AST_FRAME_VOICE: 00692 case AST_FRAME_VIDEO: 00693 /* don't pass voice or video until the call is acknowledged */ 00694 if (!p->acknowledged) { 00695 ast_frfree(f); 00696 f = &ast_null_frame; 00697 } 00698 default: 00699 /* pass everything else on through */ 00700 break; 00701 } 00702 } 00703 00704 if (owner) { 00705 ast_channel_unlock(owner); 00706 owner = ast_channel_unref(owner); 00707 } 00708 00709 CLEANUP(ast,p); 00710 if (p->chan && !p->chan->_bridge) { 00711 if (strcasecmp(p->chan->tech->type, "Local")) { 00712 p->chan->_bridge = ast; 00713 if (p->chan) 00714 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00715 } 00716 } 00717 ast_mutex_unlock(&p->lock); 00718 if (recordagentcalls && f == &answer_frame) 00719 agent_start_monitoring(ast,0); 00720 return f; 00721 }
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 1414 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_hangup(), agent_new(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_cond_signal, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, ast_indicate(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), AST_STATE_DOWN, ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, ast_channel::linkedid, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::owner, and agent_pvt::pending.
01415 { 01416 struct agent_pvt *p; 01417 struct ast_channel *chan = NULL; 01418 char *s; 01419 ast_group_t groupmatch; 01420 int groupoff; 01421 int waitforagent=0; 01422 int hasagent = 0; 01423 struct timeval now; 01424 01425 s = data; 01426 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01427 groupmatch = (1 << groupoff); 01428 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01429 groupmatch = (1 << groupoff); 01430 waitforagent = 1; 01431 } else 01432 groupmatch = 0; 01433 01434 /* Check actual logged in agents first */ 01435 AST_LIST_LOCK(&agents); 01436 AST_LIST_TRAVERSE(&agents, p, list) { 01437 ast_mutex_lock(&p->lock); 01438 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01439 if (p->chan) 01440 hasagent++; 01441 now = ast_tvnow(); 01442 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01443 p->lastdisc = ast_tv(0, 0); 01444 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01445 if (!p->owner && p->chan) { 01446 /* Fixed agent */ 01447 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01448 } 01449 if (chan) { 01450 ast_mutex_unlock(&p->lock); 01451 break; 01452 } 01453 } 01454 } 01455 ast_mutex_unlock(&p->lock); 01456 } 01457 if (!p) { 01458 AST_LIST_TRAVERSE(&agents, p, list) { 01459 ast_mutex_lock(&p->lock); 01460 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01461 if (p->chan) { 01462 hasagent++; 01463 } 01464 now = ast_tvnow(); 01465 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01466 p->lastdisc = ast_tv(0, 0); 01467 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01468 if (!p->owner && p->chan) { 01469 /* Could still get a fixed agent */ 01470 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01471 } 01472 if (chan) { 01473 ast_mutex_unlock(&p->lock); 01474 break; 01475 } 01476 } 01477 } 01478 ast_mutex_unlock(&p->lock); 01479 } 01480 } 01481 01482 if (!chan && waitforagent) { 01483 /* No agent available -- but we're requesting to wait for one. 01484 Allocate a place holder */ 01485 if (hasagent) { 01486 ast_debug(1, "Creating place holder for '%s'\n", s); 01487 p = add_agent(data, 1); 01488 p->group = groupmatch; 01489 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01490 if (!chan) 01491 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01492 } else { 01493 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01494 } 01495 } 01496 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01497 AST_LIST_UNLOCK(&agents); 01498 01499 if (chan) { 01500 ast_mutex_lock(&p->lock); 01501 if (p->pending) { 01502 ast_mutex_unlock(&p->lock); 01503 return chan; 01504 } 01505 01506 if (!p->chan) { 01507 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 01508 *cause = AST_CAUSE_UNREGISTERED; 01509 ast_mutex_unlock(&p->lock); 01510 agent_hangup(chan); 01511 return NULL; 01512 } 01513 01514 /* we need to take control of the channel from the login app 01515 * thread */ 01516 p->app_sleep_cond = 0; 01517 p->app_lock_flag = 1; 01518 01519 ast_queue_frame(p->chan, &ast_null_frame); 01520 ast_cond_wait(&p->login_wait_cond, &p->lock); 01521 01522 if (!p->chan) { 01523 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 01524 p->app_sleep_cond = 1; 01525 p->app_lock_flag = 0; 01526 ast_cond_signal(&p->app_complete_cond); 01527 ast_mutex_unlock(&p->lock); 01528 *cause = AST_CAUSE_UNREGISTERED; 01529 agent_hangup(chan); 01530 return NULL; 01531 } 01532 01533 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01534 ast_mutex_unlock(&p->lock); 01535 } 01536 01537 return chan; 01538 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 723 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.
00724 { 00725 struct agent_pvt *p = ast->tech_pvt; 00726 int res = -1; 00727 ast_mutex_lock(&p->lock); 00728 if (p->chan) 00729 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00730 ast_mutex_unlock(&p->lock); 00731 return res; 00732 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 734 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.
00735 { 00736 struct agent_pvt *p = ast->tech_pvt; 00737 int res = -1; 00738 ast_mutex_lock(&p->lock); 00739 if (p->chan) 00740 res = ast_sendtext(p->chan, text); 00741 ast_mutex_unlock(&p->lock); 00742 return res; 00743 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 924 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.
00925 { 00926 struct agent_pvt *p = NULL; 00927 00928 if (!chan || !base) { 00929 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00930 return -1; 00931 } 00932 p = chan->tech_pvt; 00933 if (!p) { 00934 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00935 return -1; 00936 } 00937 p->chan = base; 00938 return 0; 00939 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 591 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00592 { 00593 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00594 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 745 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.
00746 { 00747 struct agent_pvt *p = ast->tech_pvt; 00748 int res = -1; 00749 CHECK_FORMATS(ast, p); 00750 ast_mutex_lock(&p->lock); 00751 if (!p->chan) 00752 res = 0; 00753 else { 00754 if ((f->frametype != AST_FRAME_VOICE) || 00755 (f->frametype != AST_FRAME_VIDEO) || 00756 (f->subclass.codec == p->chan->writeformat)) { 00757 res = ast_write(p->chan, f); 00758 } else { 00759 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00760 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00761 ast->name, p->chan->name); 00762 res = 0; 00763 } 00764 } 00765 CLEANUP(ast, p); 00766 ast_mutex_unlock(&p->lock); 00767 return res; 00768 }
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 2270 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_module_user::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().
02271 { 02272 int exitifnoagentid = 0; 02273 int nowarnings = 0; 02274 int changeoutgoing = 0; 02275 int res = 0; 02276 char agent[AST_MAX_AGENT]; 02277 02278 if (data) { 02279 if (strchr(data, 'd')) 02280 exitifnoagentid = 1; 02281 if (strchr(data, 'n')) 02282 nowarnings = 1; 02283 if (strchr(data, 'c')) 02284 changeoutgoing = 1; 02285 } 02286 if (chan->caller.id.number.valid 02287 && !ast_strlen_zero(chan->caller.id.number.str)) { 02288 const char *tmp; 02289 char agentvar[AST_MAX_BUF]; 02290 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, 02291 chan->caller.id.number.str); 02292 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02293 struct agent_pvt *p; 02294 ast_copy_string(agent, tmp, sizeof(agent)); 02295 AST_LIST_LOCK(&agents); 02296 AST_LIST_TRAVERSE(&agents, p, list) { 02297 if (!strcasecmp(p->agent, tmp)) { 02298 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02299 __agent_start_monitoring(chan, p, 1); 02300 break; 02301 } 02302 } 02303 AST_LIST_UNLOCK(&agents); 02304 02305 } else { 02306 res = -1; 02307 if (!nowarnings) 02308 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); 02309 } 02310 } else { 02311 res = -1; 02312 if (!nowarnings) 02313 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"); 02314 } 02315 if (res) { 02316 if (exitifnoagentid) 02317 return res; 02318 } 02319 return 0; 02320 }
static int agents_data_provider_get | ( | const struct ast_data_search * | search, | |
struct ast_data * | data_root | |||
) | [static] |
Definition at line 2461 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_bridged_channel(), ast_channel_data_add_structure(), ast_channel_unlock, ast_channel_unref, 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::lock, agent_pvt::moh, and agent_pvt::pending.
02463 { 02464 struct agent_pvt *p; 02465 struct ast_data *data_agent, *data_channel, *data_talkingto; 02466 02467 AST_LIST_LOCK(&agents); 02468 AST_LIST_TRAVERSE(&agents, p, list) { 02469 struct ast_channel *owner; 02470 02471 data_agent = ast_data_add_node(data_root, "agent"); 02472 if (!data_agent) { 02473 continue; 02474 } 02475 02476 ast_mutex_lock(&p->lock); 02477 owner = agent_lock_owner(p); 02478 02479 if (!(p->pending)) { 02480 ast_data_add_str(data_agent, "id", p->agent); 02481 ast_data_add_structure(agent_pvt, data_agent, p); 02482 02483 ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0); 02484 if (p->chan) { 02485 data_channel = ast_data_add_node(data_agent, "loggedon"); 02486 if (!data_channel) { 02487 ast_mutex_unlock(&p->lock); 02488 ast_data_remove_node(data_root, data_agent); 02489 if (owner) { 02490 ast_channel_unlock(owner); 02491 owner = ast_channel_unref(owner); 02492 } 02493 continue; 02494 } 02495 ast_channel_data_add_structure(data_channel, p->chan, 0); 02496 if (owner && ast_bridged_channel(owner)) { 02497 data_talkingto = ast_data_add_node(data_agent, "talkingto"); 02498 if (!data_talkingto) { 02499 ast_mutex_unlock(&p->lock); 02500 ast_data_remove_node(data_root, data_agent); 02501 if (owner) { 02502 ast_channel_unlock(owner); 02503 owner = ast_channel_unref(owner); 02504 } 02505 continue; 02506 } 02507 ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0); 02508 } 02509 } else { 02510 ast_data_add_node(data_agent, "talkingto"); 02511 ast_data_add_node(data_agent, "loggedon"); 02512 } 02513 ast_data_add_str(data_agent, "musiconhold", p->moh); 02514 } 02515 02516 if (owner) { 02517 ast_channel_unlock(owner); 02518 owner = ast_channel_unref(owner); 02519 } 02520 02521 ast_mutex_unlock(&p->lock); 02522 02523 /* if this agent doesn't match remove the added agent. */ 02524 if (!ast_data_search_match(search, data_agent)) { 02525 ast_data_remove_node(data_root, data_agent); 02526 } 02527 } 02528 AST_LIST_UNLOCK(&agents); 02529 02530 return 0; 02531 }
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 1768 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, 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.
01769 { 01770 struct agent_pvt *p; 01771 char username[AST_MAX_BUF]; 01772 char location[AST_MAX_BUF] = ""; 01773 char talkingto[AST_MAX_BUF] = ""; 01774 char music[AST_MAX_BUF]; 01775 int count_agents = 0; /*!< Number of agents configured */ 01776 int online_agents = 0; /*!< Number of online agents */ 01777 int offline_agents = 0; /*!< Number of offline agents */ 01778 01779 switch (cmd) { 01780 case CLI_INIT: 01781 e->command = "agent show"; 01782 e->usage = 01783 "Usage: agent show\n" 01784 " Provides summary information on agents.\n"; 01785 return NULL; 01786 case CLI_GENERATE: 01787 return NULL; 01788 } 01789 01790 if (a->argc != 2) 01791 return CLI_SHOWUSAGE; 01792 01793 AST_LIST_LOCK(&agents); 01794 AST_LIST_TRAVERSE(&agents, p, list) { 01795 struct ast_channel *owner; 01796 ast_mutex_lock(&p->lock); 01797 owner = agent_lock_owner(p); 01798 if (p->pending) { 01799 if (p->group) 01800 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01801 else 01802 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01803 } else { 01804 if (!ast_strlen_zero(p->name)) 01805 snprintf(username, sizeof(username), "(%s) ", p->name); 01806 else 01807 username[0] = '\0'; 01808 if (p->chan) { 01809 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01810 if (owner && ast_bridged_channel(owner)) { 01811 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01812 } else { 01813 strcpy(talkingto, " is idle"); 01814 } 01815 online_agents++; 01816 } else { 01817 strcpy(location, "not logged in"); 01818 talkingto[0] = '\0'; 01819 offline_agents++; 01820 } 01821 if (!ast_strlen_zero(p->moh)) 01822 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01823 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01824 username, location, talkingto, music); 01825 count_agents++; 01826 } 01827 01828 if (owner) { 01829 ast_channel_unlock(owner); 01830 owner = ast_channel_unref(owner); 01831 } 01832 ast_mutex_unlock(&p->lock); 01833 } 01834 AST_LIST_UNLOCK(&agents); 01835 if ( !count_agents ) 01836 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01837 else 01838 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01839 ast_cli(a->fd, "\n"); 01840 01841 return CLI_SUCCESS; 01842 }
static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1845 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, 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, name, ast_channel::name, agent_pvt::name, and ast_cli_entry::usage.
01846 { 01847 struct agent_pvt *p; 01848 char username[AST_MAX_BUF]; 01849 char location[AST_MAX_BUF] = ""; 01850 char talkingto[AST_MAX_BUF] = ""; 01851 char music[AST_MAX_BUF]; 01852 int count_agents = 0; /* Number of agents configured */ 01853 int online_agents = 0; /* Number of online agents */ 01854 int agent_status = 0; /* 0 means offline, 1 means online */ 01855 01856 switch (cmd) { 01857 case CLI_INIT: 01858 e->command = "agent show online"; 01859 e->usage = 01860 "Usage: agent show online\n" 01861 " Provides a list of all online agents.\n"; 01862 return NULL; 01863 case CLI_GENERATE: 01864 return NULL; 01865 } 01866 01867 if (a->argc != 3) 01868 return CLI_SHOWUSAGE; 01869 01870 AST_LIST_LOCK(&agents); 01871 AST_LIST_TRAVERSE(&agents, p, list) { 01872 struct ast_channel *owner; 01873 01874 agent_status = 0; /* reset it to offline */ 01875 ast_mutex_lock(&p->lock); 01876 owner = agent_lock_owner(p); 01877 01878 if (!ast_strlen_zero(p->name)) 01879 snprintf(username, sizeof(username), "(%s) ", p->name); 01880 else 01881 username[0] = '\0'; 01882 if (p->chan) { 01883 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01884 if (owner && ast_bridged_channel(owner)) { 01885 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name); 01886 } else { 01887 strcpy(talkingto, " is idle"); 01888 } 01889 agent_status = 1; 01890 online_agents++; 01891 } 01892 01893 if (owner) { 01894 ast_channel_unlock(owner); 01895 owner = ast_channel_unref(owner); 01896 } 01897 01898 if (!ast_strlen_zero(p->moh)) 01899 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01900 if (agent_status) 01901 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01902 count_agents++; 01903 ast_mutex_unlock(&p->lock); 01904 } 01905 AST_LIST_UNLOCK(&agents); 01906 if (!count_agents) 01907 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01908 else 01909 ast_cli(a->fd, "%d agents online\n", online_agents); 01910 ast_cli(a->fd, "\n"); 01911 return CLI_SUCCESS; 01912 }
AST_DATA_STRUCTURE | ( | agent_pvt | , | |
DATA_EXPORT_AGENT | ||||
) |
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1314 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_hangup(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, 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().
01315 { 01316 struct ast_channel *chan=NULL, *parent=NULL; 01317 struct agent_pvt *p; 01318 int res; 01319 01320 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01321 if (needlock) 01322 AST_LIST_LOCK(&agents); 01323 AST_LIST_TRAVERSE(&agents, p, list) { 01324 if (p == newlyavailable) { 01325 continue; 01326 } 01327 ast_mutex_lock(&p->lock); 01328 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01329 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01330 /* We found a pending call, time to merge */ 01331 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL); 01332 parent = p->owner; 01333 p->abouttograb = 1; 01334 ast_mutex_unlock(&p->lock); 01335 break; 01336 } 01337 ast_mutex_unlock(&p->lock); 01338 } 01339 if (needlock) 01340 AST_LIST_UNLOCK(&agents); 01341 if (parent && chan) { 01342 if (newlyavailable->ackcall) { 01343 /* Don't do beep here */ 01344 res = 0; 01345 } else { 01346 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01347 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01348 ast_debug(3, "Played beep, result '%d'\n", res); 01349 if (!res) { 01350 res = ast_waitstream(newlyavailable->chan, ""); 01351 ast_debug(1, "Waited for stream, result '%d'\n", res); 01352 } 01353 } 01354 if (!res) { 01355 /* Note -- parent may have disappeared */ 01356 if (p->abouttograb) { 01357 newlyavailable->acknowledged = 1; 01358 /* Safe -- agent lock already held */ 01359 ast_setstate(parent, AST_STATE_UP); 01360 ast_setstate(chan, AST_STATE_UP); 01361 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01362 ast_channel_masquerade(parent, chan); 01363 ast_hangup(chan); 01364 p->abouttograb = 0; 01365 } else { 01366 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01367 agent_cleanup(newlyavailable); 01368 } 01369 } else { 01370 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01371 agent_cleanup(newlyavailable); 01372 } 01373 } 01374 return 0; 01375 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1377 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().
01378 { 01379 struct agent_pvt *p; 01380 int res=0; 01381 01382 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01383 if (needlock) 01384 AST_LIST_LOCK(&agents); 01385 AST_LIST_TRAVERSE(&agents, p, list) { 01386 if (p == newlyavailable) { 01387 continue; 01388 } 01389 ast_mutex_lock(&p->lock); 01390 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01391 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01392 ast_mutex_unlock(&p->lock); 01393 break; 01394 } 01395 ast_mutex_unlock(&p->lock); 01396 } 01397 if (needlock) 01398 AST_LIST_UNLOCK(&agents); 01399 if (p) { 01400 ast_mutex_unlock(&newlyavailable->lock); 01401 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01402 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01403 ast_debug(1, "Played beep, result '%d'\n", res); 01404 if (!res) { 01405 res = ast_waitstream(newlyavailable->chan, ""); 01406 ast_debug(1, "Waited for stream, result '%d'\n", res); 01407 } 01408 ast_mutex_lock(&newlyavailable->lock); 01409 } 01410 return res; 01411 }
static char * complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1741 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 name.
Referenced by agent_logoff_cmd().
01742 { 01743 char *ret = NULL; 01744 01745 if (pos == 2) { 01746 struct agent_pvt *p; 01747 char name[AST_MAX_AGENT]; 01748 int which = 0, len = strlen(word); 01749 01750 AST_LIST_LOCK(&agents); 01751 AST_LIST_TRAVERSE(&agents, p, list) { 01752 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01753 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01754 ret = ast_strdup(name); 01755 break; 01756 } 01757 } 01758 AST_LIST_UNLOCK(&agents); 01759 } else if (pos == 3 && state == 0) 01760 return ast_strdup("soft"); 01761 01762 return ret; 01763 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2370 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_TRAVERSE, and agent_pvt::list.
Referenced by function_agent().
02371 { 02372 struct agent_pvt *cur; 02373 02374 AST_LIST_TRAVERSE(&agents, cur, list) { 02375 if (!strcmp(cur->agent, agentid)) 02376 break; 02377 } 02378 02379 return cur; 02380 }
static int function_agent | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2382 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.
02383 { 02384 char *parse; 02385 AST_DECLARE_APP_ARGS(args, 02386 AST_APP_ARG(agentid); 02387 AST_APP_ARG(item); 02388 ); 02389 char *tmp; 02390 struct agent_pvt *agent; 02391 02392 buf[0] = '\0'; 02393 02394 if (ast_strlen_zero(data)) { 02395 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02396 return -1; 02397 } 02398 02399 parse = ast_strdupa(data); 02400 02401 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02402 if (!args.item) 02403 args.item = "status"; 02404 02405 AST_LIST_LOCK(&agents); 02406 02407 if (!(agent = find_agent(args.agentid))) { 02408 AST_LIST_UNLOCK(&agents); 02409 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02410 return -1; 02411 } 02412 02413 if (!strcasecmp(args.item, "status")) { 02414 char *status = "LOGGEDOUT"; 02415 if (agent->chan) { 02416 status = "LOGGEDIN"; 02417 } 02418 ast_copy_string(buf, status, len); 02419 } else if (!strcasecmp(args.item, "password")) 02420 ast_copy_string(buf, agent->password, len); 02421 else if (!strcasecmp(args.item, "name")) 02422 ast_copy_string(buf, agent->name, len); 02423 else if (!strcasecmp(args.item, "mohclass")) 02424 ast_copy_string(buf, agent->moh, len); 02425 else if (!strcasecmp(args.item, "channel")) { 02426 if (agent->chan) { 02427 ast_channel_lock(agent->chan); 02428 ast_copy_string(buf, agent->chan->name, len); 02429 ast_channel_unlock(agent->chan); 02430 tmp = strrchr(buf, '-'); 02431 if (tmp) 02432 *tmp = '\0'; 02433 } 02434 } else if (!strcasecmp(args.item, "fullchannel")) { 02435 if (agent->chan) { 02436 ast_channel_lock(agent->chan); 02437 ast_copy_string(buf, agent->chan->name, len); 02438 ast_channel_unlock(agent->chan); 02439 } 02440 } else if (!strcasecmp(args.item, "exten")) { 02441 buf[0] = '\0'; 02442 } 02443 02444 AST_LIST_UNLOCK(&agents); 02445 02446 return 0; 02447 }
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 2549 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().
02550 { 02551 /* Make sure we can register our agent channel type */ 02552 if (ast_channel_register(&agent_tech)) { 02553 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02554 return AST_MODULE_LOAD_FAILURE; 02555 } 02556 /* Read in the config */ 02557 if (!read_agent_config(0)) 02558 return AST_MODULE_LOAD_DECLINE; 02559 /* Dialplan applications */ 02560 ast_register_application_xml(app, login_exec); 02561 ast_register_application_xml(app3, agentmonitoroutgoing_exec); 02562 02563 /* data tree */ 02564 ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers)); 02565 02566 /* Manager commands */ 02567 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents); 02568 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff); 02569 02570 /* CLI Commands */ 02571 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02572 02573 /* Dialplan Functions */ 02574 ast_custom_function_register(&agent_function); 02575 02576 return AST_MODULE_LOAD_SUCCESS; 02577 }
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 1935 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_flag, args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_signal, 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, ast_module_user::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::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, 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().
01936 { 01937 int res=0; 01938 int tries = 0; 01939 int max_login_tries = maxlogintries; 01940 struct agent_pvt *p; 01941 struct ast_module_user *u; 01942 char user[AST_MAX_AGENT] = ""; 01943 char pass[AST_MAX_AGENT]; 01944 char agent[AST_MAX_AGENT] = ""; 01945 char xpass[AST_MAX_AGENT] = ""; 01946 char *errmsg; 01947 char *parse; 01948 AST_DECLARE_APP_ARGS(args, 01949 AST_APP_ARG(agent_id); 01950 AST_APP_ARG(options); 01951 AST_APP_ARG(extension); 01952 ); 01953 const char *tmpoptions = NULL; 01954 int play_announcement = 1; 01955 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01956 int update_cdr = updatecdr; 01957 char *filename = "agent-loginok"; 01958 01959 u = ast_module_user_add(chan); 01960 01961 parse = ast_strdupa(data); 01962 01963 AST_STANDARD_APP_ARGS(args, parse); 01964 01965 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01966 01967 ast_channel_lock(chan); 01968 /* Set Channel Specific Login Overrides */ 01969 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01970 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01971 if (max_login_tries < 0) 01972 max_login_tries = 0; 01973 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01974 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 01975 } 01976 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01977 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01978 update_cdr = 1; 01979 else 01980 update_cdr = 0; 01981 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01982 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01983 } 01984 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01985 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01986 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01987 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01988 } 01989 ast_channel_unlock(chan); 01990 /* End Channel Specific Login Overrides */ 01991 01992 if (!ast_strlen_zero(args.options)) { 01993 if (strchr(args.options, 's')) { 01994 play_announcement = 0; 01995 } 01996 } 01997 01998 if (chan->_state != AST_STATE_UP) 01999 res = ast_answer(chan); 02000 if (!res) { 02001 if (!ast_strlen_zero(args.agent_id)) 02002 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 02003 else 02004 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 02005 } 02006 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 02007 tries++; 02008 /* Check for password */ 02009 AST_LIST_LOCK(&agents); 02010 AST_LIST_TRAVERSE(&agents, p, list) { 02011 if (!strcmp(p->agent, user) && !p->pending) 02012 ast_copy_string(xpass, p->password, sizeof(xpass)); 02013 } 02014 AST_LIST_UNLOCK(&agents); 02015 if (!res) { 02016 if (!ast_strlen_zero(xpass)) 02017 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 02018 else 02019 pass[0] = '\0'; 02020 } 02021 errmsg = "agent-incorrect"; 02022 02023 #if 0 02024 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 02025 #endif 02026 02027 /* Check again for accuracy */ 02028 AST_LIST_LOCK(&agents); 02029 AST_LIST_TRAVERSE(&agents, p, list) { 02030 int unlock_channel = 1; 02031 ast_channel_lock(chan); 02032 ast_mutex_lock(&p->lock); 02033 if (!strcmp(p->agent, user) && 02034 !strcmp(p->password, pass) && !p->pending) { 02035 02036 /* Ensure we can't be gotten until we're done */ 02037 p->lastdisc = ast_tvnow(); 02038 p->lastdisc.tv_sec++; 02039 02040 /* Set Channel Specific Agent Overrides */ 02041 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02042 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02043 p->ackcall = 1; 02044 } else { 02045 p->ackcall = 0; 02046 } 02047 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02048 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 02049 ast_set_flag(p, AGENT_FLAG_ACKCALL); 02050 } else { 02051 p->ackcall = ackcall; 02052 } 02053 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02054 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02055 if (p->autologoff < 0) 02056 p->autologoff = 0; 02057 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02058 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 02059 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 02060 } else { 02061 p->autologoff = autologoff; 02062 } 02063 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02064 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02065 if (p->wrapuptime < 0) 02066 p->wrapuptime = 0; 02067 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02068 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 02069 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 02070 } else { 02071 p->wrapuptime = wrapuptime; 02072 } 02073 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF"); 02074 if (!ast_strlen_zero(tmpoptions)) { 02075 p->acceptdtmf = *tmpoptions; 02076 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 02077 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 02078 } 02079 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 02080 if (!ast_strlen_zero(tmpoptions)) { 02081 p->enddtmf = *tmpoptions; 02082 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 02083 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 02084 } 02085 ast_channel_unlock(chan); 02086 unlock_channel = 0; 02087 /* End Channel Specific Agent Overrides */ 02088 if (!p->chan) { 02089 long logintime; 02090 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02091 02092 p->logincallerid[0] = '\0'; 02093 p->acknowledged = 0; 02094 02095 ast_mutex_unlock(&p->lock); 02096 AST_LIST_UNLOCK(&agents); 02097 if( !res && play_announcement==1 ) 02098 res = ast_streamfile(chan, filename, chan->language); 02099 if (!res) 02100 ast_waitstream(chan, ""); 02101 AST_LIST_LOCK(&agents); 02102 ast_mutex_lock(&p->lock); 02103 if (!res) { 02104 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02105 if (res) 02106 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats))); 02107 } 02108 if (!res) { 02109 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02110 if (res) 02111 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats))); 02112 } 02113 /* Check once more just in case */ 02114 if (p->chan) 02115 res = -1; 02116 if (!res) { 02117 ast_indicate_data(chan, AST_CONTROL_HOLD, 02118 S_OR(p->moh, NULL), 02119 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02120 if (p->loginstart == 0) 02121 time(&p->loginstart); 02122 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02123 "Agent: %s\r\n" 02124 "Channel: %s\r\n" 02125 "Uniqueid: %s\r\n", 02126 p->agent, chan->name, chan->uniqueid); 02127 if (update_cdr && chan->cdr) 02128 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02129 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02130 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 02131 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02132 /* Login this channel and wait for it to go away */ 02133 p->chan = chan; 02134 if (p->ackcall) { 02135 check_beep(p, 0); 02136 } else { 02137 check_availability(p, 0); 02138 } 02139 ast_mutex_unlock(&p->lock); 02140 AST_LIST_UNLOCK(&agents); 02141 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02142 while (res >= 0) { 02143 ast_mutex_lock(&p->lock); 02144 if (p->deferlogoff && p->chan) { 02145 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02146 p->deferlogoff = 0; 02147 } 02148 if (p->chan != chan) 02149 res = -1; 02150 ast_mutex_unlock(&p->lock); 02151 /* Yield here so other interested threads can kick in. */ 02152 sched_yield(); 02153 if (res) 02154 break; 02155 02156 AST_LIST_LOCK(&agents); 02157 ast_mutex_lock(&p->lock); 02158 if (p->lastdisc.tv_sec) { 02159 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02160 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02161 p->lastdisc = ast_tv(0, 0); 02162 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02163 if (p->ackcall) { 02164 check_beep(p, 0); 02165 } else { 02166 check_availability(p, 0); 02167 } 02168 } 02169 } 02170 ast_mutex_unlock(&p->lock); 02171 AST_LIST_UNLOCK(&agents); 02172 02173 /* Synchronize channel ownership between call to agent and itself. */ 02174 ast_mutex_lock(&p->lock); 02175 if (p->app_lock_flag == 1) { 02176 ast_cond_signal(&p->login_wait_cond); 02177 ast_cond_wait(&p->app_complete_cond, &p->lock); 02178 } 02179 ast_mutex_unlock(&p->lock); 02180 if (p->ackcall) { 02181 res = agent_ack_sleep(p); 02182 } else { 02183 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02184 } 02185 if (p->ackcall && (res == 1)) { 02186 AST_LIST_LOCK(&agents); 02187 ast_mutex_lock(&p->lock); 02188 check_availability(p, 0); 02189 ast_mutex_unlock(&p->lock); 02190 AST_LIST_UNLOCK(&agents); 02191 res = 0; 02192 } 02193 sched_yield(); 02194 } 02195 ast_mutex_lock(&p->lock); 02196 /* Log us off if appropriate */ 02197 if (p->chan == chan) { 02198 p->chan = NULL; 02199 } 02200 02201 /* Synchronize channel ownership between call to agent and itself. */ 02202 if (p->app_lock_flag == 1) { 02203 ast_cond_signal(&p->login_wait_cond); 02204 ast_cond_wait(&p->app_complete_cond, &p->lock); 02205 } 02206 02207 if (res && p->owner) 02208 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02209 02210 p->acknowledged = 0; 02211 logintime = time(NULL) - p->loginstart; 02212 p->loginstart = 0; 02213 ast_mutex_unlock(&p->lock); 02214 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02215 "Agent: %s\r\n" 02216 "Logintime: %ld\r\n" 02217 "Uniqueid: %s\r\n", 02218 p->agent, logintime, chan->uniqueid); 02219 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02220 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02221 /* If there is no owner, go ahead and kill it now */ 02222 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02223 if (p->dead && !p->owner) { 02224 ast_mutex_destroy(&p->lock); 02225 ast_cond_destroy(&p->app_complete_cond); 02226 ast_cond_destroy(&p->login_wait_cond); 02227 ast_free(p); 02228 } 02229 } 02230 else { 02231 ast_mutex_unlock(&p->lock); 02232 p = NULL; 02233 } 02234 res = -1; 02235 } else { 02236 ast_mutex_unlock(&p->lock); 02237 errmsg = "agent-alreadyon"; 02238 p = NULL; 02239 } 02240 break; 02241 } 02242 ast_mutex_unlock(&p->lock); 02243 if (unlock_channel) { 02244 ast_channel_unlock(chan); 02245 } 02246 } 02247 if (!p) 02248 AST_LIST_UNLOCK(&agents); 02249 02250 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02251 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02252 } 02253 02254 if (!res) 02255 res = ast_safe_sleep(chan, 500); 02256 02257 ast_module_user_remove(u); 02258 02259 return -1; 02260 }
static force_inline int powerof | ( | unsigned int | d | ) | [static] |
Definition at line 1540 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 1150 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, 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_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, agent_pvt::dead, agent_pvt::lock, LOG_ERROR, LOG_NOTICE, agent_pvt::login_wait_cond, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01151 { 01152 struct ast_config *cfg; 01153 struct ast_config *ucfg; 01154 struct ast_variable *v; 01155 struct agent_pvt *p; 01156 const char *catname; 01157 const char *hasagent; 01158 int genhasagent; 01159 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01160 01161 group = 0; 01162 autologoff = 0; 01163 wrapuptime = 0; 01164 ackcall = 0; 01165 endcall = 1; 01166 cfg = ast_config_load(config, config_flags); 01167 if (!cfg) { 01168 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01169 return 0; 01170 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 01171 return -1; 01172 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 01173 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config); 01174 return 0; 01175 } 01176 if ((ucfg = ast_config_load("users.conf", config_flags))) { 01177 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { 01178 ucfg = NULL; 01179 } else if (ucfg == CONFIG_STATUS_FILEINVALID) { 01180 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n"); 01181 return 0; 01182 } 01183 } 01184 01185 AST_LIST_LOCK(&agents); 01186 AST_LIST_TRAVERSE(&agents, p, list) { 01187 p->dead = 1; 01188 } 01189 strcpy(moh, "default"); 01190 /* set the default recording values */ 01191 recordagentcalls = 0; 01192 strcpy(recordformat, "wav"); 01193 strcpy(recordformatext, "wav"); 01194 urlprefix[0] = '\0'; 01195 savecallsin[0] = '\0'; 01196 01197 /* Read in [general] section for persistence */ 01198 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01199 01200 /* Read in the [agents] section */ 01201 v = ast_variable_browse(cfg, "agents"); 01202 while(v) { 01203 /* Create the interface list */ 01204 if (!strcasecmp(v->name, "agent")) { 01205 add_agent(v->value, 0); 01206 } else if (!strcasecmp(v->name, "group")) { 01207 group = ast_get_group(v->value); 01208 } else if (!strcasecmp(v->name, "autologoff")) { 01209 autologoff = atoi(v->value); 01210 if (autologoff < 0) 01211 autologoff = 0; 01212 } else if (!strcasecmp(v->name, "ackcall")) { 01213 if (ast_true(v->value) || !strcasecmp(v->value, "always")) { 01214 ackcall = 1; 01215 } 01216 } else if (!strcasecmp(v->name, "endcall")) { 01217 endcall = ast_true(v->value); 01218 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01219 acceptdtmf = *(v->value); 01220 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01221 } else if (!strcasecmp(v->name, "enddtmf")) { 01222 enddtmf = *(v->value); 01223 } else if (!strcasecmp(v->name, "wrapuptime")) { 01224 wrapuptime = atoi(v->value); 01225 if (wrapuptime < 0) 01226 wrapuptime = 0; 01227 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01228 maxlogintries = atoi(v->value); 01229 if (maxlogintries < 0) 01230 maxlogintries = 0; 01231 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01232 strcpy(agentgoodbye,v->value); 01233 } else if (!strcasecmp(v->name, "musiconhold")) { 01234 ast_copy_string(moh, v->value, sizeof(moh)); 01235 } else if (!strcasecmp(v->name, "updatecdr")) { 01236 if (ast_true(v->value)) 01237 updatecdr = 1; 01238 else 01239 updatecdr = 0; 01240 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01241 if (ast_true(v->value)) 01242 autologoffunavail = 1; 01243 else 01244 autologoffunavail = 0; 01245 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01246 recordagentcalls = ast_true(v->value); 01247 } else if (!strcasecmp(v->name, "recordformat")) { 01248 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01249 if (!strcasecmp(v->value, "wav49")) 01250 strcpy(recordformatext, "WAV"); 01251 else 01252 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01253 } else if (!strcasecmp(v->name, "urlprefix")) { 01254 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01255 if (urlprefix[strlen(urlprefix) - 1] != '/') 01256 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01257 } else if (!strcasecmp(v->name, "savecallsin")) { 01258 if (v->value[0] == '/') 01259 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01260 else 01261 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01262 if (savecallsin[strlen(savecallsin) - 1] != '/') 01263 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01264 } else if (!strcasecmp(v->name, "custom_beep")) { 01265 ast_copy_string(beep, v->value, sizeof(beep)); 01266 } 01267 v = v->next; 01268 } 01269 if (ucfg) { 01270 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01271 catname = ast_category_browse(ucfg, NULL); 01272 while(catname) { 01273 if (strcasecmp(catname, "general")) { 01274 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01275 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01276 char tmp[256]; 01277 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01278 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01279 if (!fullname) 01280 fullname = ""; 01281 if (!secret) 01282 secret = ""; 01283 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01284 add_agent(tmp, 0); 01285 } 01286 } 01287 catname = ast_category_browse(ucfg, catname); 01288 } 01289 ast_config_destroy(ucfg); 01290 } 01291 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01292 if (p->dead) { 01293 AST_LIST_REMOVE_CURRENT(list); 01294 /* Destroy if appropriate */ 01295 if (!p->owner) { 01296 if (!p->chan) { 01297 ast_mutex_destroy(&p->lock); 01298 ast_cond_destroy(&p->app_complete_cond); 01299 ast_cond_destroy(&p->login_wait_cond); 01300 ast_free(p); 01301 } else { 01302 /* Cause them to hang up */ 01303 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01304 } 01305 } 01306 } 01307 } 01308 AST_LIST_TRAVERSE_SAFE_END; 01309 AST_LIST_UNLOCK(&agents); 01310 ast_config_destroy(cfg); 01311 return 1; 01312 }
static int reload | ( | void | ) | [static] |
Definition at line 2579 of file chan_agent.c.
References read_agent_config().
02580 { 02581 return read_agent_config(1); 02582 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2584 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.
02585 { 02586 struct agent_pvt *p; 02587 /* First, take us out of the channel loop */ 02588 ast_channel_unregister(&agent_tech); 02589 /* Unregister dialplan functions */ 02590 ast_custom_function_unregister(&agent_function); 02591 /* Unregister CLI commands */ 02592 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02593 /* Unregister dialplan applications */ 02594 ast_unregister_application(app); 02595 ast_unregister_application(app3); 02596 /* Unregister manager command */ 02597 ast_manager_unregister("Agents"); 02598 ast_manager_unregister("AgentLogoff"); 02599 /* Unregister the data tree */ 02600 ast_data_unregister(NULL); 02601 /* Unregister channel */ 02602 AST_LIST_LOCK(&agents); 02603 /* Hangup all interfaces if they have an owner */ 02604 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02605 if (p->owner) 02606 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02607 ast_free(p); 02608 } 02609 AST_LIST_UNLOCK(&agents); 02610 return 0; 02611 }
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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } [static] |
Definition at line 2619 of file chan_agent.c.
char acceptdtmf = DEFAULT_ACCEPTDTMF [static] |
int ackcall [static] |
Definition at line 224 of file chan_agent.c.
struct ast_custom_function agent_function [static] |
Initial value:
{ .name = "AGENT", .read = function_agent, }
Definition at line 2449 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 1914 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 353 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 232 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 2533 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 2538 of file chan_agent.c.
Referenced by load_module().
const char app[] = "AgentLogin" [static] |
Definition at line 206 of file chan_agent.c.
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 207 of file chan_agent.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2619 of file chan_agent.c.
int autologoff [static] |
Definition at line 222 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 227 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 240 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 1919 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char config[] = "agents.conf" [static] |
Definition at line 204 of file chan_agent.c.
int endcall [static] |
Definition at line 225 of file chan_agent.c.
char enddtmf = DEFAULT_ENDDTMF [static] |
Definition at line 229 of file chan_agent.c.
ast_group_t group [static] |
int maxlogintries = 3 [static] |
Definition at line 231 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 209 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 226 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 215 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 234 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 235 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 236 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 238 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 203 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 239 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
int wrapuptime [static] |
Definition at line 223 of file chan_agent.c.