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