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