#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/rtp.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"
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 | DEFAULT_ACCEPTDTMF '#' |
#define | DEFAULT_ENDDTMF '*' |
#define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
#define | PA_MAX_LEN 2048 |
Enumerations | |
enum | { AGENT_FLAG_ACKCALL = (1 << 0), AGENT_FLAG_AUTOLOGOFF = (1 << 1), AGENT_FLAG_WRAPUPTIME = (1 << 2), AGENT_FLAG_ACCEPTDTMF = (1 << 3), AGENT_FLAG_ENDDTMF = (1 << 4) } |
Functions | |
static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | action_agent_logoff (struct mansession *s, const struct message *m) |
static int | action_agents (struct mansession *s, const struct message *m) |
static struct agent_pvt * | add_agent (const char *agent, int pending) |
static int | agent_ack_sleep (void *data) |
static int | agent_answer (struct ast_channel *ast) |
static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
static int | agent_cleanup (struct agent_pvt *p) |
static int | agent_cont_sleep (void *data) |
static int | agent_devicestate (void *data) |
Part of PBX channel interface. | |
static int | agent_digit_begin (struct ast_channel *ast, char digit) |
static int | agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
static struct ast_channel * | agent_get_base_channel (struct ast_channel *chan) |
return the channel or base channel if one exists. This function assumes the channel it is called on is already locked | |
static int | agent_hangup (struct ast_channel *ast) |
static int | agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
static int | agent_logoff (const char *agent, int soft) |
static char * | agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static void | agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand) |
static struct ast_channel * | agent_new (struct agent_pvt *p, int state) |
Create new agent channel. | |
static struct ast_frame * | agent_read (struct ast_channel *ast) |
static struct ast_channel * | agent_request (const char *type, int format, 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, void *data) |
Called by the AgentMonitorOutgoing application (from the dial plan). | |
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) |
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 void | dump_agents (void) |
Dump AgentCallbackLogin agents to the ASTdb database for persistence. | |
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, void *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 void | reload_agents (void) |
Reload the persistent agents from astdb. | |
static void | set_agentbycallerid (const char *callerid, const char *agent) |
store/clear the global variable that stores agentid based on the callerid | |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } |
static char | acceptdtmf = DEFAULT_ACCEPTDTMF |
static int | ackcall |
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 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 const char | descrip [] |
static const char | descrip3 [] |
static int | endcall |
static char | enddtmf = DEFAULT_ENDDTMF |
static ast_group_t | group |
static const char | mandescr_agent_logoff [] |
static const char | mandescr_agents [] |
static int | maxlogintries = 3 |
static char | moh [80] = "default" |
static int | multiplelogin = 1 |
static const char | pa_family [] = "Agents" |
static int | persistent_agents = 0 |
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 | synopsis [] = "Call agent login" |
static const char | synopsis3 [] = "Record agent's outgoing call" |
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 118 of file chan_agent.c.
Referenced by agent_logoff_maintenance(), agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().
#define AST_MAX_BUF 256 |
Definition at line 119 of file chan_agent.c.
Referenced by __agent_start_monitoring(), agentmonitoroutgoing_exec(), agents_show(), agents_show_online(), and set_agentbycallerid().
#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 218 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
#define DEFAULT_ACCEPTDTMF '#' |
Definition at line 128 of file chan_agent.c.
#define DEFAULT_ENDDTMF '*' |
Definition at line 129 of file chan_agent.c.
#define GETAGENTBYCALLERID "AGENTBYCALLERID" |
Definition at line 152 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().
#define PA_MAX_LEN 2048 |
The maximum length of each persistent member agent database entry
Definition at line 123 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 154 of file chan_agent.c.
00154 { 00155 AGENT_FLAG_ACKCALL = (1 << 0), 00156 AGENT_FLAG_AUTOLOGOFF = (1 << 1), 00157 AGENT_FLAG_WRAPUPTIME = (1 << 2), 00158 AGENT_FLAG_ACCEPTDTMF = (1 << 3), 00159 AGENT_FLAG_ENDDTMF = (1 << 4), 00160 };
static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
struct agent_pvt * | p, | |||
int | needlock | |||
) | [static] |
Definition at line 413 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().
00414 { 00415 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00416 char filename[AST_MAX_BUF]; 00417 int res = -1; 00418 if (!p) 00419 return -1; 00420 if (!ast->monitor) { 00421 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00422 /* substitute . for - */ 00423 if ((pointer = strchr(filename, '.'))) 00424 *pointer = '-'; 00425 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00426 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT); 00427 ast_monitor_setjoinfiles(ast, 1); 00428 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00429 #if 0 00430 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00431 #endif 00432 if (!ast->cdr) 00433 ast->cdr = ast_cdr_alloc(); 00434 ast_cdr_setuserfield(ast, tmp2); 00435 res = 0; 00436 } else 00437 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00438 return res; 00439 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 2563 of file chan_agent.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2563 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 1682 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and s.
Referenced by load_module().
01683 { 01684 const char *agent = astman_get_header(m, "Agent"); 01685 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01686 int soft; 01687 int ret; /* return value of agent_logoff */ 01688 01689 if (ast_strlen_zero(agent)) { 01690 astman_send_error(s, m, "No agent specified"); 01691 return 0; 01692 } 01693 01694 soft = ast_true(soft_s) ? 1 : 0; 01695 ret = agent_logoff(agent, soft); 01696 if (ret == 0) 01697 astman_send_ack(s, m, "Agent logged out"); 01698 else 01699 astman_send_error(s, m, "No such agent"); 01700 01701 return 0; 01702 }
static int action_agents | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.
s | ||
m |
Definition at line 1479 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, ast_bridged_channel(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, s, S_OR, and status.
Referenced by load_module().
01480 { 01481 const char *id = astman_get_header(m,"ActionID"); 01482 char idText[256] = ""; 01483 char chanbuf[256]; 01484 struct agent_pvt *p; 01485 char *username = NULL; 01486 char *loginChan = NULL; 01487 char *talkingto = NULL; 01488 char *talkingtoChan = NULL; 01489 char *status = NULL; 01490 01491 if (!ast_strlen_zero(id)) 01492 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01493 astman_send_ack(s, m, "Agents will follow"); 01494 AST_LIST_LOCK(&agents); 01495 AST_LIST_TRAVERSE(&agents, p, list) { 01496 ast_mutex_lock(&p->lock); 01497 01498 /* Status Values: 01499 AGENT_LOGGEDOFF - Agent isn't logged in 01500 AGENT_IDLE - Agent is logged in, and waiting for call 01501 AGENT_ONCALL - Agent is logged in, and on a call 01502 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01503 01504 username = S_OR(p->name, "None"); 01505 01506 /* Set a default status. It 'should' get changed. */ 01507 status = "AGENT_UNKNOWN"; 01508 01509 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01510 loginChan = p->loginchan; 01511 talkingto = "n/a"; 01512 talkingtoChan = "n/a"; 01513 status = "AGENT_IDLE"; 01514 if (p->acknowledged) { 01515 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01516 loginChan = chanbuf; 01517 } 01518 } else if (p->chan) { 01519 loginChan = ast_strdupa(p->chan->name); 01520 if (p->owner && p->owner->_bridge) { 01521 talkingto = p->chan->cid.cid_num; 01522 if (ast_bridged_channel(p->owner)) 01523 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name); 01524 else 01525 talkingtoChan = "n/a"; 01526 status = "AGENT_ONCALL"; 01527 } else { 01528 talkingto = "n/a"; 01529 talkingtoChan = "n/a"; 01530 status = "AGENT_IDLE"; 01531 } 01532 } else { 01533 loginChan = "n/a"; 01534 talkingto = "n/a"; 01535 talkingtoChan = "n/a"; 01536 status = "AGENT_LOGGEDOFF"; 01537 } 01538 01539 astman_append(s, "Event: Agents\r\n" 01540 "Agent: %s\r\n" 01541 "Name: %s\r\n" 01542 "Status: %s\r\n" 01543 "LoggedInChan: %s\r\n" 01544 "LoggedInTime: %d\r\n" 01545 "TalkingTo: %s\r\n" 01546 "TalkingToChan: %s\r\n" 01547 "%s" 01548 "\r\n", 01549 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01550 ast_mutex_unlock(&p->lock); 01551 } 01552 AST_LIST_UNLOCK(&agents); 01553 astman_append(s, "Event: AgentsComplete\r\n" 01554 "%s" 01555 "\r\n",idText); 01556 return 0; 01557 }
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 284 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, AST_APP_ARG, ast_calloc, ast_cond_init(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::enddtmf, agent_pvt::lastdisc, agent_pvt::list, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00285 { 00286 char *parse; 00287 AST_DECLARE_APP_ARGS(args, 00288 AST_APP_ARG(agt); 00289 AST_APP_ARG(password); 00290 AST_APP_ARG(name); 00291 ); 00292 char *password = NULL; 00293 char *name = NULL; 00294 char *agt = NULL; 00295 struct agent_pvt *p; 00296 00297 parse = ast_strdupa(agent); 00298 00299 /* Extract username (agt), password and name from agent (args). */ 00300 AST_STANDARD_APP_ARGS(args, parse); 00301 00302 if(args.argc == 0) { 00303 ast_log(LOG_WARNING, "A blank agent line!\n"); 00304 return NULL; 00305 } 00306 00307 if(ast_strlen_zero(args.agt) ) { 00308 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00309 return NULL; 00310 } else 00311 agt = args.agt; 00312 00313 if(!ast_strlen_zero(args.password)) { 00314 password = args.password; 00315 while (*password && *password < 33) password++; 00316 } 00317 if(!ast_strlen_zero(args.name)) { 00318 name = args.name; 00319 while (*name && *name < 33) name++; 00320 } 00321 00322 /* Are we searching for the agent here ? To see if it exists already ? */ 00323 AST_LIST_TRAVERSE(&agents, p, list) { 00324 if (!pending && !strcmp(p->agent, agt)) 00325 break; 00326 } 00327 if (!p) { 00328 // Build the agent. 00329 if (!(p = ast_calloc(1, sizeof(*p)))) 00330 return NULL; 00331 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00332 ast_mutex_init(&p->lock); 00333 ast_mutex_init(&p->app_lock); 00334 ast_cond_init(&p->app_complete_cond, NULL); 00335 p->app_lock_flag = 0; 00336 p->app_sleep_cond = 1; 00337 p->group = group; 00338 p->pending = pending; 00339 AST_LIST_INSERT_TAIL(&agents, p, list); 00340 } 00341 00342 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00343 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00344 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00345 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) { 00346 p->ackcall = ackcall; 00347 } 00348 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) { 00349 p->autologoff = autologoff; 00350 } 00351 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) { 00352 p->acceptdtmf = acceptdtmf; 00353 } 00354 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) { 00355 p->enddtmf = enddtmf; 00356 } 00357 00358 /* If someone reduces the wrapuptime and reloads, we want it 00359 * to change the wrapuptime immediately on all calls */ 00360 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) { 00361 struct timeval now = ast_tvnow(); 00362 /* XXX check what is this exactly */ 00363 00364 /* We won't be pedantic and check the tv_usec val */ 00365 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00366 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00367 p->lastdisc.tv_usec = now.tv_usec; 00368 } 00369 } 00370 p->wrapuptime = wrapuptime; 00371 00372 if (pending) 00373 p->dead = 1; 00374 else 00375 p->dead = 0; 00376 return p; 00377 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 955 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().
00956 { 00957 struct agent_pvt *p; 00958 int res=0; 00959 int to = 1000; 00960 struct ast_frame *f; 00961 00962 /* Wait a second and look for something */ 00963 00964 p = (struct agent_pvt *) data; 00965 if (!p->chan) 00966 return -1; 00967 00968 for(;;) { 00969 to = ast_waitfor(p->chan, to); 00970 if (to < 0) 00971 return -1; 00972 if (!to) 00973 return 0; 00974 f = ast_read(p->chan); 00975 if (!f) 00976 return -1; 00977 if (f->frametype == AST_FRAME_DTMF) 00978 res = f->subclass; 00979 else 00980 res = 0; 00981 ast_frfree(f); 00982 ast_mutex_lock(&p->lock); 00983 if (!p->app_sleep_cond) { 00984 ast_mutex_unlock(&p->lock); 00985 return 0; 00986 } else if (res == p->acceptdtmf) { 00987 ast_mutex_unlock(&p->lock); 00988 return 1; 00989 } 00990 ast_mutex_unlock(&p->lock); 00991 res = 0; 00992 } 00993 return res; 00994 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 407 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00408 { 00409 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00410 return -1; 00411 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Definition at line 996 of file chan_agent.c.
References ast_channel::_bridge, ast_debug, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.
00997 { 00998 struct agent_pvt *p = bridge->tech_pvt; 00999 struct ast_channel *ret = NULL; 01000 01001 if (p) { 01002 if (chan == p->chan) 01003 ret = bridge->_bridge; 01004 else if (chan == bridge->_bridge) 01005 ret = p->chan; 01006 } 01007 01008 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 01009 return ret; 01010 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 697 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_best_codec(), ast_call(), ast_channel_inherit_variables(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_callerid(), ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLEANUP, ast_channel::language, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, ast_channel::name, ast_channel::nativeformats, agent_pvt::pending, agent_pvt::start, and ast_channel::tech_pvt.
00698 { 00699 struct agent_pvt *p = ast->tech_pvt; 00700 int res = -1; 00701 int newstate=0; 00702 ast_mutex_lock(&p->lock); 00703 p->acknowledged = 0; 00704 if (!p->chan) { 00705 if (p->pending) { 00706 ast_debug(1, "Pretending to dial on pending agent\n"); 00707 newstate = AST_STATE_DIALING; 00708 res = 0; 00709 } else { 00710 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00711 res = -1; 00712 } 00713 ast_mutex_unlock(&p->lock); 00714 if (newstate) 00715 ast_setstate(ast, newstate); 00716 return res; 00717 } else if (!ast_strlen_zero(p->loginchan)) { 00718 time(&p->start); 00719 /* Call on this agent */ 00720 ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00721 ast_set_callerid(p->chan, 00722 ast->cid.cid_num, ast->cid.cid_name, NULL); 00723 ast_channel_inherit_variables(ast, p->chan); 00724 res = ast_call(p->chan, p->loginchan, 0); 00725 CLEANUP(ast,p); 00726 ast_mutex_unlock(&p->lock); 00727 return res; 00728 } 00729 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00730 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language); 00731 res = ast_streamfile(p->chan, beep, p->chan->language); 00732 ast_debug(3, "Played beep, result '%d'\n", res); 00733 if (!res) { 00734 res = ast_waitstream(p->chan, ""); 00735 ast_debug(3, "Waited for stream, result '%d'\n", res); 00736 } 00737 if (!res) { 00738 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00739 ast_debug(3, "Set read format, result '%d'\n", res); 00740 if (res) 00741 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00742 } else { 00743 /* Agent hung-up */ 00744 p->chan = NULL; 00745 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00746 } 00747 00748 if (!res) { 00749 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00750 ast_debug(3, "Set write format, result '%d'\n", res); 00751 if (res) 00752 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00753 } 00754 if(!res) { 00755 /* Call is immediately up, or might need ack */ 00756 if (p->ackcall > 1) 00757 newstate = AST_STATE_RINGING; 00758 else { 00759 newstate = AST_STATE_UP; 00760 if (recordagentcalls) 00761 agent_start_monitoring(ast, 0); 00762 p->acknowledged = 1; 00763 } 00764 res = 0; 00765 } 00766 CLEANUP(ast, p); 00767 ast_mutex_unlock(&p->lock); 00768 if (newstate) 00769 ast_setstate(ast, newstate); 00770 return res; 00771 }
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 385 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_free(), ast_cond_destroy(), ast_cond_signal(), ast_free, ast_mutex_destroy(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00386 { 00387 struct ast_channel *chan = p->owner; 00388 p->owner = NULL; 00389 chan->tech_pvt = NULL; 00390 p->app_sleep_cond = 1; 00391 /* Release ownership of the agent to other threads (presumably running the login app). */ 00392 p->app_lock_flag = 0; 00393 ast_cond_signal(&p->app_complete_cond); 00394 if (chan) 00395 ast_channel_free(chan); 00396 if (p->dead) { 00397 ast_mutex_destroy(&p->lock); 00398 ast_mutex_destroy(&p->app_lock); 00399 ast_cond_destroy(&p->app_complete_cond); 00400 ast_free(p); 00401 } 00402 return 0; 00403 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 934 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().
00935 { 00936 struct agent_pvt *p; 00937 int res; 00938 00939 p = (struct agent_pvt *)data; 00940 00941 ast_mutex_lock(&p->lock); 00942 res = p->app_sleep_cond; 00943 if (p->lastdisc.tv_sec) { 00944 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 00945 res = 1; 00946 } 00947 ast_mutex_unlock(&p->lock); 00948 00949 if (!res) 00950 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 00951 00952 return res; 00953 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2355 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(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
02356 { 02357 struct agent_pvt *p; 02358 char *s; 02359 ast_group_t groupmatch; 02360 int groupoff; 02361 int res = AST_DEVICE_INVALID; 02362 02363 s = data; 02364 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) 02365 groupmatch = (1 << groupoff); 02366 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02367 groupmatch = (1 << groupoff); 02368 } else 02369 groupmatch = 0; 02370 02371 /* Check actual logged in agents first */ 02372 AST_LIST_LOCK(&agents); 02373 AST_LIST_TRAVERSE(&agents, p, list) { 02374 ast_mutex_lock(&p->lock); 02375 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02376 if (p->owner) { 02377 if (res != AST_DEVICE_INUSE) 02378 res = AST_DEVICE_BUSY; 02379 } else { 02380 if (res == AST_DEVICE_BUSY) 02381 res = AST_DEVICE_INUSE; 02382 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02383 if (res == AST_DEVICE_INVALID) 02384 res = AST_DEVICE_UNKNOWN; 02385 } else if (res == AST_DEVICE_INVALID) 02386 res = AST_DEVICE_UNAVAILABLE; 02387 } 02388 if (!strcmp(data, p->agent)) { 02389 ast_mutex_unlock(&p->lock); 02390 break; 02391 } 02392 } 02393 ast_mutex_unlock(&p->lock); 02394 } 02395 AST_LIST_UNLOCK(&agents); 02396 return res; 02397 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 675 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.
00676 { 00677 struct agent_pvt *p = ast->tech_pvt; 00678 ast_mutex_lock(&p->lock); 00679 if (p->chan) { 00680 ast_senddigit_begin(p->chan, digit); 00681 } 00682 ast_mutex_unlock(&p->lock); 00683 return 0; 00684 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 686 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.
00687 { 00688 struct agent_pvt *p = ast->tech_pvt; 00689 ast_mutex_lock(&p->lock); 00690 if (p->chan) { 00691 ast_senddigit_end(p->chan, digit, duration); 00692 } 00693 ast_mutex_unlock(&p->lock); 00694 return 0; 00695 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 642 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.
00643 { 00644 struct agent_pvt *p = newchan->tech_pvt; 00645 ast_mutex_lock(&p->lock); 00646 if (p->owner != oldchan) { 00647 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00648 ast_mutex_unlock(&p->lock); 00649 return -1; 00650 } 00651 p->owner = newchan; 00652 ast_mutex_unlock(&p->lock); 00653 return 0; 00654 }
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 787 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00788 { 00789 struct agent_pvt *p = NULL; 00790 struct ast_channel *base = chan; 00791 00792 /* chan is locked by the calling function */ 00793 if (!chan || !chan->tech_pvt) { 00794 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); 00795 return NULL; 00796 } 00797 p = chan->tech_pvt; 00798 if (p->chan) 00799 base = p->chan; 00800 return base; 00801 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 820 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), AST_CONTROL_HOLD, ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_hangup(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, status, ast_channel::tech_pvt, ast_channel::uniqueid, and agent_pvt::wrapuptime.
00821 { 00822 struct agent_pvt *p = ast->tech_pvt; 00823 int howlong = 0; 00824 const char *status; 00825 ast_mutex_lock(&p->lock); 00826 p->owner = NULL; 00827 ast->tech_pvt = NULL; 00828 p->app_sleep_cond = 1; 00829 p->acknowledged = 0; 00830 00831 /* if they really are hung up then set start to 0 so the test 00832 * later if we're called on an already downed channel 00833 * doesn't cause an agent to be logged out like when 00834 * agent_request() is followed immediately by agent_hangup() 00835 * as in apps/app_chanisavail.c:chanavail_exec() 00836 */ 00837 00838 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00839 if (p->start && (ast->_state != AST_STATE_UP)) { 00840 howlong = time(NULL) - p->start; 00841 p->start = 0; 00842 } else if (ast->_state == AST_STATE_RESERVED) 00843 howlong = 0; 00844 else 00845 p->start = 0; 00846 if (p->chan) { 00847 p->chan->_bridge = NULL; 00848 /* If they're dead, go ahead and hang up on the agent now */ 00849 if (!ast_strlen_zero(p->loginchan)) { 00850 /* Store last disconnect time */ 00851 if (p->wrapuptime) 00852 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00853 else 00854 p->lastdisc = ast_tv(0,0); 00855 if (p->chan) { 00856 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00857 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00858 long logintime = time(NULL) - p->loginstart; 00859 p->loginstart = 0; 00860 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00861 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00862 } 00863 /* Recognize the hangup and pass it along immediately */ 00864 ast_hangup(p->chan); 00865 p->chan = NULL; 00866 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00867 } 00868 ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00869 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00870 long logintime = time(NULL) - p->loginstart; 00871 p->loginstart = 0; 00872 if (!p->deferlogoff) 00873 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00874 p->deferlogoff = 0; 00875 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00876 if (persistent_agents) 00877 dump_agents(); 00878 } 00879 } else if (p->dead) { 00880 ast_channel_lock(p->chan); 00881 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00882 ast_channel_unlock(p->chan); 00883 } else if (p->loginstart) { 00884 ast_channel_lock(p->chan); 00885 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00886 S_OR(p->moh, NULL), 00887 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00888 ast_channel_unlock(p->chan); 00889 } 00890 } 00891 ast_mutex_unlock(&p->lock); 00892 00893 /* Only register a device state change if the agent is still logged in */ 00894 if (!p->loginstart) { 00895 p->loginchan[0] = '\0'; 00896 p->logincallerid[0] = '\0'; 00897 if (persistent_agents) 00898 dump_agents(); 00899 } else { 00900 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00901 } 00902 00903 if (p->pending) { 00904 AST_LIST_LOCK(&agents); 00905 AST_LIST_REMOVE(&agents, p, list); 00906 AST_LIST_UNLOCK(&agents); 00907 } 00908 if (p->abouttograb) { 00909 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00910 kill it later */ 00911 p->abouttograb = 0; 00912 } else if (p->dead) { 00913 ast_mutex_destroy(&p->lock); 00914 ast_mutex_destroy(&p->app_lock); 00915 ast_cond_destroy(&p->app_complete_cond); 00916 ast_free(p); 00917 } else { 00918 if (p->chan) { 00919 /* Not dead -- check availability now */ 00920 ast_mutex_lock(&p->lock); 00921 /* Store last disconnect time */ 00922 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00923 ast_mutex_unlock(&p->lock); 00924 } 00925 /* Release ownership of the agent to other threads (presumably running the login app). */ 00926 if (ast_strlen_zero(p->loginchan)) { 00927 p->app_lock_flag = 0; 00928 ast_cond_signal(&p->app_complete_cond); 00929 } 00930 } 00931 return 0; 00932 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 656 of file chan_agent.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, ast_channel::tech, and ast_channel::tech_pvt.
00657 { 00658 struct agent_pvt *p = ast->tech_pvt; 00659 int res = -1; 00660 ast_mutex_lock(&p->lock); 00661 if (p->chan && !ast_check_hangup(p->chan)) { 00662 while (ast_channel_trylock(p->chan)) { 00663 ast_channel_unlock(ast); 00664 usleep(1); 00665 ast_channel_lock(ast); 00666 } 00667 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00668 ast_channel_unlock(p->chan); 00669 } else 00670 res = 0; 00671 ast_mutex_unlock(&p->lock); 00672 return res; 00673 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1598 of file chan_agent.c.
References agent_pvt::agent, agent_logoff_maintenance(), ast_channel_trylock, ast_channel_unlock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, DEADLOCK_AVOIDANCE, agent_pvt::deferlogoff, agent_pvt::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.
Referenced by action_agent_logoff(), and agent_logoff_cmd().
01599 { 01600 struct agent_pvt *p; 01601 long logintime; 01602 int ret = -1; /* Return -1 if no agent if found */ 01603 01604 AST_LIST_LOCK(&agents); 01605 AST_LIST_TRAVERSE(&agents, p, list) { 01606 if (!strcasecmp(p->agent, agent)) { 01607 ret = 0; 01608 if (p->owner || p->chan) { 01609 if (!soft) { 01610 ast_mutex_lock(&p->lock); 01611 01612 while (p->owner && ast_channel_trylock(p->owner)) { 01613 DEADLOCK_AVOIDANCE(&p->lock); 01614 } 01615 if (p->owner) { 01616 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01617 ast_channel_unlock(p->owner); 01618 } 01619 01620 while (p->chan && ast_channel_trylock(p->chan)) { 01621 DEADLOCK_AVOIDANCE(&p->lock); 01622 } 01623 if (p->chan) { 01624 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01625 ast_channel_unlock(p->chan); 01626 } 01627 01628 ast_mutex_unlock(&p->lock); 01629 } else 01630 p->deferlogoff = 1; 01631 } else { 01632 logintime = time(NULL) - p->loginstart; 01633 p->loginstart = 0; 01634 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01635 } 01636 break; 01637 } 01638 } 01639 AST_LIST_UNLOCK(&agents); 01640 01641 return ret; 01642 }
static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1644 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_agent_logoff_cmd(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
01645 { 01646 int ret; 01647 char *agent; 01648 01649 switch (cmd) { 01650 case CLI_INIT: 01651 e->command = "agent logoff"; 01652 e->usage = 01653 "Usage: agent logoff <channel> [soft]\n" 01654 " Sets an agent as no longer logged in.\n" 01655 " If 'soft' is specified, do not hangup existing calls.\n"; 01656 return NULL; 01657 case CLI_GENERATE: 01658 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01659 } 01660 01661 if (a->argc < 3 || a->argc > 4) 01662 return CLI_SHOWUSAGE; 01663 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01664 return CLI_SHOWUSAGE; 01665 01666 agent = a->argv[2] + 6; 01667 ret = agent_logoff(agent, a->argc == 4); 01668 if (ret == 0) 01669 ast_cli(a->fd, "Logging out %s\n", agent); 01670 01671 return CLI_SUCCESS; 01672 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1559 of file chan_agent.c.
References agent_pvt::agent, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_MAX_AGENT, ast_queue_log(), ast_strdupa, ast_strlen_zero(), dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event, and set_agentbycallerid().
Referenced by agent_hangup(), agent_logoff(), and agent_read().
01560 { 01561 char *tmp = NULL; 01562 char agent[AST_MAX_AGENT]; 01563 01564 if (!ast_strlen_zero(logcommand)) 01565 tmp = logcommand; 01566 else 01567 tmp = ast_strdupa(""); 01568 01569 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01570 01571 if (!ast_strlen_zero(uniqueid)) { 01572 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01573 "Agent: %s\r\n" 01574 "Reason: %s\r\n" 01575 "Loginchan: %s\r\n" 01576 "Logintime: %ld\r\n" 01577 "Uniqueid: %s\r\n", 01578 p->agent, tmp, loginchan, logintime, uniqueid); 01579 } else { 01580 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01581 "Agent: %s\r\n" 01582 "Reason: %s\r\n" 01583 "Loginchan: %s\r\n" 01584 "Logintime: %ld\r\n", 01585 p->agent, tmp, loginchan, logintime); 01586 } 01587 01588 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01589 set_agentbycallerid(p->logincallerid, NULL); 01590 p->loginchan[0] ='\0'; 01591 p->logincallerid[0] = '\0'; 01592 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 01593 if (persistent_agents) 01594 dump_agents(); 01595 01596 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static] |
Create new agent channel.
Definition at line 1013 of file chan_agent.c.
References agent_pvt::agent, agent_tech, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_alloc, ast_channel_free(), ast_cond_signal(), AST_CONTROL_UNHOLD, ast_copy_string(), AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, ast_strlen_zero(), agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, agent_pvt::loginchan, 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().
01014 { 01015 struct ast_channel *tmp; 01016 int alreadylocked; 01017 #if 0 01018 if (!p->chan) { 01019 ast_log(LOG_WARNING, "No channel? :(\n"); 01020 return NULL; 01021 } 01022 #endif 01023 if (p->pending) 01024 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff); 01025 else 01026 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 01027 if (!tmp) { 01028 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01029 return NULL; 01030 } 01031 01032 tmp->tech = &agent_tech; 01033 if (p->chan) { 01034 tmp->nativeformats = p->chan->nativeformats; 01035 tmp->writeformat = p->chan->writeformat; 01036 tmp->rawwriteformat = p->chan->writeformat; 01037 tmp->readformat = p->chan->readformat; 01038 tmp->rawreadformat = p->chan->readformat; 01039 ast_string_field_set(tmp, language, p->chan->language); 01040 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01041 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01042 /* XXX Is this really all we copy form the originating channel?? */ 01043 } else { 01044 tmp->nativeformats = AST_FORMAT_SLINEAR; 01045 tmp->writeformat = AST_FORMAT_SLINEAR; 01046 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01047 tmp->readformat = AST_FORMAT_SLINEAR; 01048 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01049 } 01050 /* Safe, agentlock already held */ 01051 tmp->tech_pvt = p; 01052 p->owner = tmp; 01053 tmp->priority = 1; 01054 /* Wake up and wait for other applications (by definition the login app) 01055 * to release this channel). Takes ownership of the agent channel 01056 * to this thread only. 01057 * For signalling the other thread, ast_queue_frame is used until we 01058 * can safely use signals for this purpose. The pselect() needs to be 01059 * implemented in the kernel for this. 01060 */ 01061 p->app_sleep_cond = 0; 01062 01063 alreadylocked = p->app_lock_flag; 01064 p->app_lock_flag = 1; 01065 01066 if(ast_strlen_zero(p->loginchan) && alreadylocked) { 01067 if (p->chan) { 01068 ast_queue_frame(p->chan, &ast_null_frame); 01069 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01070 p->app_lock_flag = 1; 01071 ast_mutex_lock(&p->lock); 01072 } else { 01073 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01074 p->owner = NULL; 01075 tmp->tech_pvt = NULL; 01076 p->app_sleep_cond = 1; 01077 ast_channel_free( tmp ); 01078 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01079 p->app_lock_flag = 0; 01080 ast_cond_signal(&p->app_complete_cond); 01081 return NULL; 01082 } 01083 } else if (!ast_strlen_zero(p->loginchan)) { 01084 if (p->chan) 01085 ast_queue_frame(p->chan, &ast_null_frame); 01086 if (!p->chan) { 01087 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01088 p->owner = NULL; 01089 tmp->tech_pvt = NULL; 01090 p->app_sleep_cond = 1; 01091 ast_channel_free( tmp ); 01092 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01093 return NULL; 01094 } 01095 } 01096 if (p->chan) 01097 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01098 return tmp; 01099 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 446 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_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_ANSWER, ast_copy_flags, ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, agent_pvt::enddtmf, f, ast_channel::fdno, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, ast_channel::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, status, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, and agent_pvt::wrapuptime.
00447 { 00448 struct agent_pvt *p = ast->tech_pvt; 00449 struct ast_frame *f = NULL; 00450 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00451 const char *status; 00452 int cur_time = time(NULL); 00453 ast_mutex_lock(&p->lock); 00454 CHECK_FORMATS(ast, p); 00455 if (!p->start) { 00456 p->start = cur_time; 00457 } 00458 if (p->chan) { 00459 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00460 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00461 f = ast_read(p->chan); 00462 } else 00463 f = &ast_null_frame; 00464 if (!f) { 00465 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00466 if (p->chan) { 00467 p->chan->_bridge = NULL; 00468 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00469 for us when the PBX instance that called login finishes */ 00470 if (!ast_strlen_zero(p->loginchan)) { 00471 if (p->chan) 00472 ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00473 if (p->owner->_state != AST_STATE_UP) { 00474 int howlong = cur_time - p->start; 00475 if (p->autologoff && howlong >= p->autologoff) { 00476 p->loginstart = 0; 00477 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00478 agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff"); 00479 } 00480 } 00481 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00482 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00483 long logintime = cur_time - p->loginstart; 00484 p->loginstart = 0; 00485 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00486 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00487 } 00488 ast_hangup(p->chan); 00489 if (p->wrapuptime && p->acknowledged) 00490 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00491 } 00492 p->chan = NULL; 00493 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00494 p->acknowledged = 0; 00495 } 00496 } else { 00497 /* if acknowledgement is not required, and the channel is up, we may have missed 00498 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00499 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00500 p->acknowledged = 1; 00501 } 00502 00503 if (!p->acknowledged) { 00504 int howlong = cur_time - p->start; 00505 if (p->autologoff && (howlong >= p->autologoff)) { 00506 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00507 agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff"); 00508 if (p->owner || p->chan) { 00509 while (p->owner && ast_channel_trylock(p->owner)) { 00510 DEADLOCK_AVOIDANCE(&p->lock); 00511 } 00512 if (p->owner) { 00513 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 00514 ast_channel_unlock(p->owner); 00515 } 00516 00517 while (p->chan && ast_channel_trylock(p->chan)) { 00518 DEADLOCK_AVOIDANCE(&p->lock); 00519 } 00520 if (p->chan) { 00521 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00522 ast_channel_unlock(p->chan); 00523 } 00524 } else { 00525 long logintime; 00526 logintime = time(NULL) - p->loginstart; 00527 p->loginstart = 0; 00528 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 00529 } 00530 } 00531 } 00532 switch (f->frametype) { 00533 case AST_FRAME_CONTROL: 00534 if (f->subclass == AST_CONTROL_ANSWER) { 00535 if (p->ackcall) { 00536 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); 00537 /* Don't pass answer along */ 00538 ast_frfree(f); 00539 f = &ast_null_frame; 00540 } else { 00541 p->acknowledged = 1; 00542 /* Use the builtin answer frame for the 00543 recording start check below. */ 00544 ast_frfree(f); 00545 f = &answer_frame; 00546 } 00547 } 00548 break; 00549 case AST_FRAME_DTMF_BEGIN: 00550 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00551 if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){ 00552 ast_frfree(f); 00553 f = &ast_null_frame; 00554 } 00555 break; 00556 case AST_FRAME_DTMF_END: 00557 if (!p->acknowledged && (f->subclass == p->acceptdtmf)) { 00558 ast_verb(3, "%s acknowledged\n", p->chan->name); 00559 p->acknowledged = 1; 00560 ast_frfree(f); 00561 f = &answer_frame; 00562 } else if (f->subclass == p->enddtmf && endcall) { 00563 /* terminates call */ 00564 ast_frfree(f); 00565 f = NULL; 00566 } 00567 break; 00568 case AST_FRAME_VOICE: 00569 case AST_FRAME_VIDEO: 00570 /* don't pass voice or video until the call is acknowledged */ 00571 if (!p->acknowledged) { 00572 ast_frfree(f); 00573 f = &ast_null_frame; 00574 } 00575 default: 00576 /* pass everything else on through */ 00577 break; 00578 } 00579 } 00580 00581 CLEANUP(ast,p); 00582 if (p->chan && !p->chan->_bridge) { 00583 if (strcasecmp(p->chan->tech->type, "Local")) { 00584 p->chan->_bridge = ast; 00585 if (p->chan) 00586 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00587 } 00588 } 00589 ast_mutex_unlock(&p->lock); 00590 if (recordagentcalls && f == &answer_frame) 00591 agent_start_monitoring(ast,0); 00592 return f; 00593 }
static struct ast_channel * agent_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of the Asterisk PBX interface.
Definition at line 1366 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), AST_STATE_DOWN, ast_strlen_zero(), ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
01367 { 01368 struct agent_pvt *p; 01369 struct ast_channel *chan = NULL; 01370 char *s; 01371 ast_group_t groupmatch; 01372 int groupoff; 01373 int waitforagent=0; 01374 int hasagent = 0; 01375 struct timeval now; 01376 01377 s = data; 01378 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01379 groupmatch = (1 << groupoff); 01380 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01381 groupmatch = (1 << groupoff); 01382 waitforagent = 1; 01383 } else 01384 groupmatch = 0; 01385 01386 /* Check actual logged in agents first */ 01387 AST_LIST_LOCK(&agents); 01388 AST_LIST_TRAVERSE(&agents, p, list) { 01389 ast_mutex_lock(&p->lock); 01390 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01391 ast_strlen_zero(p->loginchan)) { 01392 if (p->chan) 01393 hasagent++; 01394 now = ast_tvnow(); 01395 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01396 p->lastdisc = ast_tv(0, 0); 01397 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01398 if (!p->owner && p->chan) { 01399 /* Fixed agent */ 01400 chan = agent_new(p, AST_STATE_DOWN); 01401 } 01402 if (chan) { 01403 ast_mutex_unlock(&p->lock); 01404 break; 01405 } 01406 } 01407 } 01408 ast_mutex_unlock(&p->lock); 01409 } 01410 if (!p) { 01411 AST_LIST_TRAVERSE(&agents, p, list) { 01412 ast_mutex_lock(&p->lock); 01413 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01414 if (p->chan || !ast_strlen_zero(p->loginchan)) 01415 hasagent++; 01416 now = ast_tvnow(); 01417 #if 0 01418 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec); 01419 #endif 01420 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01421 p->lastdisc = ast_tv(0, 0); 01422 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01423 if (!p->owner && p->chan) { 01424 /* Could still get a fixed agent */ 01425 chan = agent_new(p, AST_STATE_DOWN); 01426 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01427 /* Adjustable agent */ 01428 p->chan = ast_request("Local", format, p->loginchan, cause); 01429 if (p->chan) 01430 chan = agent_new(p, AST_STATE_DOWN); 01431 } 01432 if (chan) { 01433 ast_mutex_unlock(&p->lock); 01434 break; 01435 } 01436 } 01437 } 01438 ast_mutex_unlock(&p->lock); 01439 } 01440 } 01441 01442 if (!chan && waitforagent) { 01443 /* No agent available -- but we're requesting to wait for one. 01444 Allocate a place holder */ 01445 if (hasagent) { 01446 ast_debug(1, "Creating place holder for '%s'\n", s); 01447 p = add_agent(data, 1); 01448 p->group = groupmatch; 01449 chan = agent_new(p, AST_STATE_DOWN); 01450 if (!chan) 01451 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01452 } else { 01453 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01454 } 01455 } 01456 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01457 AST_LIST_UNLOCK(&agents); 01458 return chan; 01459 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 595 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.
00596 { 00597 struct agent_pvt *p = ast->tech_pvt; 00598 int res = -1; 00599 ast_mutex_lock(&p->lock); 00600 if (p->chan) 00601 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00602 ast_mutex_unlock(&p->lock); 00603 return res; 00604 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 606 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.
00607 { 00608 struct agent_pvt *p = ast->tech_pvt; 00609 int res = -1; 00610 ast_mutex_lock(&p->lock); 00611 if (p->chan) 00612 res = ast_sendtext(p->chan, text); 00613 ast_mutex_unlock(&p->lock); 00614 return res; 00615 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 803 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.
00804 { 00805 struct agent_pvt *p = NULL; 00806 00807 if (!chan || !base) { 00808 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00809 return -1; 00810 } 00811 p = chan->tech_pvt; 00812 if (!p) { 00813 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00814 return -1; 00815 } 00816 p->chan = base; 00817 return 0; 00818 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 441 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00442 { 00443 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00444 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 617 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.
00618 { 00619 struct agent_pvt *p = ast->tech_pvt; 00620 int res = -1; 00621 CHECK_FORMATS(ast, p); 00622 ast_mutex_lock(&p->lock); 00623 if (!p->chan) 00624 res = 0; 00625 else { 00626 if ((f->frametype != AST_FRAME_VOICE) || 00627 (f->frametype != AST_FRAME_VIDEO) || 00628 (f->subclass == p->chan->writeformat)) { 00629 res = ast_write(p->chan, f); 00630 } else { 00631 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00632 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00633 ast->name, p->chan->name); 00634 res = 0; 00635 } 00636 } 00637 CLEANUP(ast, p); 00638 ast_mutex_unlock(&p->lock); 00639 return res; 00640 }
static int agentmonitoroutgoing_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Called by the AgentMonitorOutgoing application (from the dial plan).
chan | ||
data |
Definition at line 2226 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_channel::cdr, agent_pvt::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, GETAGENTBYCALLERID, agent_pvt::list, LOG_WARNING, and pbx_builtin_getvar_helper().
Referenced by load_module().
02227 { 02228 int exitifnoagentid = 0; 02229 int nowarnings = 0; 02230 int changeoutgoing = 0; 02231 int res = 0; 02232 char agent[AST_MAX_AGENT]; 02233 02234 if (data) { 02235 if (strchr(data, 'd')) 02236 exitifnoagentid = 1; 02237 if (strchr(data, 'n')) 02238 nowarnings = 1; 02239 if (strchr(data, 'c')) 02240 changeoutgoing = 1; 02241 } 02242 if (chan->cid.cid_num) { 02243 const char *tmp; 02244 char agentvar[AST_MAX_BUF]; 02245 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02246 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02247 struct agent_pvt *p; 02248 ast_copy_string(agent, tmp, sizeof(agent)); 02249 AST_LIST_LOCK(&agents); 02250 AST_LIST_TRAVERSE(&agents, p, list) { 02251 if (!strcasecmp(p->agent, tmp)) { 02252 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02253 __agent_start_monitoring(chan, p, 1); 02254 break; 02255 } 02256 } 02257 AST_LIST_UNLOCK(&agents); 02258 02259 } else { 02260 res = -1; 02261 if (!nowarnings) 02262 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); 02263 } 02264 } else { 02265 res = -1; 02266 if (!nowarnings) 02267 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"); 02268 } 02269 if (res) { 02270 if (exitifnoagentid) 02271 return res; 02272 } 02273 return 0; 02274 }
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 1731 of file chan_agent.c.
References agent_pvt::acknowledged, agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.
01732 { 01733 struct agent_pvt *p; 01734 char username[AST_MAX_BUF]; 01735 char location[AST_MAX_BUF] = ""; 01736 char talkingto[AST_MAX_BUF] = ""; 01737 char music[AST_MAX_BUF]; 01738 int count_agents = 0; /*!< Number of agents configured */ 01739 int online_agents = 0; /*!< Number of online agents */ 01740 int offline_agents = 0; /*!< Number of offline agents */ 01741 01742 switch (cmd) { 01743 case CLI_INIT: 01744 e->command = "agent show"; 01745 e->usage = 01746 "Usage: agent show\n" 01747 " Provides summary information on agents.\n"; 01748 return NULL; 01749 case CLI_GENERATE: 01750 return NULL; 01751 } 01752 01753 if (a->argc != 2) 01754 return CLI_SHOWUSAGE; 01755 01756 AST_LIST_LOCK(&agents); 01757 AST_LIST_TRAVERSE(&agents, p, list) { 01758 ast_mutex_lock(&p->lock); 01759 if (p->pending) { 01760 if (p->group) 01761 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01762 else 01763 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01764 } else { 01765 if (!ast_strlen_zero(p->name)) 01766 snprintf(username, sizeof(username), "(%s) ", p->name); 01767 else 01768 username[0] = '\0'; 01769 if (p->chan) { 01770 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01771 if (p->owner && ast_bridged_channel(p->owner)) 01772 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01773 else 01774 strcpy(talkingto, " is idle"); 01775 online_agents++; 01776 } else if (!ast_strlen_zero(p->loginchan)) { 01777 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01778 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01779 else 01780 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01781 talkingto[0] = '\0'; 01782 online_agents++; 01783 if (p->acknowledged) 01784 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01785 } else { 01786 strcpy(location, "not logged in"); 01787 talkingto[0] = '\0'; 01788 offline_agents++; 01789 } 01790 if (!ast_strlen_zero(p->moh)) 01791 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01792 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01793 username, location, talkingto, music); 01794 count_agents++; 01795 } 01796 ast_mutex_unlock(&p->lock); 01797 } 01798 AST_LIST_UNLOCK(&agents); 01799 if ( !count_agents ) 01800 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01801 else 01802 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01803 ast_cli(a->fd, "\n"); 01804 01805 return CLI_SUCCESS; 01806 }
static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1809 of file chan_agent.c.
References agent_pvt::acknowledged, agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.
01810 { 01811 struct agent_pvt *p; 01812 char username[AST_MAX_BUF]; 01813 char location[AST_MAX_BUF] = ""; 01814 char talkingto[AST_MAX_BUF] = ""; 01815 char music[AST_MAX_BUF]; 01816 int count_agents = 0; /* Number of agents configured */ 01817 int online_agents = 0; /* Number of online agents */ 01818 int agent_status = 0; /* 0 means offline, 1 means online */ 01819 01820 switch (cmd) { 01821 case CLI_INIT: 01822 e->command = "agent show online"; 01823 e->usage = 01824 "Usage: agent show online\n" 01825 " Provides a list of all online agents.\n"; 01826 return NULL; 01827 case CLI_GENERATE: 01828 return NULL; 01829 } 01830 01831 if (a->argc != 3) 01832 return CLI_SHOWUSAGE; 01833 01834 AST_LIST_LOCK(&agents); 01835 AST_LIST_TRAVERSE(&agents, p, list) { 01836 agent_status = 0; /* reset it to offline */ 01837 ast_mutex_lock(&p->lock); 01838 if (!ast_strlen_zero(p->name)) 01839 snprintf(username, sizeof(username), "(%s) ", p->name); 01840 else 01841 username[0] = '\0'; 01842 if (p->chan) { 01843 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01844 if (p->owner && ast_bridged_channel(p->owner)) 01845 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01846 else 01847 strcpy(talkingto, " is idle"); 01848 agent_status = 1; 01849 online_agents++; 01850 } else if (!ast_strlen_zero(p->loginchan)) { 01851 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01852 talkingto[0] = '\0'; 01853 agent_status = 1; 01854 online_agents++; 01855 if (p->acknowledged) 01856 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01857 } 01858 if (!ast_strlen_zero(p->moh)) 01859 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01860 if (agent_status) 01861 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01862 count_agents++; 01863 ast_mutex_unlock(&p->lock); 01864 } 01865 AST_LIST_UNLOCK(&agents); 01866 if (!count_agents) 01867 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01868 else 01869 ast_cli(a->fd, "%d agents online\n", online_agents); 01870 ast_cli(a->fd, "\n"); 01871 return CLI_SUCCESS; 01872 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1264 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), ast_copy_string(), ast_debug, AST_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, ast_channel::language, agent_pvt::list, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01265 { 01266 struct ast_channel *chan=NULL, *parent=NULL; 01267 struct agent_pvt *p; 01268 int res; 01269 01270 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01271 if (needlock) 01272 AST_LIST_LOCK(&agents); 01273 AST_LIST_TRAVERSE(&agents, p, list) { 01274 if (p == newlyavailable) { 01275 continue; 01276 } 01277 ast_mutex_lock(&p->lock); 01278 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01279 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01280 /* We found a pending call, time to merge */ 01281 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01282 parent = p->owner; 01283 p->abouttograb = 1; 01284 ast_mutex_unlock(&p->lock); 01285 break; 01286 } 01287 ast_mutex_unlock(&p->lock); 01288 } 01289 if (needlock) 01290 AST_LIST_UNLOCK(&agents); 01291 if (parent && chan) { 01292 if (newlyavailable->ackcall > 1) { 01293 /* Don't do beep here */ 01294 res = 0; 01295 } else { 01296 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01297 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01298 ast_debug(3, "Played beep, result '%d'\n", res); 01299 if (!res) { 01300 res = ast_waitstream(newlyavailable->chan, ""); 01301 ast_debug(1, "Waited for stream, result '%d'\n", res); 01302 } 01303 } 01304 if (!res) { 01305 /* Note -- parent may have disappeared */ 01306 if (p->abouttograb) { 01307 newlyavailable->acknowledged = 1; 01308 /* Safe -- agent lock already held */ 01309 ast_setstate(parent, AST_STATE_UP); 01310 ast_setstate(chan, AST_STATE_UP); 01311 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01312 /* Go ahead and mark the channel as a zombie so that masquerade will 01313 destroy it for us, and we need not call ast_hangup */ 01314 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01315 ast_channel_masquerade(parent, chan); 01316 p->abouttograb = 0; 01317 } else { 01318 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01319 agent_cleanup(newlyavailable); 01320 } 01321 } else { 01322 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01323 agent_cleanup(newlyavailable); 01324 } 01325 } 01326 return 0; 01327 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1329 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().
01330 { 01331 struct agent_pvt *p; 01332 int res=0; 01333 01334 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01335 if (needlock) 01336 AST_LIST_LOCK(&agents); 01337 AST_LIST_TRAVERSE(&agents, p, list) { 01338 if (p == newlyavailable) { 01339 continue; 01340 } 01341 ast_mutex_lock(&p->lock); 01342 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01343 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01344 ast_mutex_unlock(&p->lock); 01345 break; 01346 } 01347 ast_mutex_unlock(&p->lock); 01348 } 01349 if (needlock) 01350 AST_LIST_UNLOCK(&agents); 01351 if (p) { 01352 ast_mutex_unlock(&newlyavailable->lock); 01353 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01354 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01355 ast_debug(1, "Played beep, result '%d'\n", res); 01356 if (!res) { 01357 res = ast_waitstream(newlyavailable->chan, ""); 01358 ast_debug(1, "Waited for stream, result '%d'\n", res); 01359 } 01360 ast_mutex_lock(&newlyavailable->lock); 01361 } 01362 return res; 01363 }
static char * complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1704 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_AGENT, ast_strdup, len(), agent_pvt::list, agent_pvt::loginstart, and agent_pvt::name.
Referenced by agent_logoff_cmd().
01705 { 01706 char *ret = NULL; 01707 01708 if (pos == 2) { 01709 struct agent_pvt *p; 01710 char name[AST_MAX_AGENT]; 01711 int which = 0, len = strlen(word); 01712 01713 AST_LIST_LOCK(&agents); 01714 AST_LIST_TRAVERSE(&agents, p, list) { 01715 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01716 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01717 ret = ast_strdup(name); 01718 break; 01719 } 01720 } 01721 AST_LIST_UNLOCK(&agents); 01722 } else if (pos == 3 && state == 0) 01723 return ast_strdup("soft"); 01724 01725 return ret; 01726 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2279 of file chan_agent.c.
References agent_pvt::agent, ast_db_del(), ast_db_put(), ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), buf, agent_pvt::chan, agent_pvt::list, LOG_WARNING, agent_pvt::logincallerid, and agent_pvt::loginchan.
Referenced by agent_hangup(), and agent_logoff_maintenance().
02280 { 02281 struct agent_pvt *cur_agent = NULL; 02282 char buf[256]; 02283 02284 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02285 if (cur_agent->chan) 02286 continue; 02287 02288 if (!ast_strlen_zero(cur_agent->loginchan)) { 02289 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02290 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02291 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02292 else 02293 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02294 } else { 02295 /* Delete - no agent or there is an error */ 02296 ast_db_del(pa_family, cur_agent->agent); 02297 } 02298 } 02299 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2402 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_TRAVERSE, and agent_pvt::list.
Referenced by function_agent().
02403 { 02404 struct agent_pvt *cur; 02405 02406 AST_LIST_TRAVERSE(&agents, cur, list) { 02407 if (!strcmp(cur->agent, agentid)) 02408 break; 02409 } 02410 02411 return cur; 02412 }
static int function_agent | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2414 of file chan_agent.c.
References agent_pvt::agent, AST_APP_ARG, 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.
02415 { 02416 char *parse; 02417 AST_DECLARE_APP_ARGS(args, 02418 AST_APP_ARG(agentid); 02419 AST_APP_ARG(item); 02420 ); 02421 char *tmp; 02422 struct agent_pvt *agent; 02423 02424 buf[0] = '\0'; 02425 02426 if (ast_strlen_zero(data)) { 02427 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02428 return -1; 02429 } 02430 02431 parse = ast_strdupa(data); 02432 02433 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02434 if (!args.item) 02435 args.item = "status"; 02436 02437 AST_LIST_LOCK(&agents); 02438 02439 if (!(agent = find_agent(args.agentid))) { 02440 AST_LIST_UNLOCK(&agents); 02441 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02442 return -1; 02443 } 02444 02445 if (!strcasecmp(args.item, "status")) { 02446 char *status = "LOGGEDOUT"; 02447 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02448 status = "LOGGEDIN"; 02449 ast_copy_string(buf, status, len); 02450 } else if (!strcasecmp(args.item, "password")) 02451 ast_copy_string(buf, agent->password, len); 02452 else if (!strcasecmp(args.item, "name")) 02453 ast_copy_string(buf, agent->name, len); 02454 else if (!strcasecmp(args.item, "mohclass")) 02455 ast_copy_string(buf, agent->moh, len); 02456 else if (!strcasecmp(args.item, "channel")) { 02457 if (agent->chan) { 02458 ast_copy_string(buf, agent->chan->name, len); 02459 tmp = strrchr(buf, '-'); 02460 if (tmp) 02461 *tmp = '\0'; 02462 } 02463 } else if (!strcasecmp(args.item, "exten")) 02464 ast_copy_string(buf, agent->loginchan, len); 02465 02466 AST_LIST_UNLOCK(&agents); 02467 02468 return 0; 02469 }
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 2494 of file chan_agent.c.
References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().
02495 { 02496 /* Make sure we can register our agent channel type */ 02497 if (ast_channel_register(&agent_tech)) { 02498 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02499 return AST_MODULE_LOAD_FAILURE; 02500 } 02501 /* Read in the config */ 02502 if (!read_agent_config(0)) 02503 return AST_MODULE_LOAD_DECLINE; 02504 if (persistent_agents) 02505 reload_agents(); 02506 /* Dialplan applications */ 02507 ast_register_application(app, login_exec, synopsis, descrip); 02508 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02509 02510 /* Manager commands */ 02511 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02512 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02513 02514 /* CLI Commands */ 02515 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02516 02517 /* Dialplan Functions */ 02518 ast_custom_function_register(&agent_function); 02519 02520 return AST_MODULE_LOAD_SUCCESS; 02521 }
static int login_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Log in agent application.
Called by the AgentLogin application (from the dial plan).
chan | ||
data |
Definition at line 1895 of file chan_agent.c.
References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_wait(), AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, agent_pvt::chan, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, 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().
01896 { 01897 int res=0; 01898 int tries = 0; 01899 int max_login_tries = maxlogintries; 01900 struct agent_pvt *p; 01901 struct ast_module_user *u; 01902 int login_state = 0; 01903 char user[AST_MAX_AGENT] = ""; 01904 char pass[AST_MAX_AGENT]; 01905 char agent[AST_MAX_AGENT] = ""; 01906 char xpass[AST_MAX_AGENT] = ""; 01907 char *errmsg; 01908 char *parse; 01909 AST_DECLARE_APP_ARGS(args, 01910 AST_APP_ARG(agent_id); 01911 AST_APP_ARG(options); 01912 AST_APP_ARG(extension); 01913 ); 01914 const char *tmpoptions = NULL; 01915 int play_announcement = 1; 01916 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01917 int update_cdr = updatecdr; 01918 char *filename = "agent-loginok"; 01919 01920 u = ast_module_user_add(chan); 01921 01922 parse = ast_strdupa(data); 01923 01924 AST_STANDARD_APP_ARGS(args, parse); 01925 01926 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01927 01928 ast_channel_lock(chan); 01929 /* Set Channel Specific Login Overrides */ 01930 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01931 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01932 if (max_login_tries < 0) 01933 max_login_tries = 0; 01934 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01935 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 01936 } 01937 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01938 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01939 update_cdr = 1; 01940 else 01941 update_cdr = 0; 01942 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01943 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01944 } 01945 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01946 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01947 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01948 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01949 } 01950 ast_channel_unlock(chan); 01951 /* End Channel Specific Login Overrides */ 01952 01953 if (!ast_strlen_zero(args.options)) { 01954 if (strchr(args.options, 's')) { 01955 play_announcement = 0; 01956 } 01957 } 01958 01959 if (chan->_state != AST_STATE_UP) 01960 res = ast_answer(chan); 01961 if (!res) { 01962 if (!ast_strlen_zero(args.agent_id)) 01963 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01964 else 01965 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01966 } 01967 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01968 tries++; 01969 /* Check for password */ 01970 AST_LIST_LOCK(&agents); 01971 AST_LIST_TRAVERSE(&agents, p, list) { 01972 if (!strcmp(p->agent, user) && !p->pending) 01973 ast_copy_string(xpass, p->password, sizeof(xpass)); 01974 } 01975 AST_LIST_UNLOCK(&agents); 01976 if (!res) { 01977 if (!ast_strlen_zero(xpass)) 01978 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01979 else 01980 pass[0] = '\0'; 01981 } 01982 errmsg = "agent-incorrect"; 01983 01984 #if 0 01985 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01986 #endif 01987 01988 /* Check again for accuracy */ 01989 AST_LIST_LOCK(&agents); 01990 AST_LIST_TRAVERSE(&agents, p, list) { 01991 int unlock_channel = 1; 01992 ast_channel_lock(chan); 01993 ast_mutex_lock(&p->lock); 01994 if (!strcmp(p->agent, user) && 01995 !strcmp(p->password, pass) && !p->pending) { 01996 login_state = 1; /* Successful Login */ 01997 01998 /* Ensure we can't be gotten until we're done */ 01999 p->lastdisc = ast_tvnow(); 02000 p->lastdisc.tv_sec++; 02001 02002 /* Set Channel Specific Agent Overrides */ 02003 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02004 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 02005 p->ackcall = 2; 02006 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 02007 p->ackcall = 1; 02008 else 02009 p->ackcall = 0; 02010 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02011 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 02012 ast_set_flag(p, AGENT_FLAG_ACKCALL); 02013 } else { 02014 p->ackcall = ackcall; 02015 } 02016 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02017 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02018 if (p->autologoff < 0) 02019 p->autologoff = 0; 02020 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02021 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 02022 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 02023 } else { 02024 p->autologoff = autologoff; 02025 } 02026 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02027 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02028 if (p->wrapuptime < 0) 02029 p->wrapuptime = 0; 02030 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02031 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 02032 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 02033 } else { 02034 p->wrapuptime = wrapuptime; 02035 } 02036 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF"); 02037 if (ast_strlen_zero(tmpoptions)) { 02038 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDMTF"); 02039 } 02040 if (!ast_strlen_zero(tmpoptions)) { 02041 p->acceptdtmf = *tmpoptions; 02042 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 02043 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 02044 } 02045 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 02046 if (!ast_strlen_zero(tmpoptions)) { 02047 p->enddtmf = *tmpoptions; 02048 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 02049 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 02050 } 02051 ast_channel_unlock(chan); 02052 unlock_channel = 0; 02053 /* End Channel Specific Agent Overrides */ 02054 if (!p->chan) { 02055 long logintime; 02056 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02057 02058 p->loginchan[0] = '\0'; 02059 p->logincallerid[0] = '\0'; 02060 p->acknowledged = 0; 02061 02062 ast_mutex_unlock(&p->lock); 02063 AST_LIST_UNLOCK(&agents); 02064 if( !res && play_announcement==1 ) 02065 res = ast_streamfile(chan, filename, chan->language); 02066 if (!res) 02067 ast_waitstream(chan, ""); 02068 AST_LIST_LOCK(&agents); 02069 ast_mutex_lock(&p->lock); 02070 if (!res) { 02071 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02072 if (res) 02073 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02074 } 02075 if (!res) { 02076 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02077 if (res) 02078 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02079 } 02080 /* Check once more just in case */ 02081 if (p->chan) 02082 res = -1; 02083 if (!res) { 02084 ast_indicate_data(chan, AST_CONTROL_HOLD, 02085 S_OR(p->moh, NULL), 02086 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02087 if (p->loginstart == 0) 02088 time(&p->loginstart); 02089 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02090 "Agent: %s\r\n" 02091 "Channel: %s\r\n" 02092 "Uniqueid: %s\r\n", 02093 p->agent, chan->name, chan->uniqueid); 02094 if (update_cdr && chan->cdr) 02095 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02096 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02097 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 02098 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02099 /* Login this channel and wait for it to go away */ 02100 p->chan = chan; 02101 if (p->ackcall > 1) 02102 check_beep(p, 0); 02103 else 02104 check_availability(p, 0); 02105 ast_mutex_unlock(&p->lock); 02106 AST_LIST_UNLOCK(&agents); 02107 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02108 while (res >= 0) { 02109 ast_mutex_lock(&p->lock); 02110 if (p->deferlogoff && p->chan) { 02111 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02112 p->deferlogoff = 0; 02113 } 02114 if (p->chan != chan) 02115 res = -1; 02116 ast_mutex_unlock(&p->lock); 02117 /* Yield here so other interested threads can kick in. */ 02118 sched_yield(); 02119 if (res) 02120 break; 02121 02122 AST_LIST_LOCK(&agents); 02123 ast_mutex_lock(&p->lock); 02124 if (p->lastdisc.tv_sec) { 02125 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02126 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02127 p->lastdisc = ast_tv(0, 0); 02128 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02129 if (p->ackcall > 1) 02130 check_beep(p, 0); 02131 else 02132 check_availability(p, 0); 02133 } 02134 } 02135 ast_mutex_unlock(&p->lock); 02136 AST_LIST_UNLOCK(&agents); 02137 /* Synchronize channel ownership between call to agent and itself. */ 02138 ast_mutex_lock(&p->app_lock); 02139 if (p->app_lock_flag == 1) { 02140 ast_cond_wait(&p->app_complete_cond, &p->app_lock); 02141 } 02142 ast_mutex_unlock(&p->app_lock); 02143 ast_mutex_lock(&p->lock); 02144 ast_mutex_unlock(&p->lock); 02145 if (p->ackcall > 1) 02146 res = agent_ack_sleep(p); 02147 else 02148 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02149 if ((p->ackcall > 1) && (res == 1)) { 02150 AST_LIST_LOCK(&agents); 02151 ast_mutex_lock(&p->lock); 02152 check_availability(p, 0); 02153 ast_mutex_unlock(&p->lock); 02154 AST_LIST_UNLOCK(&agents); 02155 res = 0; 02156 } 02157 sched_yield(); 02158 } 02159 ast_mutex_lock(&p->lock); 02160 if (res && p->owner) 02161 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02162 /* Log us off if appropriate */ 02163 if (p->chan == chan) { 02164 p->chan = NULL; 02165 } 02166 p->acknowledged = 0; 02167 logintime = time(NULL) - p->loginstart; 02168 p->loginstart = 0; 02169 ast_mutex_unlock(&p->lock); 02170 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02171 "Agent: %s\r\n" 02172 "Logintime: %ld\r\n" 02173 "Uniqueid: %s\r\n", 02174 p->agent, logintime, chan->uniqueid); 02175 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02176 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02177 /* If there is no owner, go ahead and kill it now */ 02178 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02179 if (p->dead && !p->owner) { 02180 ast_mutex_destroy(&p->lock); 02181 ast_mutex_destroy(&p->app_lock); 02182 ast_cond_destroy(&p->app_complete_cond); 02183 ast_free(p); 02184 } 02185 } 02186 else { 02187 ast_mutex_unlock(&p->lock); 02188 p = NULL; 02189 } 02190 res = -1; 02191 } else { 02192 ast_mutex_unlock(&p->lock); 02193 errmsg = "agent-alreadyon"; 02194 p = NULL; 02195 } 02196 break; 02197 } 02198 ast_mutex_unlock(&p->lock); 02199 if (unlock_channel) { 02200 ast_channel_unlock(chan); 02201 } 02202 } 02203 if (!p) 02204 AST_LIST_UNLOCK(&agents); 02205 02206 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02207 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02208 } 02209 02210 if (!res) 02211 res = ast_safe_sleep(chan, 500); 02212 02213 ast_module_user_remove(u); 02214 02215 return -1; 02216 }
static force_inline int powerof | ( | unsigned int | d | ) | [static] |
static int read_agent_config | ( | int | reload | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1107 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, agent_pvt::app_lock, ast_category_browse(), ast_cond_destroy(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_get_group(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), agent_pvt::chan, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEUNCHANGED, agent_pvt::dead, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01108 { 01109 struct ast_config *cfg; 01110 struct ast_config *ucfg; 01111 struct ast_variable *v; 01112 struct agent_pvt *p; 01113 const char *general_val; 01114 const char *catname; 01115 const char *hasagent; 01116 int genhasagent; 01117 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01118 01119 group = 0; 01120 autologoff = 0; 01121 wrapuptime = 0; 01122 ackcall = 0; 01123 endcall = 1; 01124 cfg = ast_config_load(config, config_flags); 01125 if (!cfg) { 01126 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01127 return 0; 01128 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 01129 return -1; 01130 AST_LIST_LOCK(&agents); 01131 AST_LIST_TRAVERSE(&agents, p, list) { 01132 p->dead = 1; 01133 } 01134 strcpy(moh, "default"); 01135 /* set the default recording values */ 01136 recordagentcalls = 0; 01137 strcpy(recordformat, "wav"); 01138 strcpy(recordformatext, "wav"); 01139 urlprefix[0] = '\0'; 01140 savecallsin[0] = '\0'; 01141 01142 /* Read in [general] section for persistence */ 01143 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01144 persistent_agents = ast_true(general_val); 01145 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01146 01147 /* Read in the [agents] section */ 01148 v = ast_variable_browse(cfg, "agents"); 01149 while(v) { 01150 /* Create the interface list */ 01151 if (!strcasecmp(v->name, "agent")) { 01152 add_agent(v->value, 0); 01153 } else if (!strcasecmp(v->name, "group")) { 01154 group = ast_get_group(v->value); 01155 } else if (!strcasecmp(v->name, "autologoff")) { 01156 autologoff = atoi(v->value); 01157 if (autologoff < 0) 01158 autologoff = 0; 01159 } else if (!strcasecmp(v->name, "ackcall")) { 01160 if (!strcasecmp(v->value, "always")) 01161 ackcall = 2; 01162 else if (ast_true(v->value)) 01163 ackcall = 1; 01164 else 01165 ackcall = 0; 01166 } else if (!strcasecmp(v->name, "endcall")) { 01167 endcall = ast_true(v->value); 01168 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01169 acceptdtmf = *(v->value); 01170 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01171 } else if (!strcasecmp(v->name, "enddtmf")) { 01172 enddtmf = *(v->value); 01173 } else if (!strcasecmp(v->name, "wrapuptime")) { 01174 wrapuptime = atoi(v->value); 01175 if (wrapuptime < 0) 01176 wrapuptime = 0; 01177 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01178 maxlogintries = atoi(v->value); 01179 if (maxlogintries < 0) 01180 maxlogintries = 0; 01181 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01182 strcpy(agentgoodbye,v->value); 01183 } else if (!strcasecmp(v->name, "musiconhold")) { 01184 ast_copy_string(moh, v->value, sizeof(moh)); 01185 } else if (!strcasecmp(v->name, "updatecdr")) { 01186 if (ast_true(v->value)) 01187 updatecdr = 1; 01188 else 01189 updatecdr = 0; 01190 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01191 if (ast_true(v->value)) 01192 autologoffunavail = 1; 01193 else 01194 autologoffunavail = 0; 01195 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01196 recordagentcalls = ast_true(v->value); 01197 } else if (!strcasecmp(v->name, "recordformat")) { 01198 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01199 if (!strcasecmp(v->value, "wav49")) 01200 strcpy(recordformatext, "WAV"); 01201 else 01202 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01203 } else if (!strcasecmp(v->name, "urlprefix")) { 01204 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01205 if (urlprefix[strlen(urlprefix) - 1] != '/') 01206 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01207 } else if (!strcasecmp(v->name, "savecallsin")) { 01208 if (v->value[0] == '/') 01209 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01210 else 01211 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01212 if (savecallsin[strlen(savecallsin) - 1] != '/') 01213 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01214 } else if (!strcasecmp(v->name, "custom_beep")) { 01215 ast_copy_string(beep, v->value, sizeof(beep)); 01216 } 01217 v = v->next; 01218 } 01219 if ((ucfg = ast_config_load("users.conf", config_flags)) && ucfg != CONFIG_STATUS_FILEUNCHANGED) { 01220 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01221 catname = ast_category_browse(ucfg, NULL); 01222 while(catname) { 01223 if (strcasecmp(catname, "general")) { 01224 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01225 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01226 char tmp[256]; 01227 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01228 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01229 if (!fullname) 01230 fullname = ""; 01231 if (!secret) 01232 secret = ""; 01233 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01234 add_agent(tmp, 0); 01235 } 01236 } 01237 catname = ast_category_browse(ucfg, catname); 01238 } 01239 ast_config_destroy(ucfg); 01240 } 01241 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01242 if (p->dead) { 01243 AST_LIST_REMOVE_CURRENT(list); 01244 /* Destroy if appropriate */ 01245 if (!p->owner) { 01246 if (!p->chan) { 01247 ast_mutex_destroy(&p->lock); 01248 ast_mutex_destroy(&p->app_lock); 01249 ast_cond_destroy(&p->app_complete_cond); 01250 ast_free(p); 01251 } else { 01252 /* Cause them to hang up */ 01253 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01254 } 01255 } 01256 } 01257 } 01258 AST_LIST_TRAVERSE_SAFE_END; 01259 AST_LIST_UNLOCK(&agents); 01260 ast_config_destroy(cfg); 01261 return 1; 01262 }
static int reload | ( | void | ) | [static] |
Definition at line 2523 of file chan_agent.c.
References read_agent_config(), and reload_agents().
02524 { 02525 if (!read_agent_config(1)) { 02526 if (persistent_agents) 02527 reload_agents(); 02528 } 02529 return 0; 02530 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2304 of file chan_agent.c.
References agent_pvt::agent, ast_copy_string(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, AST_DEVICE_UNKNOWN, ast_devstate_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, ast_db_entry::next, parse(), set_agentbycallerid(), and strsep().
Referenced by load_module(), and reload().
02305 { 02306 char *agent_num; 02307 struct ast_db_entry *db_tree; 02308 struct ast_db_entry *entry; 02309 struct agent_pvt *cur_agent; 02310 char agent_data[256]; 02311 char *parse; 02312 char *agent_chan; 02313 char *agent_callerid; 02314 02315 db_tree = ast_db_gettree(pa_family, NULL); 02316 02317 AST_LIST_LOCK(&agents); 02318 for (entry = db_tree; entry; entry = entry->next) { 02319 agent_num = entry->key + strlen(pa_family) + 2; 02320 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02321 ast_mutex_lock(&cur_agent->lock); 02322 if (strcmp(agent_num, cur_agent->agent) == 0) 02323 break; 02324 ast_mutex_unlock(&cur_agent->lock); 02325 } 02326 if (!cur_agent) { 02327 ast_db_del(pa_family, agent_num); 02328 continue; 02329 } else 02330 ast_mutex_unlock(&cur_agent->lock); 02331 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02332 ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02333 parse = agent_data; 02334 agent_chan = strsep(&parse, ";"); 02335 agent_callerid = strsep(&parse, ";"); 02336 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02337 if (agent_callerid) { 02338 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02339 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02340 } else 02341 cur_agent->logincallerid[0] = '\0'; 02342 if (cur_agent->loginstart == 0) 02343 time(&cur_agent->loginstart); 02344 ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 02345 } 02346 } 02347 AST_LIST_UNLOCK(&agents); 02348 if (db_tree) { 02349 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02350 ast_db_freetree(db_tree); 02351 } 02352 }
static void set_agentbycallerid | ( | const char * | callerid, | |
const char * | agent | |||
) | [static] |
store/clear the global variable that stores agentid based on the callerid
Definition at line 774 of file chan_agent.c.
References AST_MAX_BUF, ast_strlen_zero(), buf, GETAGENTBYCALLERID, and pbx_builtin_setvar_helper().
Referenced by agent_logoff_maintenance(), and reload_agents().
00775 { 00776 char buf[AST_MAX_BUF]; 00777 00778 /* if there is no Caller ID, nothing to do */ 00779 if (ast_strlen_zero(callerid)) 00780 return; 00781 00782 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00783 pbx_builtin_setvar_helper(NULL, buf, agent); 00784 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2532 of file chan_agent.c.
References agent_function, agent_tech, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_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.
Referenced by config_module(), and load_module().
02533 { 02534 struct agent_pvt *p; 02535 /* First, take us out of the channel loop */ 02536 ast_channel_unregister(&agent_tech); 02537 /* Unregister dialplan functions */ 02538 ast_custom_function_unregister(&agent_function); 02539 /* Unregister CLI commands */ 02540 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02541 /* Unregister dialplan applications */ 02542 ast_unregister_application(app); 02543 ast_unregister_application(app3); 02544 /* Unregister manager command */ 02545 ast_manager_unregister("Agents"); 02546 ast_manager_unregister("AgentLogoff"); 02547 /* Unregister channel */ 02548 AST_LIST_LOCK(&agents); 02549 /* Hangup all interfaces if they have an owner */ 02550 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02551 if (p->owner) 02552 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02553 ast_free(p); 02554 } 02555 AST_LIST_UNLOCK(&agents); 02556 return 0; 02557 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 2563 of file chan_agent.c.
char acceptdtmf = DEFAULT_ACCEPTDTMF [static] |
int ackcall [static] |
Definition at line 134 of file chan_agent.c.
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 1874 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 252 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 142 of file chan_agent.c.
const char app[] = "AgentLogin" [static] |
Definition at line 75 of file chan_agent.c.
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 76 of file chan_agent.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2563 of file chan_agent.c.
int autologoff [static] |
Definition at line 132 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 137 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 150 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 1879 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char config[] = "agents.conf" [static] |
Definition at line 73 of file chan_agent.c.
Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_insert(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_retrieve(), builtin_atxfer(), category_get(), dial_exec_full(), do_reload(), do_timelimit(), execute_cb(), feature_interpret_helper(), load_config(), load_module(), load_odbc_config(), misdn_cfg_init(), odbc_load_module(), park_exec_full(), parse_config(), pbx_load_module(), read_config_maps(), reload_config(), set_bridge_features_on_config(), and set_config_flags().
const char descrip[] [static] |
Definition at line 81 of file chan_agent.c.
const char descrip3[] [static] |
Definition at line 90 of file chan_agent.c.
int endcall [static] |
Definition at line 135 of file chan_agent.c.
char enddtmf = DEFAULT_ENDDTMF [static] |
Definition at line 139 of file chan_agent.c.
ast_group_t group [static] |
const char mandescr_agent_logoff[] [static] |
Initial value:
"Description: Sets an agent as no longer logged in.\n" "Variables: (Names marked with * are required)\n" " *Agent: Agent ID of the agent to log off\n" " Soft: Set to 'true' to not hangup existing calls\n"
Definition at line 110 of file chan_agent.c.
const char mandescr_agents[] [static] |
Initial value:
"Description: Will list info about all possible agents.\n" "Variables: NONE\n"
Definition at line 106 of file chan_agent.c.
int maxlogintries = 3 [static] |
Definition at line 141 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 116 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 136 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 122 of file chan_agent.c.
int persistent_agents = 0 [static] |
queues.conf [general] option
Definition at line 125 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 144 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 145 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 146 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 148 of file chan_agent.c.
const char synopsis[] = "Call agent login" [static] |
Definition at line 78 of file chan_agent.c.
Definition at line 79 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 72 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 149 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
int wrapuptime [static] |
Definition at line 133 of file chan_agent.c.