Implementation of Agents (proxy channel). More...
#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.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/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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"
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 |
Functions | |
static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
static int | __login_exec (struct ast_channel *chan, void *data, int callbackmode) |
Log in agent application. | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | action_agent_callback_login (struct mansession *s, const struct message *m) |
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 (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_devicestate_cb (const char *dev, int state, void *data) |
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 int | agent_logoff_cmd (int fd, int argc, char **argv) |
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 int | agents_show (int fd, int argc, char **argv) |
static int | agents_show_online (int fd, int argc, char **argv) |
static int | allow_multiple_login (char *chan, char *context) |
static void | callback_deprecated (void) |
static int | callback_exec (struct ast_channel *chan, void *data) |
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, 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) |
static int | read_agent_config (void) |
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 | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
static int | ackcall |
struct ast_custom_function | agent_function |
static 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 | app2 [] = "AgentCallbackLogin" |
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 struct ast_cli_entry | cli_show_agents_deprecated |
static struct ast_cli_entry | cli_show_agents_online_deprecated |
static const char | config [] = "agents.conf" |
static const char | descrip [] |
static const char | descrip2 [] |
static const char | descrip3 [] |
static int | endcall |
static ast_group_t | group |
static const char | mandescr_agent_callback_login [] |
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 char | show_agents_online_usage [] |
static char | show_agents_usage [] |
static const char | synopsis [] = "Call agent login" |
static const char | synopsis2 [] = "Call agent callback 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 |
Implementation of Agents (proxy channel).
This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.
Definition in file chan_agent.c.
#define AST_MAX_AGENT 80 |
Agent ID or Password max length
Definition at line 146 of file chan_agent.c.
Referenced by __login_exec(), agent_logoff_maintenance(), agentmonitoroutgoing_exec(), and complete_agent_logoff_cmd().
#define AST_MAX_BUF 256 |
Definition at line 147 of file chan_agent.c.
Referenced by __agent_start_monitoring(), __login_exec(), agentmonitoroutgoing_exec(), agents_show(), agents_show_online(), and set_agentbycallerid().
#define AST_MAX_FILENAME_LEN 256 |
Definition at line 148 of file chan_agent.c.
Referenced by __login_exec(), and ael2_semantic_check().
#define CHECK_FORMATS | ( | ast, | |||
p | ) |
Definition at line 213 of file chan_agent.c.
Referenced by agent_read(), and agent_write().
#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 234 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
#define GETAGENTBYCALLERID "AGENTBYCALLERID" |
Definition at line 175 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 151 of file chan_agent.c.
static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
struct agent_pvt * | p, | |||
int | needlock | |||
) | [static] |
Definition at line 463 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, and ast_channel::monitor.
Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().
00464 { 00465 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00466 char filename[AST_MAX_BUF]; 00467 int res = -1; 00468 if (!p) 00469 return -1; 00470 if (!ast->monitor) { 00471 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00472 /* substitute . for - */ 00473 if ((pointer = strchr(filename, '.'))) 00474 *pointer = '-'; 00475 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00476 ast_monitor_start(ast, recordformat, tmp, needlock); 00477 ast_monitor_setjoinfiles(ast, 1); 00478 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00479 #if 0 00480 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00481 #endif 00482 if (!ast->cdr) 00483 ast->cdr = ast_cdr_alloc(); 00484 ast_cdr_setuserfield(ast, tmp2); 00485 res = 0; 00486 } else 00487 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00488 return res; 00489 }
static int __login_exec | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | callbackmode | |||
) | [static] |
Log in agent application.
chan | ||
data | ||
callbackmode | non-zero for AgentCallbackLogin |
Definition at line 1985 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_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_complete_cond, 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_signal(), ast_cond_wait(), AST_CONTROL_HOLD, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, 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_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_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, ast_channel::exten, free, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::owner, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), agent_pvt::pending, ast_channel::priority, ast_channel::readformat, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, agent_pvt::wrapuptime, and ast_channel::writeformat.
Referenced by callback_exec(), and login_exec().
01986 { 01987 int res=0; 01988 int tries = 0; 01989 int max_login_tries = maxlogintries; 01990 struct agent_pvt *p; 01991 struct ast_module_user *u; 01992 int login_state = 0; 01993 char user[AST_MAX_AGENT] = ""; 01994 char pass[AST_MAX_AGENT]; 01995 char agent[AST_MAX_AGENT] = ""; 01996 char xpass[AST_MAX_AGENT] = ""; 01997 char *errmsg; 01998 char *parse; 01999 AST_DECLARE_APP_ARGS(args, 02000 AST_APP_ARG(agent_id); 02001 AST_APP_ARG(options); 02002 AST_APP_ARG(extension); 02003 ); 02004 const char *tmpoptions = NULL; 02005 char *context = NULL; 02006 int play_announcement = 1; 02007 char agent_goodbye[AST_MAX_FILENAME_LEN]; 02008 int update_cdr = updatecdr; 02009 char *filename = "agent-loginok"; 02010 char tmpchan[AST_MAX_BUF] = ""; 02011 02012 u = ast_module_user_add(chan); 02013 02014 parse = ast_strdupa(data); 02015 02016 AST_STANDARD_APP_ARGS(args, parse); 02017 02018 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 02019 02020 ast_channel_lock(chan); 02021 /* Set Channel Specific Login Overrides */ 02022 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 02023 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 02024 if (max_login_tries < 0) 02025 max_login_tries = 0; 02026 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 02027 if (option_verbose > 2) 02028 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 02029 } 02030 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 02031 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 02032 update_cdr = 1; 02033 else 02034 update_cdr = 0; 02035 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 02036 if (option_verbose > 2) 02037 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 02038 } 02039 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 02040 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 02041 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 02042 if (option_verbose > 2) 02043 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 02044 } 02045 ast_channel_unlock(chan); 02046 /* End Channel Specific Login Overrides */ 02047 02048 if (callbackmode && args.extension) { 02049 parse = args.extension; 02050 args.extension = strsep(&parse, "@"); 02051 context = parse; 02052 } 02053 02054 if (!ast_strlen_zero(args.options)) { 02055 if (strchr(args.options, 's')) { 02056 play_announcement = 0; 02057 } 02058 } 02059 02060 if (chan->_state != AST_STATE_UP) 02061 res = ast_answer(chan); 02062 if (!res) { 02063 if (!ast_strlen_zero(args.agent_id)) 02064 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 02065 else 02066 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 02067 } 02068 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 02069 tries++; 02070 /* Check for password */ 02071 AST_LIST_LOCK(&agents); 02072 AST_LIST_TRAVERSE(&agents, p, list) { 02073 if (!strcmp(p->agent, user) && !p->pending) 02074 ast_copy_string(xpass, p->password, sizeof(xpass)); 02075 } 02076 AST_LIST_UNLOCK(&agents); 02077 if (!res) { 02078 if (!ast_strlen_zero(xpass)) 02079 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 02080 else 02081 pass[0] = '\0'; 02082 } 02083 errmsg = "agent-incorrect"; 02084 02085 #if 0 02086 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 02087 #endif 02088 02089 /* Check again for accuracy */ 02090 AST_LIST_LOCK(&agents); 02091 AST_LIST_TRAVERSE(&agents, p, list) { 02092 int unlock_channel = 1; 02093 ast_channel_lock(chan); 02094 ast_mutex_lock(&p->lock); 02095 if (!strcmp(p->agent, user) && 02096 !strcmp(p->password, pass) && !p->pending) { 02097 login_state = 1; /* Successful Login */ 02098 02099 /* Ensure we can't be gotten until we're done */ 02100 gettimeofday(&p->lastdisc, NULL); 02101 p->lastdisc.tv_sec++; 02102 02103 /* Set Channel Specific Agent Overrides */ 02104 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02105 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 02106 p->ackcall = 2; 02107 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 02108 p->ackcall = 1; 02109 else 02110 p->ackcall = 0; 02111 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02112 if (option_verbose > 2) 02113 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 02114 } else { 02115 p->ackcall = ackcall; 02116 } 02117 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02118 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02119 if (p->autologoff < 0) 02120 p->autologoff = 0; 02121 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02122 if (option_verbose > 2) 02123 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 02124 } else { 02125 p->autologoff = autologoff; 02126 } 02127 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02128 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02129 if (p->wrapuptime < 0) 02130 p->wrapuptime = 0; 02131 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02132 if (option_verbose > 2) 02133 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 02134 } else { 02135 p->wrapuptime = wrapuptime; 02136 } 02137 ast_channel_unlock(chan); 02138 unlock_channel = 0; 02139 /* End Channel Specific Agent Overrides */ 02140 if (!p->chan) { 02141 char last_loginchan[80] = ""; 02142 long logintime; 02143 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02144 02145 if (callbackmode) { 02146 int pos = 0; 02147 /* Retrieve login chan */ 02148 for (;;) { 02149 if (!ast_strlen_zero(args.extension)) { 02150 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 02151 res = 0; 02152 } else 02153 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 02154 if (ast_strlen_zero(tmpchan) ) 02155 break; 02156 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 02157 if(!allow_multiple_login(tmpchan,context) ) { 02158 args.extension = NULL; 02159 pos = 0; 02160 } else 02161 break; 02162 } 02163 if (args.extension) { 02164 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 02165 args.extension = NULL; 02166 pos = 0; 02167 } else { 02168 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 02169 res = ast_streamfile(chan, "invalid", chan->language); 02170 if (!res) 02171 res = ast_waitstream(chan, AST_DIGIT_ANY); 02172 if (res > 0) { 02173 tmpchan[0] = res; 02174 tmpchan[1] = '\0'; 02175 pos = 1; 02176 } else { 02177 tmpchan[0] = '\0'; 02178 pos = 0; 02179 } 02180 } 02181 } 02182 args.extension = tmpchan; 02183 if (!res) { 02184 set_agentbycallerid(p->logincallerid, NULL); 02185 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 02186 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 02187 else { 02188 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 02189 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 02190 } 02191 p->acknowledged = 0; 02192 if (ast_strlen_zero(p->loginchan)) { 02193 login_state = 2; 02194 filename = "agent-loggedoff"; 02195 } else { 02196 if (chan->cid.cid_num) { 02197 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 02198 set_agentbycallerid(p->logincallerid, p->agent); 02199 } else 02200 p->logincallerid[0] = '\0'; 02201 } 02202 02203 if(update_cdr && chan->cdr) 02204 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02205 02206 } 02207 } else { 02208 p->loginchan[0] = '\0'; 02209 p->logincallerid[0] = '\0'; 02210 p->acknowledged = 0; 02211 } 02212 ast_mutex_unlock(&p->lock); 02213 AST_LIST_UNLOCK(&agents); 02214 if( !res && play_announcement==1 ) 02215 res = ast_streamfile(chan, filename, chan->language); 02216 if (!res) 02217 ast_waitstream(chan, ""); 02218 AST_LIST_LOCK(&agents); 02219 ast_mutex_lock(&p->lock); 02220 if (!res) { 02221 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02222 if (res) 02223 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02224 } 02225 if (!res) { 02226 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02227 if (res) 02228 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02229 } 02230 /* Check once more just in case */ 02231 if (p->chan) 02232 res = -1; 02233 if (callbackmode && !res) { 02234 /* Just say goodbye and be done with it */ 02235 if (!ast_strlen_zero(p->loginchan)) { 02236 if (p->loginstart == 0) 02237 time(&p->loginstart); 02238 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02239 "Agent: %s\r\n" 02240 "Loginchan: %s\r\n" 02241 "Uniqueid: %s\r\n", 02242 p->agent, p->loginchan, chan->uniqueid); 02243 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02244 if (option_verbose > 1) 02245 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02246 ast_device_state_changed("Agent/%s", p->agent); 02247 if (persistent_agents) 02248 dump_agents(); 02249 } else { 02250 logintime = time(NULL) - p->loginstart; 02251 p->loginstart = 0; 02252 02253 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02254 if (option_verbose > 1) 02255 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02256 } 02257 AST_LIST_UNLOCK(&agents); 02258 if (!res) 02259 res = ast_safe_sleep(chan, 500); 02260 ast_mutex_unlock(&p->lock); 02261 } else if (!res) { 02262 ast_indicate_data(chan, AST_CONTROL_HOLD, 02263 S_OR(p->moh, NULL), 02264 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02265 if (p->loginstart == 0) 02266 time(&p->loginstart); 02267 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02268 "Agent: %s\r\n" 02269 "Channel: %s\r\n" 02270 "Uniqueid: %s\r\n", 02271 p->agent, chan->name, chan->uniqueid); 02272 if (update_cdr && chan->cdr) 02273 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02274 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02275 if (option_verbose > 1) 02276 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02277 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02278 /* Login this channel and wait for it to go away */ 02279 p->chan = chan; 02280 if (p->ackcall > 1) 02281 check_beep(p, 0); 02282 else 02283 check_availability(p, 0); 02284 ast_mutex_unlock(&p->lock); 02285 AST_LIST_UNLOCK(&agents); 02286 ast_device_state_changed("Agent/%s", p->agent); 02287 while (res >= 0) { 02288 ast_mutex_lock(&p->lock); 02289 if (p->deferlogoff && p->chan) { 02290 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02291 p->deferlogoff = 0; 02292 } 02293 if (p->chan != chan) 02294 res = -1; 02295 ast_mutex_unlock(&p->lock); 02296 /* Yield here so other interested threads can kick in. */ 02297 sched_yield(); 02298 if (res) 02299 break; 02300 02301 AST_LIST_LOCK(&agents); 02302 ast_mutex_lock(&p->lock); 02303 if (p->lastdisc.tv_sec) { 02304 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02305 if (option_debug) 02306 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02307 p->lastdisc = ast_tv(0, 0); 02308 ast_device_state_changed("Agent/%s", p->agent); 02309 if (p->ackcall > 1) 02310 check_beep(p, 0); 02311 else 02312 check_availability(p, 0); 02313 } 02314 } 02315 ast_mutex_unlock(&p->lock); 02316 AST_LIST_UNLOCK(&agents); 02317 02318 /* Synchronize channel ownership between call to agent and itself. */ 02319 ast_mutex_lock(&p->lock); 02320 if (p->app_lock_flag == 1) { 02321 ast_cond_signal(&p->login_wait_cond); 02322 ast_cond_wait(&p->app_complete_cond, &p->lock); 02323 } 02324 ast_mutex_unlock(&p->lock); 02325 02326 if (p->ackcall > 1) 02327 res = agent_ack_sleep(p); 02328 else 02329 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02330 if ((p->ackcall > 1) && (res == 1)) { 02331 AST_LIST_LOCK(&agents); 02332 ast_mutex_lock(&p->lock); 02333 check_availability(p, 0); 02334 ast_mutex_unlock(&p->lock); 02335 AST_LIST_UNLOCK(&agents); 02336 res = 0; 02337 } 02338 sched_yield(); 02339 } 02340 ast_mutex_lock(&p->lock); 02341 /* Log us off if appropriate */ 02342 if (p->chan == chan) { 02343 p->chan = NULL; 02344 p->inherited_devicestate = -1; 02345 } 02346 02347 /* Synchronize channel ownership between call to agent and itself. */ 02348 if (p->app_lock_flag == 1) { 02349 ast_cond_signal(&p->login_wait_cond); 02350 ast_cond_wait(&p->app_complete_cond, &p->lock); 02351 } 02352 02353 if (res && p->owner) 02354 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02355 02356 p->acknowledged = 0; 02357 logintime = time(NULL) - p->loginstart; 02358 p->loginstart = 0; 02359 ast_mutex_unlock(&p->lock); 02360 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02361 "Agent: %s\r\n" 02362 "Logintime: %ld\r\n" 02363 "Uniqueid: %s\r\n", 02364 p->agent, logintime, chan->uniqueid); 02365 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02366 if (option_verbose > 1) 02367 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02368 /* If there is no owner, go ahead and kill it now */ 02369 ast_device_state_changed("Agent/%s", p->agent); 02370 if (p->dead && !p->owner) { 02371 ast_mutex_destroy(&p->lock); 02372 ast_cond_destroy(&p->app_complete_cond); 02373 ast_cond_destroy(&p->login_wait_cond); 02374 free(p); 02375 } 02376 } 02377 else { 02378 ast_mutex_unlock(&p->lock); 02379 p = NULL; 02380 } 02381 res = -1; 02382 } else { 02383 ast_mutex_unlock(&p->lock); 02384 errmsg = "agent-alreadyon"; 02385 p = NULL; 02386 } 02387 break; 02388 } 02389 ast_mutex_unlock(&p->lock); 02390 if (unlock_channel) { 02391 ast_channel_unlock(chan); 02392 } 02393 } 02394 if (!p) 02395 AST_LIST_UNLOCK(&agents); 02396 02397 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02398 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02399 } 02400 02401 if (!res) 02402 res = ast_safe_sleep(chan, 500); 02403 02404 /* AgentLogin() exit */ 02405 if (!callbackmode) { 02406 ast_module_user_remove(u); 02407 return -1; 02408 } else { /* AgentCallbackLogin() exit*/ 02409 /* Set variables */ 02410 if (login_state > 0) { 02411 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user); 02412 if (login_state==1) { 02413 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on"); 02414 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension); 02415 } else 02416 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off"); 02417 } else { 02418 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail"); 02419 } 02420 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) { 02421 ast_module_user_remove(u); 02422 return 0; 02423 } 02424 /* Do we need to play agent-goodbye now that we will be hanging up? */ 02425 if (play_announcement) { 02426 if (!res) 02427 res = ast_safe_sleep(chan, 1000); 02428 res = ast_streamfile(chan, agent_goodbye, chan->language); 02429 if (!res) 02430 res = ast_waitstream(chan, ""); 02431 if (!res) 02432 res = ast_safe_sleep(chan, 1000); 02433 } 02434 } 02435 02436 ast_module_user_remove(u); 02437 02438 /* We should never get here if next priority exists when in callbackmode */ 02439 return -1; 02440 }
static void __reg_module | ( | void | ) | [static] |
Definition at line 2938 of file chan_agent.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 2938 of file chan_agent.c.
static int action_agent_callback_login | ( | struct mansession * | s, | |
const struct message * | m | |||
) | [static] |
Sets an agent as logged in by callback in the Manager API. It is registered on load_module() and it gets called by the manager backend.
s | ||
m |
Definition at line 2491 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, ast_copy_string(), ast_device_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_verbose(), astman_get_header(), astman_send_ack(), astman_send_error(), callback_deprecated(), agent_pvt::chan, context, dump_agents(), EVENT_FLAG_AGENT, exten, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), option_verbose, agent_pvt::pending, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.
Referenced by load_module().
02492 { 02493 const char *agent = astman_get_header(m, "Agent"); 02494 const char *exten = astman_get_header(m, "Exten"); 02495 const char *context = astman_get_header(m, "Context"); 02496 const char *wrapuptime_s = astman_get_header(m, "WrapupTime"); 02497 const char *ackcall_s = astman_get_header(m, "AckCall"); 02498 struct agent_pvt *p; 02499 int login_state = 0; 02500 02501 callback_deprecated(); 02502 02503 if (ast_strlen_zero(agent)) { 02504 astman_send_error(s, m, "No agent specified"); 02505 return 0; 02506 } 02507 02508 if (ast_strlen_zero(exten)) { 02509 astman_send_error(s, m, "No extension specified"); 02510 return 0; 02511 } 02512 02513 AST_LIST_LOCK(&agents); 02514 AST_LIST_TRAVERSE(&agents, p, list) { 02515 if (strcmp(p->agent, agent) || p->pending) 02516 continue; 02517 if (p->chan) { 02518 login_state = 2; /* already logged in (and on the phone)*/ 02519 break; 02520 } 02521 ast_mutex_lock(&p->lock); 02522 login_state = 1; /* Successful Login */ 02523 02524 if (ast_strlen_zero(context)) 02525 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan)); 02526 else 02527 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context); 02528 02529 if (!ast_strlen_zero(wrapuptime_s)) { 02530 p->wrapuptime = atoi(wrapuptime_s); 02531 if (p->wrapuptime < 0) 02532 p->wrapuptime = 0; 02533 } 02534 02535 if (!strcasecmp(ackcall_s, "always")) 02536 p->ackcall = 2; 02537 else if (ast_true(ackcall_s)) 02538 p->ackcall = 1; 02539 else 02540 p->ackcall = 0; 02541 02542 if (p->loginstart == 0) 02543 time(&p->loginstart); 02544 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02545 "Agent: %s\r\n" 02546 "Loginchan: %s\r\n", 02547 p->agent, p->loginchan); 02548 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02549 if (option_verbose > 1) 02550 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02551 ast_device_state_changed("Agent/%s", p->agent); 02552 ast_mutex_unlock(&p->lock); 02553 if (persistent_agents) 02554 dump_agents(); 02555 } 02556 AST_LIST_UNLOCK(&agents); 02557 02558 if (login_state == 1) 02559 astman_send_ack(s, m, "Agent logged in"); 02560 else if (login_state == 0) 02561 astman_send_error(s, m, "No such agent"); 02562 else if (login_state == 2) 02563 astman_send_error(s, m, "Agent already logged in"); 02564 02565 return 0; 02566 }
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 1772 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
01773 { 01774 const char *agent = astman_get_header(m, "Agent"); 01775 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01776 int soft; 01777 int ret; /* return value of agent_logoff */ 01778 01779 if (ast_strlen_zero(agent)) { 01780 astman_send_error(s, m, "No agent specified"); 01781 return 0; 01782 } 01783 01784 soft = ast_true(soft_s) ? 1 : 0; 01785 ret = agent_logoff(agent, soft); 01786 if (ret == 0) 01787 astman_send_ack(s, m, "Agent logged out"); 01788 else 01789 astman_send_error(s, m, "No such agent"); 01790 01791 return 0; 01792 }
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 1585 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::lock, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, agent_pvt::owner, S_OR, and username.
Referenced by load_module().
01586 { 01587 const char *id = astman_get_header(m,"ActionID"); 01588 char idText[256] = ""; 01589 char chanbuf[256]; 01590 struct agent_pvt *p; 01591 char *username = NULL; 01592 char *loginChan = NULL; 01593 char *talkingtoChan = NULL; 01594 char *status = NULL; 01595 01596 if (!ast_strlen_zero(id)) 01597 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01598 astman_send_ack(s, m, "Agents will follow"); 01599 AST_LIST_LOCK(&agents); 01600 AST_LIST_TRAVERSE(&agents, p, list) { 01601 ast_mutex_lock(&p->lock); 01602 01603 /* Status Values: 01604 AGENT_LOGGEDOFF - Agent isn't logged in 01605 AGENT_IDLE - Agent is logged in, and waiting for call 01606 AGENT_ONCALL - Agent is logged in, and on a call 01607 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01608 01609 username = S_OR(p->name, "None"); 01610 01611 /* Set a default status. It 'should' get changed. */ 01612 status = "AGENT_UNKNOWN"; 01613 01614 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01615 loginChan = p->loginchan; 01616 talkingtoChan = "n/a"; 01617 status = "AGENT_IDLE"; 01618 if (p->acknowledged) { 01619 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01620 loginChan = chanbuf; 01621 } 01622 } else if (p->chan) { 01623 loginChan = ast_strdupa(p->chan->name); 01624 if (p->owner && p->owner->_bridge) { 01625 if (ast_bridged_channel(p->owner)) { 01626 talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, "")); 01627 } else { 01628 talkingtoChan = "n/a"; 01629 } 01630 status = "AGENT_ONCALL"; 01631 } else { 01632 talkingtoChan = "n/a"; 01633 status = "AGENT_IDLE"; 01634 } 01635 } else { 01636 loginChan = "n/a"; 01637 talkingtoChan = "n/a"; 01638 status = "AGENT_LOGGEDOFF"; 01639 } 01640 01641 astman_append(s, "Event: Agents\r\n" 01642 "Agent: %s\r\n" 01643 "Name: %s\r\n" 01644 "Status: %s\r\n" 01645 "LoggedInChan: %s\r\n" 01646 "LoggedInTime: %d\r\n" 01647 "TalkingTo: %s\r\n" 01648 "%s" 01649 "\r\n", 01650 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); 01651 ast_mutex_unlock(&p->lock); 01652 } 01653 AST_LIST_UNLOCK(&agents); 01654 astman_append(s, "Event: AgentsComplete\r\n" 01655 "%s" 01656 "\r\n",idText); 01657 return 0; 01658 }
static struct agent_pvt* add_agent | ( | char * | agent, | |
int | pending | |||
) | [static, read] |
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 338 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, 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_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::group, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00339 { 00340 char *parse; 00341 AST_DECLARE_APP_ARGS(args, 00342 AST_APP_ARG(agt); 00343 AST_APP_ARG(password); 00344 AST_APP_ARG(name); 00345 ); 00346 char *password = NULL; 00347 char *name = NULL; 00348 char *agt = NULL; 00349 struct agent_pvt *p; 00350 00351 parse = ast_strdupa(agent); 00352 00353 /* Extract username (agt), password and name from agent (args). */ 00354 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 00355 00356 if(args.argc == 0) { 00357 ast_log(LOG_WARNING, "A blank agent line!\n"); 00358 return NULL; 00359 } 00360 00361 if(ast_strlen_zero(args.agt) ) { 00362 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00363 return NULL; 00364 } else 00365 agt = args.agt; 00366 00367 if(!ast_strlen_zero(args.password)) { 00368 password = args.password; 00369 while (*password && *password < 33) password++; 00370 } 00371 if(!ast_strlen_zero(args.name)) { 00372 name = args.name; 00373 while (*name && *name < 33) name++; 00374 } 00375 00376 /* Are we searching for the agent here ? To see if it exists already ? */ 00377 AST_LIST_TRAVERSE(&agents, p, list) { 00378 if (!pending && !strcmp(p->agent, agt)) 00379 break; 00380 } 00381 if (!p) { 00382 // Build the agent. 00383 if (!(p = ast_calloc(1, sizeof(*p)))) 00384 return NULL; 00385 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00386 ast_mutex_init(&p->lock); 00387 ast_cond_init(&p->app_complete_cond, NULL); 00388 ast_cond_init(&p->login_wait_cond, NULL); 00389 p->app_lock_flag = 0; 00390 p->app_sleep_cond = 1; 00391 memcpy(&p->group, group, sizeof(p->group)); 00392 p->pending = pending; 00393 p->inherited_devicestate = -1; 00394 AST_LIST_INSERT_TAIL(&agents, p, list); 00395 } 00396 00397 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00398 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00399 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00400 p->ackcall = ackcall; 00401 p->autologoff = autologoff; 00402 00403 /* If someone reduces the wrapuptime and reloads, we want it 00404 * to change the wrapuptime immediately on all calls */ 00405 if (p->wrapuptime > wrapuptime) { 00406 struct timeval now = ast_tvnow(); 00407 /* XXX check what is this exactly */ 00408 00409 /* We won't be pedantic and check the tv_usec val */ 00410 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00411 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00412 p->lastdisc.tv_usec = now.tv_usec; 00413 } 00414 } 00415 p->wrapuptime = wrapuptime; 00416 00417 if (pending) 00418 p->dead = 1; 00419 else 00420 p->dead = 0; 00421 return p; 00422 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 1037 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, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.
Referenced by __login_exec().
01038 { 01039 struct agent_pvt *p; 01040 int res=0; 01041 int to = 1000; 01042 struct ast_frame *f; 01043 01044 /* Wait a second and look for something */ 01045 01046 p = (struct agent_pvt *) data; 01047 if (!p->chan) 01048 return -1; 01049 01050 for(;;) { 01051 to = ast_waitfor(p->chan, to); 01052 if (to < 0) 01053 return -1; 01054 if (!to) 01055 return 0; 01056 f = ast_read(p->chan); 01057 if (!f) 01058 return -1; 01059 if (f->frametype == AST_FRAME_DTMF) 01060 res = f->subclass; 01061 else 01062 res = 0; 01063 ast_frfree(f); 01064 ast_mutex_lock(&p->lock); 01065 if (!p->app_sleep_cond) { 01066 ast_mutex_unlock(&p->lock); 01067 return 0; 01068 } else if (res == '#') { 01069 ast_mutex_unlock(&p->lock); 01070 return 1; 01071 } 01072 ast_mutex_unlock(&p->lock); 01073 res = 0; 01074 } 01075 return res; 01076 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 457 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00458 { 00459 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00460 return -1; 00461 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static, read] |
Definition at line 1078 of file chan_agent.c.
References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.
01079 { 01080 struct agent_pvt *p = bridge->tech_pvt; 01081 struct ast_channel *ret = NULL; 01082 01083 if (p) { 01084 if (chan == p->chan) 01085 ret = bridge->_bridge; 01086 else if (chan == bridge->_bridge) 01087 ret = p->chan; 01088 } 01089 01090 if (option_debug) 01091 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 01092 return ret; 01093 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 754 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_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_verbose(), ast_waitstream(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLEANUP, agent_pvt::inherited_devicestate, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::loginchan, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::pending, agent_pvt::start, ast_channel::tech_pvt, and VERBOSE_PREFIX_3.
00755 { 00756 struct agent_pvt *p = ast->tech_pvt; 00757 int res = -1; 00758 int newstate=0; 00759 struct ast_channel *chan; 00760 00761 ast_mutex_lock(&p->lock); 00762 p->acknowledged = 0; 00763 00764 if (p->pending) { 00765 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00766 ast_mutex_unlock(&p->lock); 00767 ast_setstate(ast, AST_STATE_DIALING); 00768 return 0; 00769 } 00770 00771 if (!p->chan) { 00772 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 00773 ast_mutex_unlock(&p->lock); 00774 return res; 00775 } 00776 00777 if (!ast_strlen_zero(p->loginchan)) { 00778 time(&p->start); 00779 /* Call on this agent */ 00780 if (option_verbose > 2) 00781 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00782 ast_set_callerid(p->chan, 00783 ast->cid.cid_num, ast->cid.cid_name, NULL); 00784 ast_channel_inherit_variables(ast, p->chan); 00785 res = ast_call(p->chan, p->loginchan, 0); 00786 CLEANUP(ast,p); 00787 ast_mutex_unlock(&p->lock); 00788 return res; 00789 } 00790 if (option_verbose > 2) 00791 ast_verbose(VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00792 if (option_debug > 2) 00793 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language); 00794 00795 chan = p->chan; 00796 ast_mutex_unlock(&p->lock); 00797 00798 res = ast_streamfile(chan, beep, chan->language); 00799 if (option_debug > 2) 00800 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 00801 if (!res) { 00802 res = ast_waitstream(chan, ""); 00803 if (option_debug > 2) 00804 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 00805 } 00806 00807 ast_mutex_lock(&p->lock); 00808 if (!p->chan) { 00809 /* chan went away while we were streaming, this shouldn't be possible */ 00810 res = -1; 00811 } 00812 00813 if (!res) { 00814 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00815 if (option_debug > 2) 00816 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res); 00817 if (res) 00818 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00819 } else { 00820 /* Agent hung-up */ 00821 p->chan = NULL; 00822 p->inherited_devicestate = -1; 00823 ast_device_state_changed("Agent/%s", p->agent); 00824 } 00825 00826 if (!res) { 00827 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00828 if (option_debug > 2) 00829 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res); 00830 if (res) 00831 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00832 } 00833 if(!res) { 00834 /* Call is immediately up, or might need ack */ 00835 if (p->ackcall > 1) 00836 newstate = AST_STATE_RINGING; 00837 else { 00838 newstate = AST_STATE_UP; 00839 if (recordagentcalls) 00840 agent_start_monitoring(ast, 0); 00841 p->acknowledged = 1; 00842 } 00843 res = 0; 00844 } 00845 CLEANUP(ast, p); 00846 ast_mutex_unlock(&p->lock); 00847 if (newstate) 00848 ast_setstate(ast, newstate); 00849 return res; 00850 }
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 430 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_free(), ast_cond_destroy(), ast_cond_signal(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, agent_pvt::login_wait_cond, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00431 { 00432 struct ast_channel *chan = NULL; 00433 ast_mutex_lock(&p->lock); 00434 chan = p->owner; 00435 p->owner = NULL; 00436 chan->tech_pvt = NULL; 00437 /* Release ownership of the agent to other threads (presumably running the login app). */ 00438 p->app_sleep_cond = 1; 00439 p->app_lock_flag = 0; 00440 ast_cond_signal(&p->app_complete_cond); 00441 if (chan) 00442 ast_channel_free(chan); 00443 if (p->dead) { 00444 ast_mutex_unlock(&p->lock); 00445 ast_mutex_destroy(&p->lock); 00446 ast_cond_destroy(&p->app_complete_cond); 00447 ast_cond_destroy(&p->login_wait_cond); 00448 free(p); 00449 } else { 00450 ast_mutex_unlock(&p->lock); 00451 } 00452 return 0; 00453 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 1016 of file chan_agent.c.
References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, and option_debug.
Referenced by __login_exec().
01017 { 01018 struct agent_pvt *p; 01019 int res; 01020 01021 p = (struct agent_pvt *)data; 01022 01023 ast_mutex_lock(&p->lock); 01024 res = p->app_sleep_cond; 01025 if (p->lastdisc.tv_sec) { 01026 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 01027 res = 1; 01028 } 01029 ast_mutex_unlock(&p->lock); 01030 01031 if(option_debug > 4 && !res ) 01032 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res ); 01033 01034 return res; 01035 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2712 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_get_group(), ast_have_common_group(), ast_is_empty_group(), 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::inherited_devicestate, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
02713 { 02714 struct agent_pvt *p; 02715 char *s; 02716 ast_group_t groupmatch; 02717 int groupoff; 02718 int waitforagent=0; 02719 int res = AST_DEVICE_INVALID; 02720 02721 s = data; 02722 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02723 char tmp[12]; 02724 sprintf(tmp, "%d", groupoff); 02725 ast_get_group(&groupmatch, tmp); 02726 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02727 char tmp[12]; 02728 sprintf(tmp, "%d", groupoff); 02729 ast_get_group(&groupmatch, tmp); 02730 waitforagent = 1; 02731 } else { 02732 memset(&groupmatch, 0, sizeof(groupmatch)); 02733 } 02734 02735 /* Check actual logged in agents first */ 02736 AST_LIST_LOCK(&agents); 02737 AST_LIST_TRAVERSE(&agents, p, list) { 02738 ast_mutex_lock(&p->lock); 02739 if (!p->pending && ((!ast_is_empty_group(&groupmatch) && ast_have_common_group(&p->group, &groupmatch)) || !strcmp(data, p->agent))) { 02740 if (p->owner) { 02741 if (res != AST_DEVICE_INUSE) 02742 res = AST_DEVICE_BUSY; 02743 } else if (p->inherited_devicestate > -1) { 02744 res = p->inherited_devicestate; 02745 } else { 02746 if (res == AST_DEVICE_BUSY) 02747 res = AST_DEVICE_INUSE; 02748 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02749 if (res == AST_DEVICE_INVALID) 02750 res = AST_DEVICE_UNKNOWN; 02751 } else if (res == AST_DEVICE_INVALID) 02752 res = AST_DEVICE_UNAVAILABLE; 02753 } 02754 if (!strcmp(data, p->agent)) { 02755 ast_mutex_unlock(&p->lock); 02756 break; 02757 } 02758 } 02759 ast_mutex_unlock(&p->lock); 02760 } 02761 AST_LIST_UNLOCK(&agents); 02762 return res; 02763 }
static int agent_devicestate_cb | ( | const char * | dev, | |
int | state, | |||
void * | data | |||
) | [static] |
Definition at line 291 of file chan_agent.c.
References agent_pvt::agent, AST_CHANNEL_NAME, ast_copy_string(), ast_device_state_changed(), AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::inherited_devicestate, agent_pvt::lock, and agent_pvt::loginchan.
Referenced by load_module(), and unload_module().
00292 { 00293 int res, i; 00294 struct agent_pvt *p; 00295 char basename[AST_CHANNEL_NAME], *tmp; 00296 00297 /* Skip Agent status */ 00298 if (!strncasecmp(dev, "Agent/", 6)) { 00299 return 0; 00300 } 00301 00302 /* Try to be safe, but don't deadlock */ 00303 for (i = 0; i < 10; i++) { 00304 if ((res = AST_LIST_TRYLOCK(&agents)) == 0) { 00305 break; 00306 } 00307 } 00308 if (res) { 00309 return -1; 00310 } 00311 00312 AST_LIST_TRAVERSE(&agents, p, list) { 00313 ast_mutex_lock(&p->lock); 00314 if (p->chan && !ast_strlen_zero(p->loginchan)) { 00315 ast_copy_string(basename, p->chan->name, sizeof(basename)); 00316 if ((tmp = strrchr(basename, '-'))) { 00317 *tmp = '\0'; 00318 } 00319 if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) { 00320 p->inherited_devicestate = state; 00321 ast_device_state_changed("Agent/%s", p->agent); 00322 } 00323 } 00324 ast_mutex_unlock(&p->lock); 00325 } 00326 AST_LIST_UNLOCK(&agents); 00327 return 0; 00328 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 732 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.
00733 { 00734 struct agent_pvt *p = ast->tech_pvt; 00735 ast_mutex_lock(&p->lock); 00736 if (p->chan) { 00737 ast_senddigit_begin(p->chan, digit); 00738 } 00739 ast_mutex_unlock(&p->lock); 00740 return 0; 00741 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 743 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.
00744 { 00745 struct agent_pvt *p = ast->tech_pvt; 00746 ast_mutex_lock(&p->lock); 00747 if (p->chan) { 00748 ast_senddigit_end(p->chan, digit, duration); 00749 } 00750 ast_mutex_unlock(&p->lock); 00751 return 0; 00752 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 694 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.
00695 { 00696 struct agent_pvt *p = newchan->tech_pvt; 00697 ast_mutex_lock(&p->lock); 00698 if (p->owner != oldchan) { 00699 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00700 ast_mutex_unlock(&p->lock); 00701 return -1; 00702 } 00703 p->owner = newchan; 00704 ast_mutex_unlock(&p->lock); 00705 return 0; 00706 }
struct ast_channel * agent_get_base_channel | ( | struct ast_channel * | chan | ) | [static, read] |
return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
Definition at line 866 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00867 { 00868 struct agent_pvt *p = NULL; 00869 struct ast_channel *base = chan; 00870 00871 /* chan is locked by the calling function */ 00872 if (!chan || !chan->tech_pvt) { 00873 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); 00874 return NULL; 00875 } 00876 p = chan->tech_pvt; 00877 if (p->chan) 00878 base = p->chan; 00879 return base; 00880 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 899 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_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), AST_CONTROL_HOLD, ast_device_state_changed(), 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(), free, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::login_wait_cond, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, option_debug, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.
Referenced by agent_request().
00900 { 00901 struct agent_pvt *p = ast->tech_pvt; 00902 int howlong = 0; 00903 const char *status; 00904 ast_mutex_lock(&p->lock); 00905 p->owner = NULL; 00906 ast->tech_pvt = NULL; 00907 p->app_sleep_cond = 1; 00908 p->acknowledged = 0; 00909 00910 /* Release ownership of the agent to other threads (presumably running the login app). */ 00911 if (ast_strlen_zero(p->loginchan)) { 00912 p->app_lock_flag = 0; 00913 ast_cond_signal(&p->app_complete_cond); 00914 } 00915 00916 /* if they really are hung up then set start to 0 so the test 00917 * later if we're called on an already downed channel 00918 * doesn't cause an agent to be logged out like when 00919 * agent_request() is followed immediately by agent_hangup() 00920 * as in apps/app_chanisavail.c:chanavail_exec() 00921 */ 00922 00923 if (option_debug) 00924 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00925 if (p->start && (ast->_state != AST_STATE_UP)) { 00926 howlong = time(NULL) - p->start; 00927 p->start = 0; 00928 } else if (ast->_state == AST_STATE_RESERVED) 00929 howlong = 0; 00930 else 00931 p->start = 0; 00932 if (p->chan) { 00933 p->chan->_bridge = NULL; 00934 /* If they're dead, go ahead and hang up on the agent now */ 00935 if (!ast_strlen_zero(p->loginchan)) { 00936 /* Store last disconnect time */ 00937 if (p->wrapuptime) 00938 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00939 else 00940 p->lastdisc = ast_tv(0,0); 00941 if (p->chan) { 00942 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00943 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00944 long logintime = time(NULL) - p->loginstart; 00945 p->loginstart = 0; 00946 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00947 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00948 } 00949 /* Recognize the hangup and pass it along immediately */ 00950 ast_hangup(p->chan); 00951 p->chan = NULL; 00952 p->inherited_devicestate = -1; 00953 ast_device_state_changed("Agent/%s", p->agent); 00954 } 00955 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00956 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00957 long logintime = time(NULL) - p->loginstart; 00958 p->loginstart = 0; 00959 if (!p->deferlogoff) 00960 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00961 p->deferlogoff = 0; 00962 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00963 if (persistent_agents) 00964 dump_agents(); 00965 } 00966 } else if (p->dead) { 00967 ast_channel_lock(p->chan); 00968 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00969 ast_channel_unlock(p->chan); 00970 } else if (p->loginstart) { 00971 ast_channel_lock(p->chan); 00972 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00973 S_OR(p->moh, NULL), 00974 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00975 ast_channel_unlock(p->chan); 00976 } 00977 } 00978 ast_mutex_unlock(&p->lock); 00979 00980 /* Only register a device state change if the agent is still logged in */ 00981 if (!p->loginstart) { 00982 p->loginchan[0] = '\0'; 00983 p->logincallerid[0] = '\0'; 00984 if (persistent_agents) 00985 dump_agents(); 00986 } else { 00987 ast_device_state_changed("Agent/%s", p->agent); 00988 } 00989 00990 if (p->pending) { 00991 AST_LIST_LOCK(&agents); 00992 AST_LIST_REMOVE(&agents, p, list); 00993 AST_LIST_UNLOCK(&agents); 00994 } 00995 if (p->abouttograb) { 00996 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00997 kill it later */ 00998 p->abouttograb = 0; 00999 } else if (p->dead) { 01000 ast_mutex_destroy(&p->lock); 01001 ast_cond_destroy(&p->app_complete_cond); 01002 ast_cond_destroy(&p->login_wait_cond); 01003 free(p); 01004 } else { 01005 if (p->chan) { 01006 /* Not dead -- check availability now */ 01007 ast_mutex_lock(&p->lock); 01008 /* Store last disconnect time */ 01009 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 01010 ast_mutex_unlock(&p->lock); 01011 } 01012 } 01013 return 0; 01014 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 708 of file chan_agent.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, LOG_ERROR, ast_channel::tech, and ast_channel::tech_pvt.
00709 { 00710 struct agent_pvt *p = ast->tech_pvt; 00711 int res = -1; 00712 ast_mutex_lock(&p->lock); 00713 if (p->chan && !ast_check_hangup(p->chan)) { 00714 while (ast_channel_trylock(p->chan)) { 00715 int res; 00716 if ((res = ast_channel_unlock(ast))) { 00717 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res)); 00718 ast_mutex_unlock(&p->lock); 00719 return -1; 00720 } 00721 usleep(1); 00722 ast_channel_lock(ast); 00723 } 00724 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00725 ast_channel_unlock(p->chan); 00726 } else 00727 res = 0; 00728 ast_mutex_unlock(&p->lock); 00729 return res; 00730 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1700 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::lock, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.
Referenced by action_agent_logoff(), and agent_logoff_cmd().
01701 { 01702 struct agent_pvt *p; 01703 long logintime; 01704 int ret = -1; /* Return -1 if no agent if found */ 01705 01706 AST_LIST_LOCK(&agents); 01707 AST_LIST_TRAVERSE(&agents, p, list) { 01708 if (!strcasecmp(p->agent, agent)) { 01709 ret = 0; 01710 if (p->owner || p->chan) { 01711 if (!soft) { 01712 ast_mutex_lock(&p->lock); 01713 01714 while (p->owner && ast_channel_trylock(p->owner)) { 01715 DEADLOCK_AVOIDANCE(&p->lock); 01716 } 01717 if (p->owner) { 01718 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01719 ast_channel_unlock(p->owner); 01720 } 01721 01722 while (p->chan && ast_channel_trylock(p->chan)) { 01723 DEADLOCK_AVOIDANCE(&p->lock); 01724 } 01725 if (p->chan) { 01726 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01727 ast_channel_unlock(p->chan); 01728 } 01729 01730 ast_mutex_unlock(&p->lock); 01731 } else 01732 p->deferlogoff = 1; 01733 } else { 01734 logintime = time(NULL) - p->loginstart; 01735 p->loginstart = 0; 01736 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01737 } 01738 break; 01739 } 01740 } 01741 AST_LIST_UNLOCK(&agents); 01742 01743 return ret; 01744 }
static int agent_logoff_cmd | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1746 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01747 { 01748 int ret; 01749 char *agent; 01750 01751 if (argc < 3 || argc > 4) 01752 return RESULT_SHOWUSAGE; 01753 if (argc == 4 && strcasecmp(argv[3], "soft")) 01754 return RESULT_SHOWUSAGE; 01755 01756 agent = argv[2] + 6; 01757 ret = agent_logoff(agent, argc == 4); 01758 if (ret == 0) 01759 ast_cli(fd, "Logging out %s\n", agent); 01760 01761 return RESULT_SUCCESS; 01762 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1660 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::inherited_devicestate, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event(), and set_agentbycallerid().
Referenced by __login_exec(), agent_hangup(), agent_logoff(), and agent_read().
01661 { 01662 char *tmp = NULL; 01663 char agent[AST_MAX_AGENT]; 01664 01665 if (!ast_strlen_zero(logcommand)) 01666 tmp = logcommand; 01667 else 01668 tmp = ast_strdupa(""); 01669 01670 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01671 01672 if (!ast_strlen_zero(uniqueid)) { 01673 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01674 "Agent: %s\r\n" 01675 "Reason: %s\r\n" 01676 "Loginchan: %s\r\n" 01677 "Logintime: %ld\r\n" 01678 "Uniqueid: %s\r\n", 01679 p->agent, tmp, loginchan, logintime, uniqueid); 01680 } else { 01681 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01682 "Agent: %s\r\n" 01683 "Reason: %s\r\n" 01684 "Loginchan: %s\r\n" 01685 "Logintime: %ld\r\n", 01686 p->agent, tmp, loginchan, logintime); 01687 } 01688 01689 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01690 set_agentbycallerid(p->logincallerid, NULL); 01691 p->loginchan[0] ='\0'; 01692 p->logincallerid[0] = '\0'; 01693 p->inherited_devicestate = -1; 01694 ast_device_state_changed("Agent/%s", p->agent); 01695 if (persistent_agents) 01696 dump_agents(); 01697 01698 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static, read] |
Create new agent channel.
Definition at line 1096 of file chan_agent.c.
References agent_pvt::agent, agent_tech, ast_atomic_fetchadd_int(), ast_channel_alloc(), ast_copy_string(), AST_FORMAT_SLINEAR, ast_log(), ast_random(), ast_string_field_set, ast_update_use_count(), agent_pvt::chan, ast_channel::context, ast_channel::exten, language, LOG_WARNING, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.
Referenced by agent_request(), and check_availability().
01097 { 01098 struct ast_channel *tmp; 01099 #if 0 01100 if (!p->chan) { 01101 ast_log(LOG_WARNING, "No channel? :(\n"); 01102 return NULL; 01103 } 01104 #endif 01105 if (p->pending) 01106 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); 01107 else 01108 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 01109 if (!tmp) { 01110 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01111 return NULL; 01112 } 01113 01114 tmp->tech = &agent_tech; 01115 if (p->chan) { 01116 tmp->nativeformats = p->chan->nativeformats; 01117 tmp->writeformat = p->chan->writeformat; 01118 tmp->rawwriteformat = p->chan->writeformat; 01119 tmp->readformat = p->chan->readformat; 01120 tmp->rawreadformat = p->chan->readformat; 01121 ast_string_field_set(tmp, language, p->chan->language); 01122 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01123 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01124 /* XXX Is this really all we copy form the originating channel?? */ 01125 } else { 01126 tmp->nativeformats = AST_FORMAT_SLINEAR; 01127 tmp->writeformat = AST_FORMAT_SLINEAR; 01128 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01129 tmp->readformat = AST_FORMAT_SLINEAR; 01130 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01131 } 01132 /* Safe, agentlock already held */ 01133 tmp->tech_pvt = p; 01134 p->owner = tmp; 01135 /* XXX: this needs fixing */ 01136 #if 0 01137 ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1); 01138 #endif 01139 ast_update_use_count(); 01140 tmp->priority = 1; 01141 return tmp; 01142 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 496 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_ANSWER, ast_copy_flags, ast_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_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verbose(), agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, f, ast_channel::fdno, ast_frame::frametype, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_verbose, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
00497 { 00498 struct agent_pvt *p = ast->tech_pvt; 00499 struct ast_frame *f = NULL; 00500 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00501 const char *status; 00502 int cur_time = time(NULL); 00503 ast_mutex_lock(&p->lock); 00504 CHECK_FORMATS(ast, p); 00505 if (!p->start) { 00506 p->start = cur_time; 00507 } 00508 if (p->chan) { 00509 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00510 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00511 f = ast_read(p->chan); 00512 } else 00513 f = &ast_null_frame; 00514 if (!f) { 00515 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00516 if (p->chan) { 00517 p->chan->_bridge = NULL; 00518 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00519 for us when the PBX instance that called login finishes */ 00520 if (!ast_strlen_zero(p->loginchan)) { 00521 if (p->chan) 00522 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00523 if (p->owner->_state != AST_STATE_UP) { 00524 int howlong = cur_time - p->start; 00525 if (p->autologoff && howlong >= p->autologoff) { 00526 p->loginstart = 0; 00527 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00528 agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff"); 00529 } 00530 } 00531 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00532 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00533 long logintime = cur_time - p->loginstart; 00534 p->loginstart = 0; 00535 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00536 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00537 } 00538 ast_hangup(p->chan); 00539 if (p->wrapuptime && p->acknowledged) 00540 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00541 } 00542 p->chan = NULL; 00543 p->inherited_devicestate = -1; 00544 ast_device_state_changed("Agent/%s", p->agent); 00545 p->acknowledged = 0; 00546 } 00547 } else { 00548 /* if acknowledgement is not required, and the channel is up, we may have missed 00549 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00550 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00551 p->acknowledged = 1; 00552 } 00553 if (!p->acknowledged) { 00554 int howlong = cur_time - p->start; 00555 if (p->autologoff && (howlong >= p->autologoff)) { 00556 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00557 agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff"); 00558 if (p->owner || p->chan) { 00559 while (p->owner && ast_channel_trylock(p->owner)) { 00560 DEADLOCK_AVOIDANCE(&p->lock); 00561 } 00562 if (p->owner) { 00563 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 00564 ast_channel_unlock(p->owner); 00565 } 00566 00567 while (p->chan && ast_channel_trylock(p->chan)) { 00568 DEADLOCK_AVOIDANCE(&p->lock); 00569 } 00570 if (p->chan) { 00571 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00572 ast_channel_unlock(p->chan); 00573 } 00574 } else { 00575 long logintime; 00576 logintime = time(NULL) - p->loginstart; 00577 p->loginstart = 0; 00578 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 00579 } 00580 } 00581 } 00582 switch (f->frametype) { 00583 case AST_FRAME_CONTROL: 00584 if (f->subclass == AST_CONTROL_ANSWER) { 00585 if (p->ackcall) { 00586 if (option_verbose > 2) 00587 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 00588 /* Don't pass answer along */ 00589 ast_frfree(f); 00590 f = &ast_null_frame; 00591 } else { 00592 p->acknowledged = 1; 00593 /* Use the builtin answer frame for the 00594 recording start check below. */ 00595 ast_frfree(f); 00596 f = &answer_frame; 00597 } 00598 } 00599 break; 00600 case AST_FRAME_DTMF_BEGIN: 00601 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00602 if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){ 00603 ast_frfree(f); 00604 f = &ast_null_frame; 00605 } 00606 break; 00607 case AST_FRAME_DTMF_END: 00608 if (!p->acknowledged && (f->subclass == '#')) { 00609 if (option_verbose > 2) 00610 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 00611 p->acknowledged = 1; 00612 ast_frfree(f); 00613 f = &answer_frame; 00614 } else if (f->subclass == '*' && endcall) { 00615 /* terminates call */ 00616 ast_frfree(f); 00617 f = NULL; 00618 } 00619 break; 00620 case AST_FRAME_VOICE: 00621 case AST_FRAME_VIDEO: 00622 /* don't pass voice or video until the call is acknowledged */ 00623 if (!p->acknowledged) { 00624 ast_frfree(f); 00625 f = &ast_null_frame; 00626 } 00627 default: 00628 /* pass everything else on through */ 00629 break; 00630 } 00631 } 00632 00633 CLEANUP(ast,p); 00634 if (p->chan && !p->chan->_bridge) { 00635 if (strcasecmp(p->chan->tech->type, "Local")) { 00636 p->chan->_bridge = ast; 00637 if (p->chan) 00638 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00639 } 00640 } 00641 ast_mutex_unlock(&p->lock); 00642 if (recordagentcalls && f == &answer_frame) 00643 agent_start_monitoring(ast,0); 00644 return f; 00645 }
static struct ast_channel * agent_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static, read] |
Part of the Asterisk PBX interface.
Definition at line 1436 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_hangup(), agent_new(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_cond_signal(), ast_cond_wait(), AST_CONTROL_UNHOLD, ast_get_group(), ast_have_common_group(), ast_indicate(), ast_is_empty_group(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_request(), AST_STATE_DOWN, ast_strlen_zero(), ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::loginchan, option_debug, agent_pvt::owner, agent_pvt::pending, and s.
01437 { 01438 struct agent_pvt *p; 01439 struct ast_channel *chan = NULL; 01440 char *s; 01441 ast_group_t groupmatch; 01442 int groupoff; 01443 int waitforagent=0; 01444 int hasagent = 0; 01445 struct timeval tv; 01446 01447 s = data; 01448 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01449 char tmp[12]; 01450 sprintf(tmp, "%d", groupoff); 01451 ast_get_group(&groupmatch, tmp); 01452 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01453 char tmp[12]; 01454 sprintf(tmp, "%d", groupoff); 01455 ast_get_group(&groupmatch, tmp); 01456 waitforagent = 1; 01457 } else { 01458 memset(groupmatch, 0, sizeof(groupmatch)); 01459 } 01460 01461 /* Check actual logged in agents first */ 01462 AST_LIST_LOCK(&agents); 01463 AST_LIST_TRAVERSE(&agents, p, list) { 01464 ast_mutex_lock(&p->lock); 01465 if (!p->pending && ((!ast_is_empty_group(&groupmatch) && ast_have_common_group(&p->group, &groupmatch)) || !strcmp(data, p->agent)) && 01466 ast_strlen_zero(p->loginchan)) { 01467 if (p->chan) 01468 hasagent++; 01469 tv = ast_tvnow(); 01470 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01471 p->lastdisc = ast_tv(0, 0); 01472 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01473 if (!p->owner && p->chan) { 01474 /* Fixed agent */ 01475 chan = agent_new(p, AST_STATE_DOWN); 01476 } 01477 if (chan) { 01478 ast_mutex_unlock(&p->lock); 01479 break; 01480 } 01481 } 01482 } 01483 ast_mutex_unlock(&p->lock); 01484 } 01485 if (!p) { 01486 AST_LIST_TRAVERSE(&agents, p, list) { 01487 ast_mutex_lock(&p->lock); 01488 if (!p->pending && ((!ast_is_empty_group(&groupmatch) && ast_have_common_group(&p->group, &groupmatch)) || !strcmp(data, p->agent))) { 01489 if (p->chan || !ast_strlen_zero(p->loginchan)) 01490 hasagent++; 01491 tv = ast_tvnow(); 01492 #if 0 01493 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec); 01494 #endif 01495 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01496 p->lastdisc = ast_tv(0, 0); 01497 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01498 if (!p->owner && p->chan) { 01499 /* Could still get a fixed agent */ 01500 chan = agent_new(p, AST_STATE_DOWN); 01501 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01502 /* Adjustable agent */ 01503 p->chan = ast_request("Local", format, p->loginchan, cause); 01504 if (p->chan) 01505 chan = agent_new(p, AST_STATE_DOWN); 01506 } 01507 if (chan) { 01508 ast_mutex_unlock(&p->lock); 01509 break; 01510 } 01511 } 01512 } 01513 ast_mutex_unlock(&p->lock); 01514 } 01515 } 01516 01517 if (!chan && waitforagent) { 01518 /* No agent available -- but we're requesting to wait for one. 01519 Allocate a place holder */ 01520 if (hasagent) { 01521 if (option_debug) 01522 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); 01523 p = add_agent(data, 1); 01524 memcpy(&p->group, &groupmatch, sizeof(p->group)); 01525 chan = agent_new(p, AST_STATE_DOWN); 01526 if (!chan) 01527 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01528 } else 01529 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); 01530 } 01531 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01532 AST_LIST_UNLOCK(&agents); 01533 01534 if (chan) { 01535 ast_mutex_lock(&p->lock); 01536 if (p->pending) { 01537 ast_mutex_unlock(&p->lock); 01538 return chan; 01539 } 01540 01541 if (!p->chan) { 01542 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 01543 *cause = AST_CAUSE_UNREGISTERED; 01544 ast_mutex_unlock(&p->lock); 01545 agent_hangup(chan); 01546 return NULL; 01547 } 01548 01549 /* when not in callback mode we need to take control of the channel 01550 * from the login app thread */ 01551 if(ast_strlen_zero(p->loginchan)) { 01552 p->app_sleep_cond = 0; 01553 p->app_lock_flag = 1; 01554 01555 ast_queue_frame(p->chan, &ast_null_frame); 01556 ast_cond_wait(&p->login_wait_cond, &p->lock); 01557 01558 if (!p->chan) { 01559 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 01560 p->app_sleep_cond = 1; 01561 p->app_lock_flag = 0; 01562 ast_cond_signal(&p->app_complete_cond); 01563 ast_mutex_unlock(&p->lock); 01564 *cause = AST_CAUSE_UNREGISTERED; 01565 agent_hangup(chan); 01566 return NULL; 01567 } 01568 01569 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01570 } 01571 ast_mutex_unlock(&p->lock); 01572 } 01573 01574 return chan; 01575 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 647 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.
00648 { 00649 struct agent_pvt *p = ast->tech_pvt; 00650 int res = -1; 00651 ast_mutex_lock(&p->lock); 00652 if (p->chan) 00653 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00654 ast_mutex_unlock(&p->lock); 00655 return res; 00656 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 658 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.
00659 { 00660 struct agent_pvt *p = ast->tech_pvt; 00661 int res = -1; 00662 ast_mutex_lock(&p->lock); 00663 if (p->chan) 00664 res = ast_sendtext(p->chan, text); 00665 ast_mutex_unlock(&p->lock); 00666 return res; 00667 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 882 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00883 { 00884 struct agent_pvt *p = NULL; 00885 00886 if (!chan || !base) { 00887 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00888 return -1; 00889 } 00890 p = chan->tech_pvt; 00891 if (!p) { 00892 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00893 return -1; 00894 } 00895 p->chan = base; 00896 return 0; 00897 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 491 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00492 { 00493 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00494 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 669 of file chan_agent.c.
References AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame::frametype, agent_pvt::lock, LOG_DEBUG, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.
00670 { 00671 struct agent_pvt *p = ast->tech_pvt; 00672 int res = -1; 00673 CHECK_FORMATS(ast, p); 00674 ast_mutex_lock(&p->lock); 00675 if (!p->chan) 00676 res = 0; 00677 else { 00678 if ((f->frametype != AST_FRAME_VOICE) || 00679 (f->frametype != AST_FRAME_VIDEO) || 00680 (f->subclass == p->chan->writeformat)) { 00681 res = ast_write(p->chan, f); 00682 } else { 00683 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00684 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00685 ast->name, p->chan->name); 00686 res = 0; 00687 } 00688 } 00689 CLEANUP(ast, p); 00690 ast_mutex_unlock(&p->lock); 00691 return res; 00692 }
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 2576 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), ast_channel::priority, and VERBOSE_PREFIX_3.
Referenced by load_module().
02577 { 02578 int exitifnoagentid = 0; 02579 int nowarnings = 0; 02580 int changeoutgoing = 0; 02581 int res = 0; 02582 char agent[AST_MAX_AGENT]; 02583 02584 if (data) { 02585 if (strchr(data, 'd')) 02586 exitifnoagentid = 1; 02587 if (strchr(data, 'n')) 02588 nowarnings = 1; 02589 if (strchr(data, 'c')) 02590 changeoutgoing = 1; 02591 } 02592 if (chan->cid.cid_num) { 02593 const char *tmp; 02594 char agentvar[AST_MAX_BUF]; 02595 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02596 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02597 struct agent_pvt *p; 02598 ast_copy_string(agent, tmp, sizeof(agent)); 02599 AST_LIST_LOCK(&agents); 02600 AST_LIST_TRAVERSE(&agents, p, list) { 02601 if (!strcasecmp(p->agent, tmp)) { 02602 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02603 __agent_start_monitoring(chan, p, 1); 02604 break; 02605 } 02606 } 02607 AST_LIST_UNLOCK(&agents); 02608 02609 } else { 02610 res = -1; 02611 if (!nowarnings) 02612 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); 02613 } 02614 } else { 02615 res = -1; 02616 if (!nowarnings) 02617 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"); 02618 } 02619 /* check if there is n + 101 priority */ 02620 /*! \todo XXX Needs to check option priorityjump etc etc */ 02621 if (res) { 02622 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) { 02623 chan->priority+=100; 02624 if (option_verbose > 2) 02625 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); 02626 } else if (exitifnoagentid) 02627 return res; 02628 } 02629 return 0; 02630 }
static int agents_show | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Show agents in cli.
< Number of agents configured
< Number of online agents
< Number of offline agents
Definition at line 1821 of file chan_agent.c.
References agent_pvt::acknowledged, agent_pvt::agent, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_print_group(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.
01822 { 01823 struct agent_pvt *p; 01824 char username[AST_MAX_BUF]; 01825 char location[AST_MAX_BUF] = ""; 01826 char talkingto[AST_MAX_BUF] = ""; 01827 char moh[AST_MAX_BUF]; 01828 int count_agents = 0; /*!< Number of agents configured */ 01829 int online_agents = 0; /*!< Number of online agents */ 01830 int offline_agents = 0; /*!< Number of offline agents */ 01831 if (argc != 2) 01832 return RESULT_SHOWUSAGE; 01833 AST_LIST_LOCK(&agents); 01834 AST_LIST_TRAVERSE(&agents, p, list) { 01835 ast_mutex_lock(&p->lock); 01836 if (p->pending) { 01837 char tmp[256]; 01838 if (p->group) 01839 ast_cli(fd, "-- Pending call to group %s\n", ast_print_group(tmp, sizeof(tmp), &p->group)); 01840 else 01841 ast_cli(fd, "-- Pending call to agent %s\n", p->agent); 01842 } else { 01843 if (!ast_strlen_zero(p->name)) 01844 snprintf(username, sizeof(username), "(%s) ", p->name); 01845 else 01846 username[0] = '\0'; 01847 if (p->chan) { 01848 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01849 if (p->owner && ast_bridged_channel(p->owner)) 01850 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01851 else 01852 strcpy(talkingto, " is idle"); 01853 online_agents++; 01854 } else if (!ast_strlen_zero(p->loginchan)) { 01855 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01856 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01857 else 01858 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01859 talkingto[0] = '\0'; 01860 online_agents++; 01861 if (p->acknowledged) 01862 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01863 } else { 01864 strcpy(location, "not logged in"); 01865 talkingto[0] = '\0'; 01866 offline_agents++; 01867 } 01868 if (!ast_strlen_zero(p->moh)) 01869 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01870 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 01871 username, location, talkingto, moh); 01872 count_agents++; 01873 } 01874 ast_mutex_unlock(&p->lock); 01875 } 01876 AST_LIST_UNLOCK(&agents); 01877 if ( !count_agents ) 01878 ast_cli(fd, "No Agents are configured in %s\n",config); 01879 else 01880 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01881 ast_cli(fd, "\n"); 01882 01883 return RESULT_SUCCESS; 01884 }
static int agents_show_online | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1887 of file chan_agent.c.
References agent_pvt::acknowledged, agent_pvt::agent, 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, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.
01888 { 01889 struct agent_pvt *p; 01890 char username[AST_MAX_BUF]; 01891 char location[AST_MAX_BUF] = ""; 01892 char talkingto[AST_MAX_BUF] = ""; 01893 char moh[AST_MAX_BUF]; 01894 int count_agents = 0; /* Number of agents configured */ 01895 int online_agents = 0; /* Number of online agents */ 01896 int agent_status = 0; /* 0 means offline, 1 means online */ 01897 if (argc != 3) 01898 return RESULT_SHOWUSAGE; 01899 AST_LIST_LOCK(&agents); 01900 AST_LIST_TRAVERSE(&agents, p, list) { 01901 agent_status = 0; /* reset it to offline */ 01902 ast_mutex_lock(&p->lock); 01903 if (!ast_strlen_zero(p->name)) 01904 snprintf(username, sizeof(username), "(%s) ", p->name); 01905 else 01906 username[0] = '\0'; 01907 if (p->chan) { 01908 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01909 if (p->owner && ast_bridged_channel(p->owner)) 01910 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01911 else 01912 strcpy(talkingto, " is idle"); 01913 agent_status = 1; 01914 online_agents++; 01915 } else if (!ast_strlen_zero(p->loginchan)) { 01916 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01917 talkingto[0] = '\0'; 01918 agent_status = 1; 01919 online_agents++; 01920 if (p->acknowledged) 01921 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01922 } 01923 if (!ast_strlen_zero(p->moh)) 01924 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01925 if (agent_status) 01926 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh); 01927 count_agents++; 01928 ast_mutex_unlock(&p->lock); 01929 } 01930 AST_LIST_UNLOCK(&agents); 01931 if (!count_agents) 01932 ast_cli(fd, "No Agents are configured in %s\n", config); 01933 else 01934 ast_cli(fd, "%d agents online\n", online_agents); 01935 ast_cli(fd, "\n"); 01936 return RESULT_SUCCESS; 01937 }
static int allow_multiple_login | ( | char * | chan, | |
char * | context | |||
) | [static] |
Definition at line 1414 of file chan_agent.c.
References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.
Referenced by __login_exec().
01415 { 01416 struct agent_pvt *p; 01417 char loginchan[80]; 01418 01419 if (multiplelogin) { 01420 return 1; 01421 } 01422 if (!chan) { 01423 return 0; 01424 } 01425 01426 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); 01427 01428 AST_LIST_TRAVERSE(&agents, p, list) { 01429 if(!strcasecmp(loginchan, p->loginchan)) 01430 return 0; 01431 } 01432 return -1; 01433 }
static void callback_deprecated | ( | void | ) | [static] |
Definition at line 2455 of file chan_agent.c.
References ast_log(), depwarning, and LOG_WARNING.
Referenced by action_agent_callback_login(), and callback_exec().
02456 { 02457 static int depwarning = 0; 02458 02459 if (!depwarning) { 02460 depwarning = 1; 02461 02462 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n"); 02463 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n"); 02464 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n"); 02465 } 02466 }
static int callback_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Called by the AgentCallbackLogin application (from the dial plan).
chan | ||
data |
Definition at line 2476 of file chan_agent.c.
References __login_exec(), and callback_deprecated().
Referenced by load_module().
02477 { 02478 callback_deprecated(); 02479 02480 return __login_exec(chan, data, 1); 02481 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1300 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_FLAG_ZOMBIE, ast_have_common_group(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), 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, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.
Referenced by __login_exec().
01301 { 01302 struct ast_channel *chan=NULL, *parent=NULL; 01303 struct agent_pvt *p; 01304 int res; 01305 01306 if (option_debug) 01307 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); 01308 if (needlock) 01309 AST_LIST_LOCK(&agents); 01310 AST_LIST_TRAVERSE(&agents, p, list) { 01311 if (p == newlyavailable) { 01312 continue; 01313 } 01314 ast_mutex_lock(&p->lock); 01315 if (!p->abouttograb && p->pending && ((p->group && ast_have_common_group(&newlyavailable->group, &p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01316 if (option_debug) 01317 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01318 /* We found a pending call, time to merge */ 01319 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01320 parent = p->owner; 01321 p->abouttograb = 1; 01322 ast_mutex_unlock(&p->lock); 01323 break; 01324 } 01325 ast_mutex_unlock(&p->lock); 01326 } 01327 if (needlock) 01328 AST_LIST_UNLOCK(&agents); 01329 if (parent && chan) { 01330 if (newlyavailable->ackcall > 1) { 01331 /* Don't do beep here */ 01332 res = 0; 01333 } else { 01334 if (option_debug > 2) 01335 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01336 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01337 if (option_debug > 2) 01338 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01339 if (!res) { 01340 res = ast_waitstream(newlyavailable->chan, ""); 01341 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01342 } 01343 } 01344 if (!res) { 01345 /* Note -- parent may have disappeared */ 01346 if (p->abouttograb) { 01347 newlyavailable->acknowledged = 1; 01348 /* Safe -- agent lock already held */ 01349 ast_setstate(parent, AST_STATE_UP); 01350 ast_setstate(chan, AST_STATE_UP); 01351 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01352 /* Go ahead and mark the channel as a zombie so that masquerade will 01353 destroy it for us, and we need not call ast_hangup */ 01354 ast_mutex_lock(&parent->lock); 01355 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01356 ast_channel_masquerade(parent, chan); 01357 ast_mutex_unlock(&parent->lock); 01358 p->abouttograb = 0; 01359 } else { 01360 if (option_debug) 01361 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); 01362 agent_cleanup(newlyavailable); 01363 } 01364 } else { 01365 if (option_debug) 01366 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); 01367 agent_cleanup(newlyavailable); 01368 } 01369 } 01370 return 0; 01371 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1373 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::agent, ast_have_common_group(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.
Referenced by __login_exec().
01374 { 01375 struct agent_pvt *p; 01376 int res=0; 01377 01378 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); 01379 if (needlock) 01380 AST_LIST_LOCK(&agents); 01381 AST_LIST_TRAVERSE(&agents, p, list) { 01382 if (p == newlyavailable) { 01383 continue; 01384 } 01385 ast_mutex_lock(&p->lock); 01386 if (!p->abouttograb && p->pending && ((p->group && ast_have_common_group(&newlyavailable->group, &p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01387 if (option_debug) 01388 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01389 ast_mutex_unlock(&p->lock); 01390 break; 01391 } 01392 ast_mutex_unlock(&p->lock); 01393 } 01394 if (needlock) 01395 AST_LIST_UNLOCK(&agents); 01396 if (p) { 01397 ast_mutex_unlock(&newlyavailable->lock); 01398 if (option_debug > 2) 01399 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01400 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01401 if (option_debug > 2) 01402 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01403 if (!res) { 01404 res = ast_waitstream(newlyavailable->chan, ""); 01405 if (option_debug) 01406 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01407 } 01408 ast_mutex_lock(&newlyavailable->lock); 01409 } 01410 return res; 01411 }
static char* complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1794 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_AGENT, ast_strdup, len(), and agent_pvt::name.
01795 { 01796 char *ret = NULL; 01797 01798 if (pos == 2) { 01799 struct agent_pvt *p; 01800 char name[AST_MAX_AGENT]; 01801 int which = 0, len = strlen(word); 01802 01803 AST_LIST_LOCK(&agents); 01804 AST_LIST_TRAVERSE(&agents, p, list) { 01805 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01806 if (!strncasecmp(word, name, len) && ++which > state) { 01807 ret = ast_strdup(name); 01808 break; 01809 } 01810 } 01811 AST_LIST_UNLOCK(&agents); 01812 } else if (pos == 3 && state == 0) 01813 return ast_strdup("soft"); 01814 01815 return ret; 01816 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2635 of file chan_agent.c.
References agent_pvt::agent, ast_db_del(), ast_db_put(), AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), agent_pvt::chan, LOG_DEBUG, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, and option_debug.
Referenced by __login_exec(), action_agent_callback_login(), agent_hangup(), and agent_logoff_maintenance().
02636 { 02637 struct agent_pvt *cur_agent = NULL; 02638 char buf[256]; 02639 02640 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02641 if (cur_agent->chan) 02642 continue; 02643 02644 if (!ast_strlen_zero(cur_agent->loginchan)) { 02645 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02646 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02647 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02648 else if (option_debug) 02649 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02650 } else { 02651 /* Delete - no agent or there is an error */ 02652 ast_db_del(pa_family, cur_agent->agent); 02653 } 02654 } 02655 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static, read] |
Definition at line 2768 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02769 { 02770 struct agent_pvt *cur; 02771 02772 AST_LIST_TRAVERSE(&agents, cur, list) { 02773 if (!strcmp(cur->agent, agentid)) 02774 break; 02775 } 02776 02777 return cur; 02778 }
static int function_agent | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2780 of file chan_agent.c.
References agent_pvt::agent, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::chan, find_agent(), LOG_WARNING, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, parse(), and agent_pvt::password.
02781 { 02782 char *parse; 02783 AST_DECLARE_APP_ARGS(args, 02784 AST_APP_ARG(agentid); 02785 AST_APP_ARG(item); 02786 ); 02787 char *tmp; 02788 struct agent_pvt *agent; 02789 02790 buf[0] = '\0'; 02791 02792 if (ast_strlen_zero(data)) { 02793 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02794 return -1; 02795 } 02796 02797 parse = ast_strdupa(data); 02798 02799 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02800 if (!args.item) 02801 args.item = "status"; 02802 02803 AST_LIST_LOCK(&agents); 02804 02805 if (!(agent = find_agent(args.agentid))) { 02806 AST_LIST_UNLOCK(&agents); 02807 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02808 return -1; 02809 } 02810 02811 if (!strcasecmp(args.item, "status")) { 02812 char *status = "LOGGEDOUT"; 02813 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02814 status = "LOGGEDIN"; 02815 ast_copy_string(buf, status, len); 02816 } else if (!strcasecmp(args.item, "password")) 02817 ast_copy_string(buf, agent->password, len); 02818 else if (!strcasecmp(args.item, "name")) 02819 ast_copy_string(buf, agent->name, len); 02820 else if (!strcasecmp(args.item, "mohclass")) 02821 ast_copy_string(buf, agent->moh, len); 02822 else if (!strcasecmp(args.item, "channel")) { 02823 if (agent->chan) { 02824 ast_channel_lock(agent->chan); 02825 ast_copy_string(buf, agent->chan->name, len); 02826 ast_channel_unlock(agent->chan); 02827 tmp = strrchr(buf, '-'); 02828 if (tmp) 02829 *tmp = '\0'; 02830 } 02831 } else if (!strcasecmp(args.item, "exten")) 02832 ast_copy_string(buf, agent->loginchan, len); 02833 02834 AST_LIST_UNLOCK(&agents); 02835 02836 return 0; 02837 }
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 2862 of file chan_agent.c.
References action_agent_callback_login(), action_agent_logoff(), action_agents(), agent_devicestate_cb(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register(), ast_devstate_add(), ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, ast_register_application(), callback_exec(), cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().
02863 { 02864 /* Make sure we can register our agent channel type */ 02865 if (ast_channel_register(&agent_tech)) { 02866 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02867 return -1; 02868 } 02869 /* Read in the config */ 02870 if (!read_agent_config()) 02871 return AST_MODULE_LOAD_DECLINE; 02872 if (persistent_agents) 02873 reload_agents(); 02874 /* Dialplan applications */ 02875 ast_register_application(app, login_exec, synopsis, descrip); 02876 ast_register_application(app2, callback_exec, synopsis2, descrip2); 02877 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02878 02879 /* Manager commands */ 02880 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02881 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02882 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login); 02883 02884 /* CLI Commands */ 02885 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02886 02887 /* Dialplan Functions */ 02888 ast_custom_function_register(&agent_function); 02889 02890 ast_devstate_add(agent_devicestate_cb, NULL); 02891 02892 return 0; 02893 }
static int login_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Called by the AgentLogin application (from the dial plan).
chan | ||
data |
Definition at line 2450 of file chan_agent.c.
References __login_exec().
Referenced by load_module().
02451 { 02452 return __login_exec(chan, data, 0); 02453 }
static int read_agent_config | ( | void | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1150 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, ast_category_browse(), ast_cond_destroy(), ast_config_destroy(), ast_config_load(), ast_copy_string(), ast_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, agent_pvt::dead, free, agent_pvt::lock, LOG_NOTICE, agent_pvt::login_wait_cond, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01151 { 01152 struct ast_config *cfg; 01153 struct ast_config *ucfg; 01154 struct ast_variable *v; 01155 struct agent_pvt *p; 01156 const char *general_val; 01157 const char *catname; 01158 const char *hasagent; 01159 int genhasagent; 01160 01161 memset(group, 0, sizeof(group)); 01162 autologoff = 0; 01163 wrapuptime = 0; 01164 ackcall = 0; 01165 endcall = 1; 01166 cfg = ast_config_load(config); 01167 if (!cfg) { 01168 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01169 return 0; 01170 } 01171 AST_LIST_LOCK(&agents); 01172 AST_LIST_TRAVERSE(&agents, p, list) { 01173 p->dead = 1; 01174 } 01175 strcpy(moh, "default"); 01176 /* set the default recording values */ 01177 recordagentcalls = 0; 01178 strcpy(recordformat, "wav"); 01179 strcpy(recordformatext, "wav"); 01180 urlprefix[0] = '\0'; 01181 savecallsin[0] = '\0'; 01182 01183 /* Read in [general] section for persistence */ 01184 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01185 persistent_agents = ast_true(general_val); 01186 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01187 01188 /* Read in the [agents] section */ 01189 v = ast_variable_browse(cfg, "agents"); 01190 while(v) { 01191 /* Create the interface list */ 01192 if (!strcasecmp(v->name, "agent")) { 01193 add_agent(v->value, 0); 01194 } else if (!strcasecmp(v->name, "group")) { 01195 ast_get_group(&group, v->value); 01196 } else if (!strcasecmp(v->name, "autologoff")) { 01197 autologoff = atoi(v->value); 01198 if (autologoff < 0) 01199 autologoff = 0; 01200 } else if (!strcasecmp(v->name, "ackcall")) { 01201 if (!strcasecmp(v->value, "always")) 01202 ackcall = 2; 01203 else if (ast_true(v->value)) 01204 ackcall = 1; 01205 else 01206 ackcall = 0; 01207 } else if (!strcasecmp(v->name, "endcall")) { 01208 endcall = ast_true(v->value); 01209 } else if (!strcasecmp(v->name, "wrapuptime")) { 01210 wrapuptime = atoi(v->value); 01211 if (wrapuptime < 0) 01212 wrapuptime = 0; 01213 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01214 maxlogintries = atoi(v->value); 01215 if (maxlogintries < 0) 01216 maxlogintries = 0; 01217 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01218 strcpy(agentgoodbye,v->value); 01219 } else if (!strcasecmp(v->name, "musiconhold")) { 01220 ast_copy_string(moh, v->value, sizeof(moh)); 01221 } else if (!strcasecmp(v->name, "updatecdr")) { 01222 if (ast_true(v->value)) 01223 updatecdr = 1; 01224 else 01225 updatecdr = 0; 01226 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01227 if (ast_true(v->value)) 01228 autologoffunavail = 1; 01229 else 01230 autologoffunavail = 0; 01231 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01232 recordagentcalls = ast_true(v->value); 01233 } else if (!strcasecmp(v->name, "recordformat")) { 01234 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01235 if (!strcasecmp(v->value, "wav49")) 01236 strcpy(recordformatext, "WAV"); 01237 else 01238 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01239 } else if (!strcasecmp(v->name, "urlprefix")) { 01240 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01241 if (urlprefix[strlen(urlprefix) - 1] != '/') 01242 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01243 } else if (!strcasecmp(v->name, "savecallsin")) { 01244 if (v->value[0] == '/') 01245 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01246 else 01247 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01248 if (savecallsin[strlen(savecallsin) - 1] != '/') 01249 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01250 } else if (!strcasecmp(v->name, "custom_beep")) { 01251 ast_copy_string(beep, v->value, sizeof(beep)); 01252 } 01253 v = v->next; 01254 } 01255 if ((ucfg = ast_config_load("users.conf"))) { 01256 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01257 catname = ast_category_browse(ucfg, NULL); 01258 while(catname) { 01259 if (strcasecmp(catname, "general")) { 01260 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01261 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01262 char tmp[256]; 01263 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01264 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01265 if (!fullname) 01266 fullname = ""; 01267 if (!secret) 01268 secret = ""; 01269 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01270 add_agent(tmp, 0); 01271 } 01272 } 01273 catname = ast_category_browse(ucfg, catname); 01274 } 01275 ast_config_destroy(ucfg); 01276 } 01277 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01278 if (p->dead) { 01279 AST_LIST_REMOVE_CURRENT(&agents, list); 01280 /* Destroy if appropriate */ 01281 if (!p->owner) { 01282 if (!p->chan) { 01283 ast_mutex_destroy(&p->lock); 01284 ast_cond_destroy(&p->app_complete_cond); 01285 ast_cond_destroy(&p->login_wait_cond); 01286 free(p); 01287 } else { 01288 /* Cause them to hang up */ 01289 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01290 } 01291 } 01292 } 01293 } 01294 AST_LIST_TRAVERSE_SAFE_END 01295 AST_LIST_UNLOCK(&agents); 01296 ast_config_destroy(cfg); 01297 return 1; 01298 }
static int reload | ( | void | ) | [static] |
Definition at line 2895 of file chan_agent.c.
References read_agent_config(), and reload_agents().
02896 { 02897 read_agent_config(); 02898 if (persistent_agents) 02899 reload_agents(); 02900 return 0; 02901 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2660 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_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::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, ast_db_entry::next, option_debug, parse(), set_agentbycallerid(), and strsep().
Referenced by load_module(), and reload().
02661 { 02662 char *agent_num; 02663 struct ast_db_entry *db_tree; 02664 struct ast_db_entry *entry; 02665 struct agent_pvt *cur_agent; 02666 char agent_data[256]; 02667 char *parse; 02668 char *agent_chan; 02669 char *agent_callerid; 02670 02671 db_tree = ast_db_gettree(pa_family, NULL); 02672 02673 AST_LIST_LOCK(&agents); 02674 for (entry = db_tree; entry; entry = entry->next) { 02675 agent_num = entry->key + strlen(pa_family) + 2; 02676 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02677 ast_mutex_lock(&cur_agent->lock); 02678 if (strcmp(agent_num, cur_agent->agent) == 0) 02679 break; 02680 ast_mutex_unlock(&cur_agent->lock); 02681 } 02682 if (!cur_agent) { 02683 ast_db_del(pa_family, agent_num); 02684 continue; 02685 } else 02686 ast_mutex_unlock(&cur_agent->lock); 02687 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02688 if (option_debug) 02689 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02690 parse = agent_data; 02691 agent_chan = strsep(&parse, ";"); 02692 agent_callerid = strsep(&parse, ";"); 02693 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02694 if (agent_callerid) { 02695 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02696 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02697 } else 02698 cur_agent->logincallerid[0] = '\0'; 02699 if (cur_agent->loginstart == 0) 02700 time(&cur_agent->loginstart); 02701 ast_device_state_changed("Agent/%s", cur_agent->agent); 02702 } 02703 } 02704 AST_LIST_UNLOCK(&agents); 02705 if (db_tree) { 02706 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02707 ast_db_freetree(db_tree); 02708 } 02709 }
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 853 of file chan_agent.c.
References AST_MAX_BUF, ast_strlen_zero(), GETAGENTBYCALLERID, and pbx_builtin_setvar_helper().
Referenced by __login_exec(), agent_logoff_maintenance(), and reload_agents().
00854 { 00855 char buf[AST_MAX_BUF]; 00856 00857 /* if there is no Caller ID, nothing to do */ 00858 if (ast_strlen_zero(callerid)) 00859 return; 00860 00861 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00862 pbx_builtin_setvar_helper(NULL, buf, agent); 00863 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2903 of file chan_agent.c.
References agent_devicestate_cb(), agent_function, agent_tech, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_del(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), cli_agents, free, and agent_pvt::owner.
02904 { 02905 struct agent_pvt *p; 02906 /* First, take us out of the channel loop */ 02907 ast_channel_unregister(&agent_tech); 02908 /* Delete devicestate subscription */ 02909 ast_devstate_del(agent_devicestate_cb, NULL); 02910 /* Unregister dialplan functions */ 02911 ast_custom_function_unregister(&agent_function); 02912 /* Unregister CLI commands */ 02913 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02914 /* Unregister dialplan applications */ 02915 ast_unregister_application(app); 02916 ast_unregister_application(app2); 02917 ast_unregister_application(app3); 02918 /* Unregister manager command */ 02919 ast_manager_unregister("Agents"); 02920 ast_manager_unregister("AgentLogoff"); 02921 ast_manager_unregister("AgentCallbackLogin"); 02922 /* Unregister channel */ 02923 AST_LIST_LOCK(&agents); 02924 /* Hangup all interfaces if they have an owner */ 02925 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02926 if (p->owner) 02927 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02928 free(p); 02929 } 02930 AST_LIST_UNLOCK(&agents); 02931 return 0; 02932 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 2938 of file chan_agent.c.
int ackcall [static] |
Definition at line 159 of file chan_agent.c.
Definition at line 2839 of file chan_agent.c.
Referenced by load_module(), and unload_module().
char agent_logoff_usage[] [static] |
"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 1949 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 267 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 165 of file chan_agent.c.
const char app[] = "AgentLogin" [static] |
Definition at line 82 of file chan_agent.c.
Referenced by action_originate(), answer_exec_enable(), exec_exec(), execif_exec(), feature_exec_app(), handle_context_add_extension(), handle_context_add_extension_deprecated(), load_config(), page_exec(), pbx_extension_helper(), realtime_exec(), and tryexec_exec().
const char app2[] = "AgentCallbackLogin" [static] |
Definition at line 83 of file chan_agent.c.
Referenced by _macro_exec().
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 84 of file chan_agent.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2938 of file chan_agent.c.
int autologoff [static] |
Definition at line 157 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 162 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 173 of file chan_agent.c.
struct ast_cli_entry cli_agents[] [static] |
Definition at line 1964 of file chan_agent.c.
Referenced by load_module(), and unload_module().
struct ast_cli_entry cli_show_agents_deprecated [static] |
{ { "show", "agents", NULL }, agents_show, NULL, NULL, NULL }
Definition at line 1954 of file chan_agent.c.
struct ast_cli_entry cli_show_agents_online_deprecated [static] |
{ { "show", "agents", "online" }, agents_show_online, NULL, NULL, NULL }
Definition at line 1959 of file chan_agent.c.
const char config[] = "agents.conf" [static] |
Definition at line 80 of file chan_agent.c.
Referenced by ast_config_new(), ast_readconfig(), do_reload(), load_module(), load_odbc_config(), misdn_cfg_init(), parse_config(), read_config_maps(), reload(), and reload_config().
const char descrip[] [static] |
Definition at line 90 of file chan_agent.c.
Referenced by aji_handle_presence().
const char descrip2[] [static] |
Definition at line 99 of file chan_agent.c.
const char descrip3[] [static] |
Definition at line 107 of file chan_agent.c.
int endcall [static] |
Definition at line 160 of file chan_agent.c.
ast_group_t group [static] |
Definition at line 156 of file chan_agent.c.
Referenced by ast_app_group_set_channel(), ast_makesocket(), common_exec(), group_count_function_read(), group_match_count_function_read(), main(), misdn_check_l2l1(), and misdn_request().
const char mandescr_agent_callback_login[] [static] |
Definition at line 135 of file chan_agent.c.
const char mandescr_agent_logoff[] [static] |
"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 129 of file chan_agent.c.
const char mandescr_agents[] [static] |
"Description: Will list info about all possible agents.\n" "Variables: NONE\n"
Definition at line 125 of file chan_agent.c.
int maxlogintries = 3 [static] |
Definition at line 164 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 144 of file chan_agent.c.
Referenced by get_mohbyname(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().
int multiplelogin = 1 [static] |
Definition at line 161 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 150 of file chan_agent.c.
int persistent_agents = 0 [static] |
queues.conf [general] option
Definition at line 153 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 167 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 168 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 169 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 171 of file chan_agent.c.
char show_agents_online_usage[] [static] |
"Usage: agent show online\n" " Provides a list of all online agents.\n"
Definition at line 1945 of file chan_agent.c.
char show_agents_usage[] [static] |
"Usage: agent show\n" " Provides summary information on agents.\n"
Definition at line 1941 of file chan_agent.c.
Definition at line 86 of file chan_agent.c.
Definition at line 87 of file chan_agent.c.
Definition at line 88 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 79 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 172 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
Definition at line 170 of file chan_agent.c.
Referenced by start_monitor_exec().
int wrapuptime [static] |
Definition at line 158 of file chan_agent.c.