#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 2539 of file chan_agent.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2539 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 1661 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().
01662 { 01663 const char *agent = astman_get_header(m, "Agent"); 01664 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01665 int soft; 01666 int ret; /* return value of agent_logoff */ 01667 01668 if (ast_strlen_zero(agent)) { 01669 astman_send_error(s, m, "No agent specified"); 01670 return 0; 01671 } 01672 01673 soft = ast_true(soft_s) ? 1 : 0; 01674 ret = agent_logoff(agent, soft); 01675 if (ret == 0) 01676 astman_send_ack(s, m, "Agent logged out"); 01677 else 01678 astman_send_error(s, m, "No such agent"); 01679 01680 return 0; 01681 }
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 1458 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().
01459 { 01460 const char *id = astman_get_header(m,"ActionID"); 01461 char idText[256] = ""; 01462 char chanbuf[256]; 01463 struct agent_pvt *p; 01464 char *username = NULL; 01465 char *loginChan = NULL; 01466 char *talkingto = NULL; 01467 char *talkingtoChan = NULL; 01468 char *status = NULL; 01469 01470 if (!ast_strlen_zero(id)) 01471 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01472 astman_send_ack(s, m, "Agents will follow"); 01473 AST_LIST_LOCK(&agents); 01474 AST_LIST_TRAVERSE(&agents, p, list) { 01475 ast_mutex_lock(&p->lock); 01476 01477 /* Status Values: 01478 AGENT_LOGGEDOFF - Agent isn't logged in 01479 AGENT_IDLE - Agent is logged in, and waiting for call 01480 AGENT_ONCALL - Agent is logged in, and on a call 01481 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01482 01483 username = S_OR(p->name, "None"); 01484 01485 /* Set a default status. It 'should' get changed. */ 01486 status = "AGENT_UNKNOWN"; 01487 01488 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01489 loginChan = p->loginchan; 01490 talkingto = "n/a"; 01491 talkingtoChan = "n/a"; 01492 status = "AGENT_IDLE"; 01493 if (p->acknowledged) { 01494 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01495 loginChan = chanbuf; 01496 } 01497 } else if (p->chan) { 01498 loginChan = ast_strdupa(p->chan->name); 01499 if (p->owner && p->owner->_bridge) { 01500 talkingto = p->chan->cid.cid_num; 01501 if (ast_bridged_channel(p->owner)) 01502 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name); 01503 else 01504 talkingtoChan = "n/a"; 01505 status = "AGENT_ONCALL"; 01506 } else { 01507 talkingto = "n/a"; 01508 talkingtoChan = "n/a"; 01509 status = "AGENT_IDLE"; 01510 } 01511 } else { 01512 loginChan = "n/a"; 01513 talkingto = "n/a"; 01514 talkingtoChan = "n/a"; 01515 status = "AGENT_LOGGEDOFF"; 01516 } 01517 01518 astman_append(s, "Event: Agents\r\n" 01519 "Agent: %s\r\n" 01520 "Name: %s\r\n" 01521 "Status: %s\r\n" 01522 "LoggedInChan: %s\r\n" 01523 "LoggedInTime: %d\r\n" 01524 "TalkingTo: %s\r\n" 01525 "TalkingToChan: %s\r\n" 01526 "%s" 01527 "\r\n", 01528 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01529 ast_mutex_unlock(&p->lock); 01530 } 01531 AST_LIST_UNLOCK(&agents); 01532 astman_append(s, "Event: AgentsComplete\r\n" 01533 "%s" 01534 "\r\n",idText); 01535 return 0; 01536 }
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 934 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().
00935 { 00936 struct agent_pvt *p; 00937 int res=0; 00938 int to = 1000; 00939 struct ast_frame *f; 00940 00941 /* Wait a second and look for something */ 00942 00943 p = (struct agent_pvt *) data; 00944 if (!p->chan) 00945 return -1; 00946 00947 for(;;) { 00948 to = ast_waitfor(p->chan, to); 00949 if (to < 0) 00950 return -1; 00951 if (!to) 00952 return 0; 00953 f = ast_read(p->chan); 00954 if (!f) 00955 return -1; 00956 if (f->frametype == AST_FRAME_DTMF) 00957 res = f->subclass; 00958 else 00959 res = 0; 00960 ast_frfree(f); 00961 ast_mutex_lock(&p->lock); 00962 if (!p->app_sleep_cond) { 00963 ast_mutex_unlock(&p->lock); 00964 return 0; 00965 } else if (res == p->acceptdtmf) { 00966 ast_mutex_unlock(&p->lock); 00967 return 1; 00968 } 00969 ast_mutex_unlock(&p->lock); 00970 res = 0; 00971 } 00972 return res; 00973 }
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 975 of file chan_agent.c.
References ast_channel::_bridge, ast_debug, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.
00976 { 00977 struct agent_pvt *p = bridge->tech_pvt; 00978 struct ast_channel *ret = NULL; 00979 00980 if (p) { 00981 if (chan == p->chan) 00982 ret = bridge->_bridge; 00983 else if (chan == bridge->_bridge) 00984 ret = p->chan; 00985 } 00986 00987 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 00988 return ret; 00989 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 676 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.
00677 { 00678 struct agent_pvt *p = ast->tech_pvt; 00679 int res = -1; 00680 int newstate=0; 00681 ast_mutex_lock(&p->lock); 00682 p->acknowledged = 0; 00683 if (!p->chan) { 00684 if (p->pending) { 00685 ast_debug(1, "Pretending to dial on pending agent\n"); 00686 newstate = AST_STATE_DIALING; 00687 res = 0; 00688 } else { 00689 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00690 res = -1; 00691 } 00692 ast_mutex_unlock(&p->lock); 00693 if (newstate) 00694 ast_setstate(ast, newstate); 00695 return res; 00696 } else if (!ast_strlen_zero(p->loginchan)) { 00697 time(&p->start); 00698 /* Call on this agent */ 00699 ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00700 ast_set_callerid(p->chan, 00701 ast->cid.cid_num, ast->cid.cid_name, NULL); 00702 ast_channel_inherit_variables(ast, p->chan); 00703 res = ast_call(p->chan, p->loginchan, 0); 00704 CLEANUP(ast,p); 00705 ast_mutex_unlock(&p->lock); 00706 return res; 00707 } 00708 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00709 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language); 00710 res = ast_streamfile(p->chan, beep, p->chan->language); 00711 ast_debug(3, "Played beep, result '%d'\n", res); 00712 if (!res) { 00713 res = ast_waitstream(p->chan, ""); 00714 ast_debug(3, "Waited for stream, result '%d'\n", res); 00715 } 00716 if (!res) { 00717 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00718 ast_debug(3, "Set read format, result '%d'\n", res); 00719 if (res) 00720 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00721 } else { 00722 /* Agent hung-up */ 00723 p->chan = NULL; 00724 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00725 } 00726 00727 if (!res) { 00728 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00729 ast_debug(3, "Set write format, result '%d'\n", res); 00730 if (res) 00731 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00732 } 00733 if(!res) { 00734 /* Call is immediately up, or might need ack */ 00735 if (p->ackcall > 1) 00736 newstate = AST_STATE_RINGING; 00737 else { 00738 newstate = AST_STATE_UP; 00739 if (recordagentcalls) 00740 agent_start_monitoring(ast, 0); 00741 p->acknowledged = 1; 00742 } 00743 res = 0; 00744 } 00745 CLEANUP(ast, p); 00746 ast_mutex_unlock(&p->lock); 00747 if (newstate) 00748 ast_setstate(ast, newstate); 00749 return res; 00750 }
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 913 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().
00914 { 00915 struct agent_pvt *p; 00916 int res; 00917 00918 p = (struct agent_pvt *)data; 00919 00920 ast_mutex_lock(&p->lock); 00921 res = p->app_sleep_cond; 00922 if (p->lastdisc.tv_sec) { 00923 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 00924 res = 1; 00925 } 00926 ast_mutex_unlock(&p->lock); 00927 00928 if (!res) 00929 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 00930 00931 return res; 00932 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2331 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.
02332 { 02333 struct agent_pvt *p; 02334 char *s; 02335 ast_group_t groupmatch; 02336 int groupoff; 02337 int res = AST_DEVICE_INVALID; 02338 02339 s = data; 02340 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) 02341 groupmatch = (1 << groupoff); 02342 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 02343 groupmatch = (1 << groupoff); 02344 } else 02345 groupmatch = 0; 02346 02347 /* Check actual logged in agents first */ 02348 AST_LIST_LOCK(&agents); 02349 AST_LIST_TRAVERSE(&agents, p, list) { 02350 ast_mutex_lock(&p->lock); 02351 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02352 if (p->owner) { 02353 if (res != AST_DEVICE_INUSE) 02354 res = AST_DEVICE_BUSY; 02355 } else { 02356 if (res == AST_DEVICE_BUSY) 02357 res = AST_DEVICE_INUSE; 02358 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02359 if (res == AST_DEVICE_INVALID) 02360 res = AST_DEVICE_UNKNOWN; 02361 } else if (res == AST_DEVICE_INVALID) 02362 res = AST_DEVICE_UNAVAILABLE; 02363 } 02364 if (!strcmp(data, p->agent)) { 02365 ast_mutex_unlock(&p->lock); 02366 break; 02367 } 02368 } 02369 ast_mutex_unlock(&p->lock); 02370 } 02371 AST_LIST_UNLOCK(&agents); 02372 return res; 02373 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 654 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.
00655 { 00656 struct agent_pvt *p = ast->tech_pvt; 00657 ast_mutex_lock(&p->lock); 00658 if (p->chan) { 00659 ast_senddigit_begin(p->chan, digit); 00660 } 00661 ast_mutex_unlock(&p->lock); 00662 return 0; 00663 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 665 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.
00666 { 00667 struct agent_pvt *p = ast->tech_pvt; 00668 ast_mutex_lock(&p->lock); 00669 if (p->chan) { 00670 ast_senddigit_end(p->chan, digit, duration); 00671 } 00672 ast_mutex_unlock(&p->lock); 00673 return 0; 00674 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 621 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.
00622 { 00623 struct agent_pvt *p = newchan->tech_pvt; 00624 ast_mutex_lock(&p->lock); 00625 if (p->owner != oldchan) { 00626 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00627 ast_mutex_unlock(&p->lock); 00628 return -1; 00629 } 00630 p->owner = newchan; 00631 ast_mutex_unlock(&p->lock); 00632 return 0; 00633 }
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 766 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00767 { 00768 struct agent_pvt *p = NULL; 00769 struct ast_channel *base = chan; 00770 00771 /* chan is locked by the calling function */ 00772 if (!chan || !chan->tech_pvt) { 00773 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); 00774 return NULL; 00775 } 00776 p = chan->tech_pvt; 00777 if (p->chan) 00778 base = p->chan; 00779 return base; 00780 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 799 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.
00800 { 00801 struct agent_pvt *p = ast->tech_pvt; 00802 int howlong = 0; 00803 const char *status; 00804 ast_mutex_lock(&p->lock); 00805 p->owner = NULL; 00806 ast->tech_pvt = NULL; 00807 p->app_sleep_cond = 1; 00808 p->acknowledged = 0; 00809 00810 /* if they really are hung up then set start to 0 so the test 00811 * later if we're called on an already downed channel 00812 * doesn't cause an agent to be logged out like when 00813 * agent_request() is followed immediately by agent_hangup() 00814 * as in apps/app_chanisavail.c:chanavail_exec() 00815 */ 00816 00817 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00818 if (p->start && (ast->_state != AST_STATE_UP)) { 00819 howlong = time(NULL) - p->start; 00820 p->start = 0; 00821 } else if (ast->_state == AST_STATE_RESERVED) 00822 howlong = 0; 00823 else 00824 p->start = 0; 00825 if (p->chan) { 00826 p->chan->_bridge = NULL; 00827 /* If they're dead, go ahead and hang up on the agent now */ 00828 if (!ast_strlen_zero(p->loginchan)) { 00829 /* Store last disconnect time */ 00830 if (p->wrapuptime) 00831 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00832 else 00833 p->lastdisc = ast_tv(0,0); 00834 if (p->chan) { 00835 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00836 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00837 long logintime = time(NULL) - p->loginstart; 00838 p->loginstart = 0; 00839 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00840 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00841 } 00842 /* Recognize the hangup and pass it along immediately */ 00843 ast_hangup(p->chan); 00844 p->chan = NULL; 00845 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00846 } 00847 ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00848 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00849 long logintime = time(NULL) - p->loginstart; 00850 p->loginstart = 0; 00851 if (!p->deferlogoff) 00852 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00853 p->deferlogoff = 0; 00854 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00855 if (persistent_agents) 00856 dump_agents(); 00857 } 00858 } else if (p->dead) { 00859 ast_channel_lock(p->chan); 00860 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00861 ast_channel_unlock(p->chan); 00862 } else if (p->loginstart) { 00863 ast_channel_lock(p->chan); 00864 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00865 S_OR(p->moh, NULL), 00866 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00867 ast_channel_unlock(p->chan); 00868 } 00869 } 00870 ast_mutex_unlock(&p->lock); 00871 00872 /* Only register a device state change if the agent is still logged in */ 00873 if (!p->loginstart) { 00874 p->loginchan[0] = '\0'; 00875 p->logincallerid[0] = '\0'; 00876 if (persistent_agents) 00877 dump_agents(); 00878 } else { 00879 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00880 } 00881 00882 if (p->pending) { 00883 AST_LIST_LOCK(&agents); 00884 AST_LIST_REMOVE(&agents, p, list); 00885 AST_LIST_UNLOCK(&agents); 00886 } 00887 if (p->abouttograb) { 00888 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00889 kill it later */ 00890 p->abouttograb = 0; 00891 } else if (p->dead) { 00892 ast_mutex_destroy(&p->lock); 00893 ast_mutex_destroy(&p->app_lock); 00894 ast_cond_destroy(&p->app_complete_cond); 00895 ast_free(p); 00896 } else { 00897 if (p->chan) { 00898 /* Not dead -- check availability now */ 00899 ast_mutex_lock(&p->lock); 00900 /* Store last disconnect time */ 00901 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00902 ast_mutex_unlock(&p->lock); 00903 } 00904 /* Release ownership of the agent to other threads (presumably running the login app). */ 00905 if (ast_strlen_zero(p->loginchan)) { 00906 p->app_lock_flag = 0; 00907 ast_cond_signal(&p->app_complete_cond); 00908 } 00909 } 00910 return 0; 00911 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 635 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.
00636 { 00637 struct agent_pvt *p = ast->tech_pvt; 00638 int res = -1; 00639 ast_mutex_lock(&p->lock); 00640 if (p->chan && !ast_check_hangup(p->chan)) { 00641 while (ast_channel_trylock(p->chan)) { 00642 ast_channel_unlock(ast); 00643 usleep(1); 00644 ast_channel_lock(ast); 00645 } 00646 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00647 ast_channel_unlock(p->chan); 00648 } else 00649 res = 0; 00650 ast_mutex_unlock(&p->lock); 00651 return res; 00652 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1577 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(), agent_logoff_cmd(), and agent_read().
01578 { 01579 struct agent_pvt *p; 01580 long logintime; 01581 int ret = -1; /* Return -1 if no agent if found */ 01582 01583 AST_LIST_LOCK(&agents); 01584 AST_LIST_TRAVERSE(&agents, p, list) { 01585 if (!strcasecmp(p->agent, agent)) { 01586 ret = 0; 01587 if (p->owner || p->chan) { 01588 if (!soft) { 01589 ast_mutex_lock(&p->lock); 01590 01591 while (p->owner && ast_channel_trylock(p->owner)) { 01592 DEADLOCK_AVOIDANCE(&p->lock); 01593 } 01594 if (p->owner) { 01595 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01596 ast_channel_unlock(p->owner); 01597 } 01598 01599 while (p->chan && ast_channel_trylock(p->chan)) { 01600 DEADLOCK_AVOIDANCE(&p->lock); 01601 } 01602 if (p->chan) { 01603 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01604 ast_channel_unlock(p->chan); 01605 } 01606 01607 ast_mutex_unlock(&p->lock); 01608 } else 01609 p->deferlogoff = 1; 01610 } else { 01611 logintime = time(NULL) - p->loginstart; 01612 p->loginstart = 0; 01613 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01614 } 01615 break; 01616 } 01617 } 01618 AST_LIST_UNLOCK(&agents); 01619 01620 return ret; 01621 }
static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1623 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.
01624 { 01625 int ret; 01626 char *agent; 01627 01628 switch (cmd) { 01629 case CLI_INIT: 01630 e->command = "agent logoff"; 01631 e->usage = 01632 "Usage: agent logoff <channel> [soft]\n" 01633 " Sets an agent as no longer logged in.\n" 01634 " If 'soft' is specified, do not hangup existing calls.\n"; 01635 return NULL; 01636 case CLI_GENERATE: 01637 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01638 } 01639 01640 if (a->argc < 3 || a->argc > 4) 01641 return CLI_SHOWUSAGE; 01642 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01643 return CLI_SHOWUSAGE; 01644 01645 agent = a->argv[2] + 6; 01646 ret = agent_logoff(agent, a->argc == 4); 01647 if (ret == 0) 01648 ast_cli(a->fd, "Logging out %s\n", agent); 01649 01650 return CLI_SUCCESS; 01651 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1538 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().
01539 { 01540 char *tmp = NULL; 01541 char agent[AST_MAX_AGENT]; 01542 01543 if (!ast_strlen_zero(logcommand)) 01544 tmp = logcommand; 01545 else 01546 tmp = ast_strdupa(""); 01547 01548 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01549 01550 if (!ast_strlen_zero(uniqueid)) { 01551 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01552 "Agent: %s\r\n" 01553 "Reason: %s\r\n" 01554 "Loginchan: %s\r\n" 01555 "Logintime: %ld\r\n" 01556 "Uniqueid: %s\r\n", 01557 p->agent, tmp, loginchan, logintime, uniqueid); 01558 } else { 01559 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01560 "Agent: %s\r\n" 01561 "Reason: %s\r\n" 01562 "Loginchan: %s\r\n" 01563 "Logintime: %ld\r\n", 01564 p->agent, tmp, loginchan, logintime); 01565 } 01566 01567 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01568 set_agentbycallerid(p->logincallerid, NULL); 01569 p->loginchan[0] ='\0'; 01570 p->logincallerid[0] = '\0'; 01571 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 01572 if (persistent_agents) 01573 dump_agents(); 01574 01575 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static] |
Create new agent channel.
Definition at line 992 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().
00993 { 00994 struct ast_channel *tmp; 00995 int alreadylocked; 00996 #if 0 00997 if (!p->chan) { 00998 ast_log(LOG_WARNING, "No channel? :(\n"); 00999 return NULL; 01000 } 01001 #endif 01002 if (p->pending) 01003 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); 01004 else 01005 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 01006 if (!tmp) { 01007 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01008 return NULL; 01009 } 01010 01011 tmp->tech = &agent_tech; 01012 if (p->chan) { 01013 tmp->nativeformats = p->chan->nativeformats; 01014 tmp->writeformat = p->chan->writeformat; 01015 tmp->rawwriteformat = p->chan->writeformat; 01016 tmp->readformat = p->chan->readformat; 01017 tmp->rawreadformat = p->chan->readformat; 01018 ast_string_field_set(tmp, language, p->chan->language); 01019 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01020 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01021 /* XXX Is this really all we copy form the originating channel?? */ 01022 } else { 01023 tmp->nativeformats = AST_FORMAT_SLINEAR; 01024 tmp->writeformat = AST_FORMAT_SLINEAR; 01025 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01026 tmp->readformat = AST_FORMAT_SLINEAR; 01027 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01028 } 01029 /* Safe, agentlock already held */ 01030 tmp->tech_pvt = p; 01031 p->owner = tmp; 01032 tmp->priority = 1; 01033 /* Wake up and wait for other applications (by definition the login app) 01034 * to release this channel). Takes ownership of the agent channel 01035 * to this thread only. 01036 * For signalling the other thread, ast_queue_frame is used until we 01037 * can safely use signals for this purpose. The pselect() needs to be 01038 * implemented in the kernel for this. 01039 */ 01040 p->app_sleep_cond = 0; 01041 01042 alreadylocked = p->app_lock_flag; 01043 p->app_lock_flag = 1; 01044 01045 if(ast_strlen_zero(p->loginchan) && alreadylocked) { 01046 if (p->chan) { 01047 ast_queue_frame(p->chan, &ast_null_frame); 01048 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01049 p->app_lock_flag = 1; 01050 ast_mutex_lock(&p->lock); 01051 } else { 01052 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01053 p->owner = NULL; 01054 tmp->tech_pvt = NULL; 01055 p->app_sleep_cond = 1; 01056 ast_channel_free( tmp ); 01057 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01058 p->app_lock_flag = 0; 01059 ast_cond_signal(&p->app_complete_cond); 01060 return NULL; 01061 } 01062 } else if (!ast_strlen_zero(p->loginchan)) { 01063 if (p->chan) 01064 ast_queue_frame(p->chan, &ast_null_frame); 01065 if (!p->chan) { 01066 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01067 p->owner = NULL; 01068 tmp->tech_pvt = NULL; 01069 p->app_sleep_cond = 1; 01070 ast_channel_free( tmp ); 01071 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01072 return NULL; 01073 } 01074 } 01075 if (p->chan) 01076 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01077 return tmp; 01078 }
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(), agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, 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_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, 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 agent_logoff(p->agent, 0); 00509 } 00510 } 00511 switch (f->frametype) { 00512 case AST_FRAME_CONTROL: 00513 if (f->subclass == AST_CONTROL_ANSWER) { 00514 if (p->ackcall) { 00515 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); 00516 /* Don't pass answer along */ 00517 ast_frfree(f); 00518 f = &ast_null_frame; 00519 } else { 00520 p->acknowledged = 1; 00521 /* Use the builtin answer frame for the 00522 recording start check below. */ 00523 ast_frfree(f); 00524 f = &answer_frame; 00525 } 00526 } 00527 break; 00528 case AST_FRAME_DTMF_BEGIN: 00529 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00530 if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){ 00531 ast_frfree(f); 00532 f = &ast_null_frame; 00533 } 00534 break; 00535 case AST_FRAME_DTMF_END: 00536 if (!p->acknowledged && (f->subclass == p->acceptdtmf)) { 00537 ast_verb(3, "%s acknowledged\n", p->chan->name); 00538 p->acknowledged = 1; 00539 ast_frfree(f); 00540 f = &answer_frame; 00541 } else if (f->subclass == p->enddtmf && endcall) { 00542 /* terminates call */ 00543 ast_frfree(f); 00544 f = NULL; 00545 } 00546 break; 00547 case AST_FRAME_VOICE: 00548 case AST_FRAME_VIDEO: 00549 /* don't pass voice or video until the call is acknowledged */ 00550 if (!p->acknowledged) { 00551 ast_frfree(f); 00552 f = &ast_null_frame; 00553 } 00554 default: 00555 /* pass everything else on through */ 00556 break; 00557 } 00558 } 00559 00560 CLEANUP(ast,p); 00561 if (p->chan && !p->chan->_bridge) { 00562 if (strcasecmp(p->chan->tech->type, "Local")) { 00563 p->chan->_bridge = ast; 00564 if (p->chan) 00565 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00566 } 00567 } 00568 ast_mutex_unlock(&p->lock); 00569 if (recordagentcalls && f == &answer_frame) 00570 agent_start_monitoring(ast,0); 00571 return f; 00572 }
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 1345 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.
01346 { 01347 struct agent_pvt *p; 01348 struct ast_channel *chan = NULL; 01349 char *s; 01350 ast_group_t groupmatch; 01351 int groupoff; 01352 int waitforagent=0; 01353 int hasagent = 0; 01354 struct timeval now; 01355 01356 s = data; 01357 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01358 groupmatch = (1 << groupoff); 01359 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01360 groupmatch = (1 << groupoff); 01361 waitforagent = 1; 01362 } else 01363 groupmatch = 0; 01364 01365 /* Check actual logged in agents first */ 01366 AST_LIST_LOCK(&agents); 01367 AST_LIST_TRAVERSE(&agents, p, list) { 01368 ast_mutex_lock(&p->lock); 01369 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01370 ast_strlen_zero(p->loginchan)) { 01371 if (p->chan) 01372 hasagent++; 01373 now = ast_tvnow(); 01374 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01375 p->lastdisc = ast_tv(0, 0); 01376 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01377 if (!p->owner && p->chan) { 01378 /* Fixed agent */ 01379 chan = agent_new(p, AST_STATE_DOWN); 01380 } 01381 if (chan) { 01382 ast_mutex_unlock(&p->lock); 01383 break; 01384 } 01385 } 01386 } 01387 ast_mutex_unlock(&p->lock); 01388 } 01389 if (!p) { 01390 AST_LIST_TRAVERSE(&agents, p, list) { 01391 ast_mutex_lock(&p->lock); 01392 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01393 if (p->chan || !ast_strlen_zero(p->loginchan)) 01394 hasagent++; 01395 now = ast_tvnow(); 01396 #if 0 01397 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec); 01398 #endif 01399 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01400 p->lastdisc = ast_tv(0, 0); 01401 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01402 if (!p->owner && p->chan) { 01403 /* Could still get a fixed agent */ 01404 chan = agent_new(p, AST_STATE_DOWN); 01405 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01406 /* Adjustable agent */ 01407 p->chan = ast_request("Local", format, p->loginchan, cause); 01408 if (p->chan) 01409 chan = agent_new(p, AST_STATE_DOWN); 01410 } 01411 if (chan) { 01412 ast_mutex_unlock(&p->lock); 01413 break; 01414 } 01415 } 01416 } 01417 ast_mutex_unlock(&p->lock); 01418 } 01419 } 01420 01421 if (!chan && waitforagent) { 01422 /* No agent available -- but we're requesting to wait for one. 01423 Allocate a place holder */ 01424 if (hasagent) { 01425 ast_debug(1, "Creating place holder for '%s'\n", s); 01426 p = add_agent(data, 1); 01427 p->group = groupmatch; 01428 chan = agent_new(p, AST_STATE_DOWN); 01429 if (!chan) 01430 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01431 } else { 01432 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01433 } 01434 } 01435 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01436 AST_LIST_UNLOCK(&agents); 01437 return chan; 01438 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 574 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.
00575 { 00576 struct agent_pvt *p = ast->tech_pvt; 00577 int res = -1; 00578 ast_mutex_lock(&p->lock); 00579 if (p->chan) 00580 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00581 ast_mutex_unlock(&p->lock); 00582 return res; 00583 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 585 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.
00586 { 00587 struct agent_pvt *p = ast->tech_pvt; 00588 int res = -1; 00589 ast_mutex_lock(&p->lock); 00590 if (p->chan) 00591 res = ast_sendtext(p->chan, text); 00592 ast_mutex_unlock(&p->lock); 00593 return res; 00594 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 782 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.
00783 { 00784 struct agent_pvt *p = NULL; 00785 00786 if (!chan || !base) { 00787 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00788 return -1; 00789 } 00790 p = chan->tech_pvt; 00791 if (!p) { 00792 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00793 return -1; 00794 } 00795 p->chan = base; 00796 return 0; 00797 }
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 596 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.
00597 { 00598 struct agent_pvt *p = ast->tech_pvt; 00599 int res = -1; 00600 CHECK_FORMATS(ast, p); 00601 ast_mutex_lock(&p->lock); 00602 if (!p->chan) 00603 res = 0; 00604 else { 00605 if ((f->frametype != AST_FRAME_VOICE) || 00606 (f->frametype != AST_FRAME_VIDEO) || 00607 (f->subclass == p->chan->writeformat)) { 00608 res = ast_write(p->chan, f); 00609 } else { 00610 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00611 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00612 ast->name, p->chan->name); 00613 res = 0; 00614 } 00615 } 00616 CLEANUP(ast, p); 00617 ast_mutex_unlock(&p->lock); 00618 return res; 00619 }
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 2202 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().
02203 { 02204 int exitifnoagentid = 0; 02205 int nowarnings = 0; 02206 int changeoutgoing = 0; 02207 int res = 0; 02208 char agent[AST_MAX_AGENT]; 02209 02210 if (data) { 02211 if (strchr(data, 'd')) 02212 exitifnoagentid = 1; 02213 if (strchr(data, 'n')) 02214 nowarnings = 1; 02215 if (strchr(data, 'c')) 02216 changeoutgoing = 1; 02217 } 02218 if (chan->cid.cid_num) { 02219 const char *tmp; 02220 char agentvar[AST_MAX_BUF]; 02221 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02222 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02223 struct agent_pvt *p; 02224 ast_copy_string(agent, tmp, sizeof(agent)); 02225 AST_LIST_LOCK(&agents); 02226 AST_LIST_TRAVERSE(&agents, p, list) { 02227 if (!strcasecmp(p->agent, tmp)) { 02228 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02229 __agent_start_monitoring(chan, p, 1); 02230 break; 02231 } 02232 } 02233 AST_LIST_UNLOCK(&agents); 02234 02235 } else { 02236 res = -1; 02237 if (!nowarnings) 02238 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); 02239 } 02240 } else { 02241 res = -1; 02242 if (!nowarnings) 02243 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"); 02244 } 02245 if (res) { 02246 if (exitifnoagentid) 02247 return res; 02248 } 02249 return 0; 02250 }
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 1710 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.
01711 { 01712 struct agent_pvt *p; 01713 char username[AST_MAX_BUF]; 01714 char location[AST_MAX_BUF] = ""; 01715 char talkingto[AST_MAX_BUF] = ""; 01716 char music[AST_MAX_BUF]; 01717 int count_agents = 0; /*!< Number of agents configured */ 01718 int online_agents = 0; /*!< Number of online agents */ 01719 int offline_agents = 0; /*!< Number of offline agents */ 01720 01721 switch (cmd) { 01722 case CLI_INIT: 01723 e->command = "agent show"; 01724 e->usage = 01725 "Usage: agent show\n" 01726 " Provides summary information on agents.\n"; 01727 return NULL; 01728 case CLI_GENERATE: 01729 return NULL; 01730 } 01731 01732 if (a->argc != 2) 01733 return CLI_SHOWUSAGE; 01734 01735 AST_LIST_LOCK(&agents); 01736 AST_LIST_TRAVERSE(&agents, p, list) { 01737 ast_mutex_lock(&p->lock); 01738 if (p->pending) { 01739 if (p->group) 01740 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01741 else 01742 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01743 } else { 01744 if (!ast_strlen_zero(p->name)) 01745 snprintf(username, sizeof(username), "(%s) ", p->name); 01746 else 01747 username[0] = '\0'; 01748 if (p->chan) { 01749 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01750 if (p->owner && ast_bridged_channel(p->owner)) 01751 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01752 else 01753 strcpy(talkingto, " is idle"); 01754 online_agents++; 01755 } else if (!ast_strlen_zero(p->loginchan)) { 01756 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01757 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01758 else 01759 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01760 talkingto[0] = '\0'; 01761 online_agents++; 01762 if (p->acknowledged) 01763 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01764 } else { 01765 strcpy(location, "not logged in"); 01766 talkingto[0] = '\0'; 01767 offline_agents++; 01768 } 01769 if (!ast_strlen_zero(p->moh)) 01770 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01771 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01772 username, location, talkingto, music); 01773 count_agents++; 01774 } 01775 ast_mutex_unlock(&p->lock); 01776 } 01777 AST_LIST_UNLOCK(&agents); 01778 if ( !count_agents ) 01779 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01780 else 01781 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01782 ast_cli(a->fd, "\n"); 01783 01784 return CLI_SUCCESS; 01785 }
static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1788 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.
01789 { 01790 struct agent_pvt *p; 01791 char username[AST_MAX_BUF]; 01792 char location[AST_MAX_BUF] = ""; 01793 char talkingto[AST_MAX_BUF] = ""; 01794 char music[AST_MAX_BUF]; 01795 int count_agents = 0; /* Number of agents configured */ 01796 int online_agents = 0; /* Number of online agents */ 01797 int agent_status = 0; /* 0 means offline, 1 means online */ 01798 01799 switch (cmd) { 01800 case CLI_INIT: 01801 e->command = "agent show online"; 01802 e->usage = 01803 "Usage: agent show online\n" 01804 " Provides a list of all online agents.\n"; 01805 return NULL; 01806 case CLI_GENERATE: 01807 return NULL; 01808 } 01809 01810 if (a->argc != 3) 01811 return CLI_SHOWUSAGE; 01812 01813 AST_LIST_LOCK(&agents); 01814 AST_LIST_TRAVERSE(&agents, p, list) { 01815 agent_status = 0; /* reset it to offline */ 01816 ast_mutex_lock(&p->lock); 01817 if (!ast_strlen_zero(p->name)) 01818 snprintf(username, sizeof(username), "(%s) ", p->name); 01819 else 01820 username[0] = '\0'; 01821 if (p->chan) { 01822 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01823 if (p->owner && ast_bridged_channel(p->owner)) 01824 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01825 else 01826 strcpy(talkingto, " is idle"); 01827 agent_status = 1; 01828 online_agents++; 01829 } else if (!ast_strlen_zero(p->loginchan)) { 01830 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01831 talkingto[0] = '\0'; 01832 agent_status = 1; 01833 online_agents++; 01834 if (p->acknowledged) 01835 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01836 } 01837 if (!ast_strlen_zero(p->moh)) 01838 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01839 if (agent_status) 01840 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01841 count_agents++; 01842 ast_mutex_unlock(&p->lock); 01843 } 01844 AST_LIST_UNLOCK(&agents); 01845 if (!count_agents) 01846 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01847 else 01848 ast_cli(a->fd, "%d agents online\n", online_agents); 01849 ast_cli(a->fd, "\n"); 01850 return CLI_SUCCESS; 01851 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1243 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().
01244 { 01245 struct ast_channel *chan=NULL, *parent=NULL; 01246 struct agent_pvt *p; 01247 int res; 01248 01249 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01250 if (needlock) 01251 AST_LIST_LOCK(&agents); 01252 AST_LIST_TRAVERSE(&agents, p, list) { 01253 if (p == newlyavailable) { 01254 continue; 01255 } 01256 ast_mutex_lock(&p->lock); 01257 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01258 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01259 /* We found a pending call, time to merge */ 01260 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01261 parent = p->owner; 01262 p->abouttograb = 1; 01263 ast_mutex_unlock(&p->lock); 01264 break; 01265 } 01266 ast_mutex_unlock(&p->lock); 01267 } 01268 if (needlock) 01269 AST_LIST_UNLOCK(&agents); 01270 if (parent && chan) { 01271 if (newlyavailable->ackcall > 1) { 01272 /* Don't do beep here */ 01273 res = 0; 01274 } else { 01275 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01276 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01277 ast_debug(3, "Played beep, result '%d'\n", res); 01278 if (!res) { 01279 res = ast_waitstream(newlyavailable->chan, ""); 01280 ast_debug(1, "Waited for stream, result '%d'\n", res); 01281 } 01282 } 01283 if (!res) { 01284 /* Note -- parent may have disappeared */ 01285 if (p->abouttograb) { 01286 newlyavailable->acknowledged = 1; 01287 /* Safe -- agent lock already held */ 01288 ast_setstate(parent, AST_STATE_UP); 01289 ast_setstate(chan, AST_STATE_UP); 01290 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01291 /* Go ahead and mark the channel as a zombie so that masquerade will 01292 destroy it for us, and we need not call ast_hangup */ 01293 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01294 ast_channel_masquerade(parent, chan); 01295 p->abouttograb = 0; 01296 } else { 01297 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01298 agent_cleanup(newlyavailable); 01299 } 01300 } else { 01301 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01302 agent_cleanup(newlyavailable); 01303 } 01304 } 01305 return 0; 01306 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1308 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().
01309 { 01310 struct agent_pvt *p; 01311 int res=0; 01312 01313 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01314 if (needlock) 01315 AST_LIST_LOCK(&agents); 01316 AST_LIST_TRAVERSE(&agents, p, list) { 01317 if (p == newlyavailable) { 01318 continue; 01319 } 01320 ast_mutex_lock(&p->lock); 01321 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01322 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01323 ast_mutex_unlock(&p->lock); 01324 break; 01325 } 01326 ast_mutex_unlock(&p->lock); 01327 } 01328 if (needlock) 01329 AST_LIST_UNLOCK(&agents); 01330 if (p) { 01331 ast_mutex_unlock(&newlyavailable->lock); 01332 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01333 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01334 ast_debug(1, "Played beep, result '%d'\n", res); 01335 if (!res) { 01336 res = ast_waitstream(newlyavailable->chan, ""); 01337 ast_debug(1, "Waited for stream, result '%d'\n", res); 01338 } 01339 ast_mutex_lock(&newlyavailable->lock); 01340 } 01341 return res; 01342 }
static char * complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1683 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().
01684 { 01685 char *ret = NULL; 01686 01687 if (pos == 2) { 01688 struct agent_pvt *p; 01689 char name[AST_MAX_AGENT]; 01690 int which = 0, len = strlen(word); 01691 01692 AST_LIST_LOCK(&agents); 01693 AST_LIST_TRAVERSE(&agents, p, list) { 01694 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01695 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01696 ret = ast_strdup(name); 01697 break; 01698 } 01699 } 01700 AST_LIST_UNLOCK(&agents); 01701 } else if (pos == 3 && state == 0) 01702 return ast_strdup("soft"); 01703 01704 return ret; 01705 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2255 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().
02256 { 02257 struct agent_pvt *cur_agent = NULL; 02258 char buf[256]; 02259 02260 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02261 if (cur_agent->chan) 02262 continue; 02263 02264 if (!ast_strlen_zero(cur_agent->loginchan)) { 02265 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02266 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02267 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02268 else 02269 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02270 } else { 02271 /* Delete - no agent or there is an error */ 02272 ast_db_del(pa_family, cur_agent->agent); 02273 } 02274 } 02275 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2378 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_TRAVERSE, and agent_pvt::list.
Referenced by function_agent().
02379 { 02380 struct agent_pvt *cur; 02381 02382 AST_LIST_TRAVERSE(&agents, cur, list) { 02383 if (!strcmp(cur->agent, agentid)) 02384 break; 02385 } 02386 02387 return cur; 02388 }
static int function_agent | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2390 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.
02391 { 02392 char *parse; 02393 AST_DECLARE_APP_ARGS(args, 02394 AST_APP_ARG(agentid); 02395 AST_APP_ARG(item); 02396 ); 02397 char *tmp; 02398 struct agent_pvt *agent; 02399 02400 buf[0] = '\0'; 02401 02402 if (ast_strlen_zero(data)) { 02403 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02404 return -1; 02405 } 02406 02407 parse = ast_strdupa(data); 02408 02409 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02410 if (!args.item) 02411 args.item = "status"; 02412 02413 AST_LIST_LOCK(&agents); 02414 02415 if (!(agent = find_agent(args.agentid))) { 02416 AST_LIST_UNLOCK(&agents); 02417 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02418 return -1; 02419 } 02420 02421 if (!strcasecmp(args.item, "status")) { 02422 char *status = "LOGGEDOUT"; 02423 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02424 status = "LOGGEDIN"; 02425 ast_copy_string(buf, status, len); 02426 } else if (!strcasecmp(args.item, "password")) 02427 ast_copy_string(buf, agent->password, len); 02428 else if (!strcasecmp(args.item, "name")) 02429 ast_copy_string(buf, agent->name, len); 02430 else if (!strcasecmp(args.item, "mohclass")) 02431 ast_copy_string(buf, agent->moh, len); 02432 else if (!strcasecmp(args.item, "channel")) { 02433 if (agent->chan) { 02434 ast_copy_string(buf, agent->chan->name, len); 02435 tmp = strrchr(buf, '-'); 02436 if (tmp) 02437 *tmp = '\0'; 02438 } 02439 } else if (!strcasecmp(args.item, "exten")) 02440 ast_copy_string(buf, agent->loginchan, len); 02441 02442 AST_LIST_UNLOCK(&agents); 02443 02444 return 0; 02445 }
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 2470 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().
02471 { 02472 /* Make sure we can register our agent channel type */ 02473 if (ast_channel_register(&agent_tech)) { 02474 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02475 return AST_MODULE_LOAD_FAILURE; 02476 } 02477 /* Read in the config */ 02478 if (!read_agent_config(0)) 02479 return AST_MODULE_LOAD_DECLINE; 02480 if (persistent_agents) 02481 reload_agents(); 02482 /* Dialplan applications */ 02483 ast_register_application(app, login_exec, synopsis, descrip); 02484 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02485 02486 /* Manager commands */ 02487 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02488 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02489 02490 /* CLI Commands */ 02491 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02492 02493 /* Dialplan Functions */ 02494 ast_custom_function_register(&agent_function); 02495 02496 return AST_MODULE_LOAD_SUCCESS; 02497 }
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 1874 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().
01875 { 01876 int res=0; 01877 int tries = 0; 01878 int max_login_tries = maxlogintries; 01879 struct agent_pvt *p; 01880 struct ast_module_user *u; 01881 int login_state = 0; 01882 char user[AST_MAX_AGENT] = ""; 01883 char pass[AST_MAX_AGENT]; 01884 char agent[AST_MAX_AGENT] = ""; 01885 char xpass[AST_MAX_AGENT] = ""; 01886 char *errmsg; 01887 char *parse; 01888 AST_DECLARE_APP_ARGS(args, 01889 AST_APP_ARG(agent_id); 01890 AST_APP_ARG(options); 01891 AST_APP_ARG(extension); 01892 ); 01893 const char *tmpoptions = NULL; 01894 int play_announcement = 1; 01895 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01896 int update_cdr = updatecdr; 01897 char *filename = "agent-loginok"; 01898 01899 u = ast_module_user_add(chan); 01900 01901 parse = ast_strdupa(data); 01902 01903 AST_STANDARD_APP_ARGS(args, parse); 01904 01905 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01906 01907 ast_channel_lock(chan); 01908 /* Set Channel Specific Login Overrides */ 01909 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01910 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01911 if (max_login_tries < 0) 01912 max_login_tries = 0; 01913 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01914 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 01915 } 01916 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01917 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01918 update_cdr = 1; 01919 else 01920 update_cdr = 0; 01921 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01922 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01923 } 01924 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01925 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01926 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01927 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01928 } 01929 ast_channel_unlock(chan); 01930 /* End Channel Specific Login Overrides */ 01931 01932 if (!ast_strlen_zero(args.options)) { 01933 if (strchr(args.options, 's')) { 01934 play_announcement = 0; 01935 } 01936 } 01937 01938 if (chan->_state != AST_STATE_UP) 01939 res = ast_answer(chan); 01940 if (!res) { 01941 if (!ast_strlen_zero(args.agent_id)) 01942 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01943 else 01944 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01945 } 01946 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01947 tries++; 01948 /* Check for password */ 01949 AST_LIST_LOCK(&agents); 01950 AST_LIST_TRAVERSE(&agents, p, list) { 01951 if (!strcmp(p->agent, user) && !p->pending) 01952 ast_copy_string(xpass, p->password, sizeof(xpass)); 01953 } 01954 AST_LIST_UNLOCK(&agents); 01955 if (!res) { 01956 if (!ast_strlen_zero(xpass)) 01957 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01958 else 01959 pass[0] = '\0'; 01960 } 01961 errmsg = "agent-incorrect"; 01962 01963 #if 0 01964 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01965 #endif 01966 01967 /* Check again for accuracy */ 01968 AST_LIST_LOCK(&agents); 01969 AST_LIST_TRAVERSE(&agents, p, list) { 01970 int unlock_channel = 1; 01971 ast_channel_lock(chan); 01972 ast_mutex_lock(&p->lock); 01973 if (!strcmp(p->agent, user) && 01974 !strcmp(p->password, pass) && !p->pending) { 01975 login_state = 1; /* Successful Login */ 01976 01977 /* Ensure we can't be gotten until we're done */ 01978 p->lastdisc = ast_tvnow(); 01979 p->lastdisc.tv_sec++; 01980 01981 /* Set Channel Specific Agent Overrides */ 01982 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01983 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 01984 p->ackcall = 2; 01985 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 01986 p->ackcall = 1; 01987 else 01988 p->ackcall = 0; 01989 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01990 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 01991 ast_set_flag(p, AGENT_FLAG_ACKCALL); 01992 } else { 01993 p->ackcall = ackcall; 01994 } 01995 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01996 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01997 if (p->autologoff < 0) 01998 p->autologoff = 0; 01999 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02000 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 02001 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 02002 } else { 02003 p->autologoff = autologoff; 02004 } 02005 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02006 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02007 if (p->wrapuptime < 0) 02008 p->wrapuptime = 0; 02009 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02010 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 02011 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 02012 } else { 02013 p->wrapuptime = wrapuptime; 02014 } 02015 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDMTF"); 02016 if (!ast_strlen_zero(tmpoptions)) { 02017 p->acceptdtmf = *tmpoptions; 02018 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 02019 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 02020 } 02021 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 02022 if (!ast_strlen_zero(tmpoptions)) { 02023 p->enddtmf = *tmpoptions; 02024 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 02025 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 02026 } 02027 ast_channel_unlock(chan); 02028 unlock_channel = 0; 02029 /* End Channel Specific Agent Overrides */ 02030 if (!p->chan) { 02031 long logintime; 02032 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02033 02034 p->loginchan[0] = '\0'; 02035 p->logincallerid[0] = '\0'; 02036 p->acknowledged = 0; 02037 02038 ast_mutex_unlock(&p->lock); 02039 AST_LIST_UNLOCK(&agents); 02040 if( !res && play_announcement==1 ) 02041 res = ast_streamfile(chan, filename, chan->language); 02042 if (!res) 02043 ast_waitstream(chan, ""); 02044 AST_LIST_LOCK(&agents); 02045 ast_mutex_lock(&p->lock); 02046 if (!res) { 02047 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02048 if (res) 02049 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02050 } 02051 if (!res) { 02052 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02053 if (res) 02054 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02055 } 02056 /* Check once more just in case */ 02057 if (p->chan) 02058 res = -1; 02059 if (!res) { 02060 ast_indicate_data(chan, AST_CONTROL_HOLD, 02061 S_OR(p->moh, NULL), 02062 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02063 if (p->loginstart == 0) 02064 time(&p->loginstart); 02065 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02066 "Agent: %s\r\n" 02067 "Channel: %s\r\n" 02068 "Uniqueid: %s\r\n", 02069 p->agent, chan->name, chan->uniqueid); 02070 if (update_cdr && chan->cdr) 02071 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02072 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02073 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 02074 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02075 /* Login this channel and wait for it to go away */ 02076 p->chan = chan; 02077 if (p->ackcall > 1) 02078 check_beep(p, 0); 02079 else 02080 check_availability(p, 0); 02081 ast_mutex_unlock(&p->lock); 02082 AST_LIST_UNLOCK(&agents); 02083 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02084 while (res >= 0) { 02085 ast_mutex_lock(&p->lock); 02086 if (p->deferlogoff && p->chan) { 02087 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02088 p->deferlogoff = 0; 02089 } 02090 if (p->chan != chan) 02091 res = -1; 02092 ast_mutex_unlock(&p->lock); 02093 /* Yield here so other interested threads can kick in. */ 02094 sched_yield(); 02095 if (res) 02096 break; 02097 02098 AST_LIST_LOCK(&agents); 02099 ast_mutex_lock(&p->lock); 02100 if (p->lastdisc.tv_sec) { 02101 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02102 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02103 p->lastdisc = ast_tv(0, 0); 02104 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02105 if (p->ackcall > 1) 02106 check_beep(p, 0); 02107 else 02108 check_availability(p, 0); 02109 } 02110 } 02111 ast_mutex_unlock(&p->lock); 02112 AST_LIST_UNLOCK(&agents); 02113 /* Synchronize channel ownership between call to agent and itself. */ 02114 ast_mutex_lock(&p->app_lock); 02115 if (p->app_lock_flag == 1) { 02116 ast_cond_wait(&p->app_complete_cond, &p->app_lock); 02117 } 02118 ast_mutex_unlock(&p->app_lock); 02119 ast_mutex_lock(&p->lock); 02120 ast_mutex_unlock(&p->lock); 02121 if (p->ackcall > 1) 02122 res = agent_ack_sleep(p); 02123 else 02124 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02125 if ((p->ackcall > 1) && (res == 1)) { 02126 AST_LIST_LOCK(&agents); 02127 ast_mutex_lock(&p->lock); 02128 check_availability(p, 0); 02129 ast_mutex_unlock(&p->lock); 02130 AST_LIST_UNLOCK(&agents); 02131 res = 0; 02132 } 02133 sched_yield(); 02134 } 02135 ast_mutex_lock(&p->lock); 02136 if (res && p->owner) 02137 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02138 /* Log us off if appropriate */ 02139 if (p->chan == chan) { 02140 p->chan = NULL; 02141 } 02142 p->acknowledged = 0; 02143 logintime = time(NULL) - p->loginstart; 02144 p->loginstart = 0; 02145 ast_mutex_unlock(&p->lock); 02146 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02147 "Agent: %s\r\n" 02148 "Logintime: %ld\r\n" 02149 "Uniqueid: %s\r\n", 02150 p->agent, logintime, chan->uniqueid); 02151 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02152 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02153 /* If there is no owner, go ahead and kill it now */ 02154 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02155 if (p->dead && !p->owner) { 02156 ast_mutex_destroy(&p->lock); 02157 ast_mutex_destroy(&p->app_lock); 02158 ast_cond_destroy(&p->app_complete_cond); 02159 ast_free(p); 02160 } 02161 } 02162 else { 02163 ast_mutex_unlock(&p->lock); 02164 p = NULL; 02165 } 02166 res = -1; 02167 } else { 02168 ast_mutex_unlock(&p->lock); 02169 errmsg = "agent-alreadyon"; 02170 p = NULL; 02171 } 02172 break; 02173 } 02174 ast_mutex_unlock(&p->lock); 02175 if (unlock_channel) { 02176 ast_channel_unlock(chan); 02177 } 02178 } 02179 if (!p) 02180 AST_LIST_UNLOCK(&agents); 02181 02182 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02183 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02184 } 02185 02186 if (!res) 02187 res = ast_safe_sleep(chan, 500); 02188 02189 ast_module_user_remove(u); 02190 02191 return -1; 02192 }
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 1086 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().
01087 { 01088 struct ast_config *cfg; 01089 struct ast_config *ucfg; 01090 struct ast_variable *v; 01091 struct agent_pvt *p; 01092 const char *general_val; 01093 const char *catname; 01094 const char *hasagent; 01095 int genhasagent; 01096 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01097 01098 group = 0; 01099 autologoff = 0; 01100 wrapuptime = 0; 01101 ackcall = 0; 01102 endcall = 1; 01103 cfg = ast_config_load(config, config_flags); 01104 if (!cfg) { 01105 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01106 return 0; 01107 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) 01108 return -1; 01109 AST_LIST_LOCK(&agents); 01110 AST_LIST_TRAVERSE(&agents, p, list) { 01111 p->dead = 1; 01112 } 01113 strcpy(moh, "default"); 01114 /* set the default recording values */ 01115 recordagentcalls = 0; 01116 strcpy(recordformat, "wav"); 01117 strcpy(recordformatext, "wav"); 01118 urlprefix[0] = '\0'; 01119 savecallsin[0] = '\0'; 01120 01121 /* Read in [general] section for persistence */ 01122 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01123 persistent_agents = ast_true(general_val); 01124 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01125 01126 /* Read in the [agents] section */ 01127 v = ast_variable_browse(cfg, "agents"); 01128 while(v) { 01129 /* Create the interface list */ 01130 if (!strcasecmp(v->name, "agent")) { 01131 add_agent(v->value, 0); 01132 } else if (!strcasecmp(v->name, "group")) { 01133 group = ast_get_group(v->value); 01134 } else if (!strcasecmp(v->name, "autologoff")) { 01135 autologoff = atoi(v->value); 01136 if (autologoff < 0) 01137 autologoff = 0; 01138 } else if (!strcasecmp(v->name, "ackcall")) { 01139 if (!strcasecmp(v->value, "always")) 01140 ackcall = 2; 01141 else if (ast_true(v->value)) 01142 ackcall = 1; 01143 else 01144 ackcall = 0; 01145 } else if (!strcasecmp(v->name, "endcall")) { 01146 endcall = ast_true(v->value); 01147 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01148 acceptdtmf = *(v->value); 01149 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01150 } else if (!strcasecmp(v->name, "enddtmf")) { 01151 enddtmf = *(v->value); 01152 } else if (!strcasecmp(v->name, "wrapuptime")) { 01153 wrapuptime = atoi(v->value); 01154 if (wrapuptime < 0) 01155 wrapuptime = 0; 01156 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01157 maxlogintries = atoi(v->value); 01158 if (maxlogintries < 0) 01159 maxlogintries = 0; 01160 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01161 strcpy(agentgoodbye,v->value); 01162 } else if (!strcasecmp(v->name, "musiconhold")) { 01163 ast_copy_string(moh, v->value, sizeof(moh)); 01164 } else if (!strcasecmp(v->name, "updatecdr")) { 01165 if (ast_true(v->value)) 01166 updatecdr = 1; 01167 else 01168 updatecdr = 0; 01169 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01170 if (ast_true(v->value)) 01171 autologoffunavail = 1; 01172 else 01173 autologoffunavail = 0; 01174 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01175 recordagentcalls = ast_true(v->value); 01176 } else if (!strcasecmp(v->name, "recordformat")) { 01177 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01178 if (!strcasecmp(v->value, "wav49")) 01179 strcpy(recordformatext, "WAV"); 01180 else 01181 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01182 } else if (!strcasecmp(v->name, "urlprefix")) { 01183 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01184 if (urlprefix[strlen(urlprefix) - 1] != '/') 01185 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01186 } else if (!strcasecmp(v->name, "savecallsin")) { 01187 if (v->value[0] == '/') 01188 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01189 else 01190 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01191 if (savecallsin[strlen(savecallsin) - 1] != '/') 01192 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01193 } else if (!strcasecmp(v->name, "custom_beep")) { 01194 ast_copy_string(beep, v->value, sizeof(beep)); 01195 } 01196 v = v->next; 01197 } 01198 if ((ucfg = ast_config_load("users.conf", config_flags)) && ucfg != CONFIG_STATUS_FILEUNCHANGED) { 01199 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01200 catname = ast_category_browse(ucfg, NULL); 01201 while(catname) { 01202 if (strcasecmp(catname, "general")) { 01203 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01204 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01205 char tmp[256]; 01206 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01207 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01208 if (!fullname) 01209 fullname = ""; 01210 if (!secret) 01211 secret = ""; 01212 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01213 add_agent(tmp, 0); 01214 } 01215 } 01216 catname = ast_category_browse(ucfg, catname); 01217 } 01218 ast_config_destroy(ucfg); 01219 } 01220 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01221 if (p->dead) { 01222 AST_LIST_REMOVE_CURRENT(list); 01223 /* Destroy if appropriate */ 01224 if (!p->owner) { 01225 if (!p->chan) { 01226 ast_mutex_destroy(&p->lock); 01227 ast_mutex_destroy(&p->app_lock); 01228 ast_cond_destroy(&p->app_complete_cond); 01229 ast_free(p); 01230 } else { 01231 /* Cause them to hang up */ 01232 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01233 } 01234 } 01235 } 01236 } 01237 AST_LIST_TRAVERSE_SAFE_END; 01238 AST_LIST_UNLOCK(&agents); 01239 ast_config_destroy(cfg); 01240 return 1; 01241 }
static int reload | ( | void | ) | [static] |
Definition at line 2499 of file chan_agent.c.
References read_agent_config(), and reload_agents().
02500 { 02501 if (!read_agent_config(1)) { 02502 if (persistent_agents) 02503 reload_agents(); 02504 } 02505 return 0; 02506 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2280 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().
02281 { 02282 char *agent_num; 02283 struct ast_db_entry *db_tree; 02284 struct ast_db_entry *entry; 02285 struct agent_pvt *cur_agent; 02286 char agent_data[256]; 02287 char *parse; 02288 char *agent_chan; 02289 char *agent_callerid; 02290 02291 db_tree = ast_db_gettree(pa_family, NULL); 02292 02293 AST_LIST_LOCK(&agents); 02294 for (entry = db_tree; entry; entry = entry->next) { 02295 agent_num = entry->key + strlen(pa_family) + 2; 02296 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02297 ast_mutex_lock(&cur_agent->lock); 02298 if (strcmp(agent_num, cur_agent->agent) == 0) 02299 break; 02300 ast_mutex_unlock(&cur_agent->lock); 02301 } 02302 if (!cur_agent) { 02303 ast_db_del(pa_family, agent_num); 02304 continue; 02305 } else 02306 ast_mutex_unlock(&cur_agent->lock); 02307 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02308 ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02309 parse = agent_data; 02310 agent_chan = strsep(&parse, ";"); 02311 agent_callerid = strsep(&parse, ";"); 02312 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02313 if (agent_callerid) { 02314 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02315 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02316 } else 02317 cur_agent->logincallerid[0] = '\0'; 02318 if (cur_agent->loginstart == 0) 02319 time(&cur_agent->loginstart); 02320 ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 02321 } 02322 } 02323 AST_LIST_UNLOCK(&agents); 02324 if (db_tree) { 02325 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02326 ast_db_freetree(db_tree); 02327 } 02328 }
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 753 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().
00754 { 00755 char buf[AST_MAX_BUF]; 00756 00757 /* if there is no Caller ID, nothing to do */ 00758 if (ast_strlen_zero(callerid)) 00759 return; 00760 00761 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00762 pbx_builtin_setvar_helper(NULL, buf, agent); 00763 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2508 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().
02509 { 02510 struct agent_pvt *p; 02511 /* First, take us out of the channel loop */ 02512 ast_channel_unregister(&agent_tech); 02513 /* Unregister dialplan functions */ 02514 ast_custom_function_unregister(&agent_function); 02515 /* Unregister CLI commands */ 02516 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02517 /* Unregister dialplan applications */ 02518 ast_unregister_application(app); 02519 ast_unregister_application(app3); 02520 /* Unregister manager command */ 02521 ast_manager_unregister("Agents"); 02522 ast_manager_unregister("AgentLogoff"); 02523 /* Unregister channel */ 02524 AST_LIST_LOCK(&agents); 02525 /* Hangup all interfaces if they have an owner */ 02526 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02527 if (p->owner) 02528 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02529 ast_free(p); 02530 } 02531 AST_LIST_UNLOCK(&agents); 02532 return 0; 02533 }
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 2539 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 1853 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 2539 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 1858 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 dial_exec_full(), get_mohbyname(), moh_generate(), moh_register(), 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.