#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... | |
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 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 | AST_LIST_HEAD_STATIC (agents, agent_pvt) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,) | |
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 force_inline int | powerof (unsigned int d) |
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 int | ackcall |
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 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 |
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 | ) |
#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 230 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 450 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().
00451 { 00452 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00453 char filename[AST_MAX_BUF]; 00454 int res = -1; 00455 if (!p) 00456 return -1; 00457 if (!ast->monitor) { 00458 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00459 /* substitute . for - */ 00460 if ((pointer = strchr(filename, '.'))) 00461 *pointer = '-'; 00462 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00463 ast_monitor_start(ast, recordformat, tmp, needlock); 00464 ast_monitor_setjoinfiles(ast, 1); 00465 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00466 #if 0 00467 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00468 #endif 00469 if (!ast->cdr) 00470 ast->cdr = ast_cdr_alloc(); 00471 ast_cdr_setuserfield(ast, tmp2); 00472 res = 0; 00473 } else 00474 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00475 return res; 00476 }
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 1918 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_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, 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_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_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, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
Referenced by callback_exec(), and login_exec().
01919 { 01920 int res=0; 01921 int tries = 0; 01922 int max_login_tries = maxlogintries; 01923 struct agent_pvt *p; 01924 struct ast_module_user *u; 01925 int login_state = 0; 01926 char user[AST_MAX_AGENT] = ""; 01927 char pass[AST_MAX_AGENT]; 01928 char agent[AST_MAX_AGENT] = ""; 01929 char xpass[AST_MAX_AGENT] = ""; 01930 char *errmsg; 01931 char *parse; 01932 AST_DECLARE_APP_ARGS(args, 01933 AST_APP_ARG(agent_id); 01934 AST_APP_ARG(options); 01935 AST_APP_ARG(extension); 01936 ); 01937 const char *tmpoptions = NULL; 01938 char *context = NULL; 01939 int play_announcement = 1; 01940 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01941 int update_cdr = updatecdr; 01942 char *filename = "agent-loginok"; 01943 char tmpchan[AST_MAX_BUF] = ""; 01944 01945 u = ast_module_user_add(chan); 01946 01947 parse = ast_strdupa(data); 01948 01949 AST_STANDARD_APP_ARGS(args, parse); 01950 01951 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01952 01953 ast_channel_lock(chan); 01954 /* Set Channel Specific Login Overrides */ 01955 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01956 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01957 if (max_login_tries < 0) 01958 max_login_tries = 0; 01959 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01960 if (option_verbose > 2) 01961 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); 01962 } 01963 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01964 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01965 update_cdr = 1; 01966 else 01967 update_cdr = 0; 01968 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01969 if (option_verbose > 2) 01970 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01971 } 01972 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01973 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01974 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01975 if (option_verbose > 2) 01976 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01977 } 01978 ast_channel_unlock(chan); 01979 /* End Channel Specific Login Overrides */ 01980 01981 if (callbackmode && args.extension) { 01982 parse = args.extension; 01983 args.extension = strsep(&parse, "@"); 01984 context = parse; 01985 } 01986 01987 if (!ast_strlen_zero(args.options)) { 01988 if (strchr(args.options, 's')) { 01989 play_announcement = 0; 01990 } 01991 } 01992 01993 if (chan->_state != AST_STATE_UP) 01994 res = ast_answer(chan); 01995 if (!res) { 01996 if (!ast_strlen_zero(args.agent_id)) 01997 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01998 else 01999 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 02000 } 02001 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 02002 tries++; 02003 /* Check for password */ 02004 AST_LIST_LOCK(&agents); 02005 AST_LIST_TRAVERSE(&agents, p, list) { 02006 if (!strcmp(p->agent, user) && !p->pending) 02007 ast_copy_string(xpass, p->password, sizeof(xpass)); 02008 } 02009 AST_LIST_UNLOCK(&agents); 02010 if (!res) { 02011 if (!ast_strlen_zero(xpass)) 02012 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 02013 else 02014 pass[0] = '\0'; 02015 } 02016 errmsg = "agent-incorrect"; 02017 02018 #if 0 02019 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 02020 #endif 02021 02022 /* Check again for accuracy */ 02023 AST_LIST_LOCK(&agents); 02024 AST_LIST_TRAVERSE(&agents, p, list) { 02025 int unlock_channel = 1; 02026 ast_channel_lock(chan); 02027 ast_mutex_lock(&p->lock); 02028 if (!strcmp(p->agent, user) && 02029 !strcmp(p->password, pass) && !p->pending) { 02030 login_state = 1; /* Successful Login */ 02031 02032 /* Ensure we can't be gotten until we're done */ 02033 gettimeofday(&p->lastdisc, NULL); 02034 p->lastdisc.tv_sec++; 02035 02036 /* Set Channel Specific Agent Overrides */ 02037 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02038 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 02039 p->ackcall = 2; 02040 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 02041 p->ackcall = 1; 02042 else 02043 p->ackcall = 0; 02044 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02045 if (option_verbose > 2) 02046 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 02047 } else { 02048 p->ackcall = ackcall; 02049 } 02050 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02051 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02052 if (p->autologoff < 0) 02053 p->autologoff = 0; 02054 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02055 if (option_verbose > 2) 02056 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 02057 } else { 02058 p->autologoff = autologoff; 02059 } 02060 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02061 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02062 if (p->wrapuptime < 0) 02063 p->wrapuptime = 0; 02064 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02065 if (option_verbose > 2) 02066 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 02067 } else { 02068 p->wrapuptime = wrapuptime; 02069 } 02070 ast_channel_unlock(chan); 02071 unlock_channel = 0; 02072 /* End Channel Specific Agent Overrides */ 02073 if (!p->chan) { 02074 char last_loginchan[80] = ""; 02075 long logintime; 02076 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02077 02078 if (callbackmode) { 02079 int pos = 0; 02080 /* Retrieve login chan */ 02081 for (;;) { 02082 if (!ast_strlen_zero(args.extension)) { 02083 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 02084 res = 0; 02085 } else 02086 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 02087 if (ast_strlen_zero(tmpchan) ) 02088 break; 02089 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 02090 if(!allow_multiple_login(tmpchan,context) ) { 02091 args.extension = NULL; 02092 pos = 0; 02093 } else 02094 break; 02095 } 02096 if (args.extension) { 02097 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 02098 args.extension = NULL; 02099 pos = 0; 02100 } else { 02101 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 02102 res = ast_streamfile(chan, "invalid", chan->language); 02103 if (!res) 02104 res = ast_waitstream(chan, AST_DIGIT_ANY); 02105 if (res > 0) { 02106 tmpchan[0] = res; 02107 tmpchan[1] = '\0'; 02108 pos = 1; 02109 } else { 02110 tmpchan[0] = '\0'; 02111 pos = 0; 02112 } 02113 } 02114 } 02115 args.extension = tmpchan; 02116 if (!res) { 02117 set_agentbycallerid(p->logincallerid, NULL); 02118 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 02119 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 02120 else { 02121 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 02122 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 02123 } 02124 p->acknowledged = 0; 02125 if (ast_strlen_zero(p->loginchan)) { 02126 login_state = 2; 02127 filename = "agent-loggedoff"; 02128 } else { 02129 if (chan->cid.cid_num) { 02130 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 02131 set_agentbycallerid(p->logincallerid, p->agent); 02132 } else 02133 p->logincallerid[0] = '\0'; 02134 } 02135 02136 if(update_cdr && chan->cdr) 02137 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02138 02139 } 02140 } else { 02141 p->loginchan[0] = '\0'; 02142 p->logincallerid[0] = '\0'; 02143 p->acknowledged = 0; 02144 } 02145 ast_mutex_unlock(&p->lock); 02146 AST_LIST_UNLOCK(&agents); 02147 if( !res && play_announcement==1 ) 02148 res = ast_streamfile(chan, filename, chan->language); 02149 if (!res) 02150 ast_waitstream(chan, ""); 02151 AST_LIST_LOCK(&agents); 02152 ast_mutex_lock(&p->lock); 02153 if (!res) { 02154 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02155 if (res) 02156 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02157 } 02158 if (!res) { 02159 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02160 if (res) 02161 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02162 } 02163 /* Check once more just in case */ 02164 if (p->chan) 02165 res = -1; 02166 if (callbackmode && !res) { 02167 /* Just say goodbye and be done with it */ 02168 if (!ast_strlen_zero(p->loginchan)) { 02169 if (p->loginstart == 0) 02170 time(&p->loginstart); 02171 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02172 "Agent: %s\r\n" 02173 "Loginchan: %s\r\n" 02174 "Uniqueid: %s\r\n", 02175 p->agent, p->loginchan, chan->uniqueid); 02176 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02177 if (option_verbose > 1) 02178 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02179 ast_device_state_changed("Agent/%s", p->agent); 02180 if (persistent_agents) 02181 dump_agents(); 02182 } else { 02183 logintime = time(NULL) - p->loginstart; 02184 p->loginstart = 0; 02185 02186 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02187 if (option_verbose > 1) 02188 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02189 } 02190 AST_LIST_UNLOCK(&agents); 02191 if (!res) 02192 res = ast_safe_sleep(chan, 500); 02193 ast_mutex_unlock(&p->lock); 02194 } else if (!res) { 02195 ast_indicate_data(chan, AST_CONTROL_HOLD, 02196 S_OR(p->moh, NULL), 02197 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02198 if (p->loginstart == 0) 02199 time(&p->loginstart); 02200 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02201 "Agent: %s\r\n" 02202 "Channel: %s\r\n" 02203 "Uniqueid: %s\r\n", 02204 p->agent, chan->name, chan->uniqueid); 02205 if (update_cdr && chan->cdr) 02206 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02207 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02208 if (option_verbose > 1) 02209 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02210 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02211 /* Login this channel and wait for it to go away */ 02212 p->chan = chan; 02213 if (p->ackcall > 1) 02214 check_beep(p, 0); 02215 else 02216 check_availability(p, 0); 02217 ast_mutex_unlock(&p->lock); 02218 AST_LIST_UNLOCK(&agents); 02219 ast_device_state_changed("Agent/%s", p->agent); 02220 while (res >= 0) { 02221 ast_mutex_lock(&p->lock); 02222 if (p->deferlogoff && p->chan) { 02223 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02224 p->deferlogoff = 0; 02225 } 02226 if (p->chan != chan) 02227 res = -1; 02228 ast_mutex_unlock(&p->lock); 02229 /* Yield here so other interested threads can kick in. */ 02230 sched_yield(); 02231 if (res) 02232 break; 02233 02234 AST_LIST_LOCK(&agents); 02235 ast_mutex_lock(&p->lock); 02236 if (p->lastdisc.tv_sec) { 02237 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02238 if (option_debug) 02239 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02240 p->lastdisc = ast_tv(0, 0); 02241 ast_device_state_changed("Agent/%s", p->agent); 02242 if (p->ackcall > 1) 02243 check_beep(p, 0); 02244 else 02245 check_availability(p, 0); 02246 } 02247 } 02248 ast_mutex_unlock(&p->lock); 02249 AST_LIST_UNLOCK(&agents); 02250 /* Synchronize channel ownership between call to agent and itself. */ 02251 ast_mutex_lock( &p->app_lock ); 02252 ast_mutex_lock(&p->lock); 02253 p->owning_app = pthread_self(); 02254 ast_mutex_unlock(&p->lock); 02255 if (p->ackcall > 1) 02256 res = agent_ack_sleep(p); 02257 else 02258 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02259 ast_mutex_unlock( &p->app_lock ); 02260 if ((p->ackcall > 1) && (res == 1)) { 02261 AST_LIST_LOCK(&agents); 02262 ast_mutex_lock(&p->lock); 02263 check_availability(p, 0); 02264 ast_mutex_unlock(&p->lock); 02265 AST_LIST_UNLOCK(&agents); 02266 res = 0; 02267 } 02268 sched_yield(); 02269 } 02270 ast_mutex_lock(&p->lock); 02271 if (res && p->owner) 02272 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02273 /* Log us off if appropriate */ 02274 if (p->chan == chan) { 02275 p->chan = NULL; 02276 p->inherited_devicestate = -1; 02277 } 02278 p->acknowledged = 0; 02279 logintime = time(NULL) - p->loginstart; 02280 p->loginstart = 0; 02281 ast_mutex_unlock(&p->lock); 02282 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02283 "Agent: %s\r\n" 02284 "Logintime: %ld\r\n" 02285 "Uniqueid: %s\r\n", 02286 p->agent, logintime, chan->uniqueid); 02287 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02288 if (option_verbose > 1) 02289 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02290 /* If there is no owner, go ahead and kill it now */ 02291 ast_device_state_changed("Agent/%s", p->agent); 02292 if (p->dead && !p->owner) { 02293 ast_mutex_destroy(&p->lock); 02294 ast_mutex_destroy(&p->app_lock); 02295 free(p); 02296 } 02297 } 02298 else { 02299 ast_mutex_unlock(&p->lock); 02300 p = NULL; 02301 } 02302 res = -1; 02303 } else { 02304 ast_mutex_unlock(&p->lock); 02305 errmsg = "agent-alreadyon"; 02306 p = NULL; 02307 } 02308 break; 02309 } 02310 ast_mutex_unlock(&p->lock); 02311 if (unlock_channel) { 02312 ast_channel_unlock(chan); 02313 } 02314 } 02315 if (!p) 02316 AST_LIST_UNLOCK(&agents); 02317 02318 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02319 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02320 } 02321 02322 if (!res) 02323 res = ast_safe_sleep(chan, 500); 02324 02325 /* AgentLogin() exit */ 02326 if (!callbackmode) { 02327 ast_module_user_remove(u); 02328 return -1; 02329 } else { /* AgentCallbackLogin() exit*/ 02330 /* Set variables */ 02331 if (login_state > 0) { 02332 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user); 02333 if (login_state==1) { 02334 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on"); 02335 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension); 02336 } else 02337 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off"); 02338 } else { 02339 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail"); 02340 } 02341 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) { 02342 ast_module_user_remove(u); 02343 return 0; 02344 } 02345 /* Do we need to play agent-goodbye now that we will be hanging up? */ 02346 if (play_announcement) { 02347 if (!res) 02348 res = ast_safe_sleep(chan, 1000); 02349 res = ast_streamfile(chan, agent_goodbye, chan->language); 02350 if (!res) 02351 res = ast_waitstream(chan, ""); 02352 if (!res) 02353 res = ast_safe_sleep(chan, 1000); 02354 } 02355 } 02356 02357 ast_module_user_remove(u); 02358 02359 /* We should never get here if next priority exists when in callbackmode */ 02360 return -1; 02361 }
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 2412 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, 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, s, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.
Referenced by load_module().
02413 { 02414 const char *agent = astman_get_header(m, "Agent"); 02415 const char *exten = astman_get_header(m, "Exten"); 02416 const char *context = astman_get_header(m, "Context"); 02417 const char *wrapuptime_s = astman_get_header(m, "WrapupTime"); 02418 const char *ackcall_s = astman_get_header(m, "AckCall"); 02419 struct agent_pvt *p; 02420 int login_state = 0; 02421 02422 callback_deprecated(); 02423 02424 if (ast_strlen_zero(agent)) { 02425 astman_send_error(s, m, "No agent specified"); 02426 return 0; 02427 } 02428 02429 if (ast_strlen_zero(exten)) { 02430 astman_send_error(s, m, "No extension specified"); 02431 return 0; 02432 } 02433 02434 AST_LIST_LOCK(&agents); 02435 AST_LIST_TRAVERSE(&agents, p, list) { 02436 if (strcmp(p->agent, agent) || p->pending) 02437 continue; 02438 if (p->chan) { 02439 login_state = 2; /* already logged in (and on the phone)*/ 02440 break; 02441 } 02442 ast_mutex_lock(&p->lock); 02443 login_state = 1; /* Successful Login */ 02444 02445 if (ast_strlen_zero(context)) 02446 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan)); 02447 else 02448 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context); 02449 02450 if (!ast_strlen_zero(wrapuptime_s)) { 02451 p->wrapuptime = atoi(wrapuptime_s); 02452 if (p->wrapuptime < 0) 02453 p->wrapuptime = 0; 02454 } 02455 02456 if (strcasecmp(ackcall_s, "always")) 02457 p->ackcall = 2; 02458 else if (ast_true(ackcall_s)) 02459 p->ackcall = 1; 02460 else 02461 p->ackcall = 0; 02462 02463 if (p->loginstart == 0) 02464 time(&p->loginstart); 02465 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02466 "Agent: %s\r\n" 02467 "Loginchan: %s\r\n", 02468 p->agent, p->loginchan); 02469 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02470 if (option_verbose > 1) 02471 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02472 ast_device_state_changed("Agent/%s", p->agent); 02473 ast_mutex_unlock(&p->lock); 02474 if (persistent_agents) 02475 dump_agents(); 02476 } 02477 AST_LIST_UNLOCK(&agents); 02478 02479 if (login_state == 1) 02480 astman_send_ack(s, m, "Agent logged in"); 02481 else if (login_state == 0) 02482 astman_send_error(s, m, "No such agent"); 02483 else if (login_state == 2) 02484 astman_send_error(s, m, "Agent already logged in"); 02485 02486 return 0; 02487 }
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 1706 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and s.
Referenced by load_module().
01707 { 01708 const char *agent = astman_get_header(m, "Agent"); 01709 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01710 int soft; 01711 int ret; /* return value of agent_logoff */ 01712 01713 if (ast_strlen_zero(agent)) { 01714 astman_send_error(s, m, "No agent specified"); 01715 return 0; 01716 } 01717 01718 soft = ast_true(soft_s) ? 1 : 0; 01719 ret = agent_logoff(agent, soft); 01720 if (ret == 0) 01721 astman_send_ack(s, m, "Agent logged out"); 01722 else 01723 astman_send_error(s, m, "No such agent"); 01724 01725 return 0; 01726 }
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 1519 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, S_OR, and username.
Referenced by load_module().
01520 { 01521 const char *id = astman_get_header(m,"ActionID"); 01522 char idText[256] = ""; 01523 char chanbuf[256]; 01524 struct agent_pvt *p; 01525 char *username = NULL; 01526 char *loginChan = NULL; 01527 char *talkingtoChan = NULL; 01528 char *status = NULL; 01529 01530 if (!ast_strlen_zero(id)) 01531 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01532 astman_send_ack(s, m, "Agents will follow"); 01533 AST_LIST_LOCK(&agents); 01534 AST_LIST_TRAVERSE(&agents, p, list) { 01535 ast_mutex_lock(&p->lock); 01536 01537 /* Status Values: 01538 AGENT_LOGGEDOFF - Agent isn't logged in 01539 AGENT_IDLE - Agent is logged in, and waiting for call 01540 AGENT_ONCALL - Agent is logged in, and on a call 01541 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01542 01543 username = S_OR(p->name, "None"); 01544 01545 /* Set a default status. It 'should' get changed. */ 01546 status = "AGENT_UNKNOWN"; 01547 01548 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01549 loginChan = p->loginchan; 01550 talkingtoChan = "n/a"; 01551 status = "AGENT_IDLE"; 01552 if (p->acknowledged) { 01553 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01554 loginChan = chanbuf; 01555 } 01556 } else if (p->chan) { 01557 loginChan = ast_strdupa(p->chan->name); 01558 if (p->owner && p->owner->_bridge) { 01559 if (ast_bridged_channel(p->owner)) { 01560 talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, "")); 01561 } else { 01562 talkingtoChan = "n/a"; 01563 } 01564 status = "AGENT_ONCALL"; 01565 } else { 01566 talkingtoChan = "n/a"; 01567 status = "AGENT_IDLE"; 01568 } 01569 } else { 01570 loginChan = "n/a"; 01571 talkingtoChan = "n/a"; 01572 status = "AGENT_LOGGEDOFF"; 01573 } 01574 01575 astman_append(s, "Event: Agents\r\n" 01576 "Agent: %s\r\n" 01577 "Name: %s\r\n" 01578 "Status: %s\r\n" 01579 "LoggedInChan: %s\r\n" 01580 "LoggedInTime: %d\r\n" 01581 "TalkingTo: %s\r\n" 01582 "%s" 01583 "\r\n", 01584 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); 01585 ast_mutex_unlock(&p->lock); 01586 } 01587 AST_LIST_UNLOCK(&agents); 01588 astman_append(s, "Event: AgentsComplete\r\n" 01589 "%s" 01590 "\r\n",idText); 01591 return 0; 01592 }
static struct agent_pvt* add_agent | ( | char * | agent, | |
int | pending | |||
) | [static] |
Adds an agent to the global list of agents.
agent | A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" | |
pending | If it is pending or not. |
Definition at line 333 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, AST_APP_ARG, ast_calloc, 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(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::lastdisc, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00334 { 00335 char *parse; 00336 AST_DECLARE_APP_ARGS(args, 00337 AST_APP_ARG(agt); 00338 AST_APP_ARG(password); 00339 AST_APP_ARG(name); 00340 ); 00341 char *password = NULL; 00342 char *name = NULL; 00343 char *agt = NULL; 00344 struct agent_pvt *p; 00345 00346 parse = ast_strdupa(agent); 00347 00348 /* Extract username (agt), password and name from agent (args). */ 00349 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 00350 00351 if(args.argc == 0) { 00352 ast_log(LOG_WARNING, "A blank agent line!\n"); 00353 return NULL; 00354 } 00355 00356 if(ast_strlen_zero(args.agt) ) { 00357 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00358 return NULL; 00359 } else 00360 agt = args.agt; 00361 00362 if(!ast_strlen_zero(args.password)) { 00363 password = args.password; 00364 while (*password && *password < 33) password++; 00365 } 00366 if(!ast_strlen_zero(args.name)) { 00367 name = args.name; 00368 while (*name && *name < 33) name++; 00369 } 00370 00371 /* Are we searching for the agent here ? To see if it exists already ? */ 00372 AST_LIST_TRAVERSE(&agents, p, list) { 00373 if (!pending && !strcmp(p->agent, agt)) 00374 break; 00375 } 00376 if (!p) { 00377 // Build the agent. 00378 if (!(p = ast_calloc(1, sizeof(*p)))) 00379 return NULL; 00380 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00381 ast_mutex_init(&p->lock); 00382 ast_mutex_init(&p->app_lock); 00383 p->owning_app = (pthread_t) -1; 00384 p->app_sleep_cond = 1; 00385 p->group = group; 00386 p->pending = pending; 00387 p->inherited_devicestate = -1; 00388 AST_LIST_INSERT_TAIL(&agents, p, list); 00389 } 00390 00391 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00392 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00393 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00394 p->ackcall = ackcall; 00395 p->autologoff = autologoff; 00396 00397 /* If someone reduces the wrapuptime and reloads, we want it 00398 * to change the wrapuptime immediately on all calls */ 00399 if (p->wrapuptime > wrapuptime) { 00400 struct timeval now = ast_tvnow(); 00401 /* XXX check what is this exactly */ 00402 00403 /* We won't be pedantic and check the tv_usec val */ 00404 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00405 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00406 p->lastdisc.tv_usec = now.tv_usec; 00407 } 00408 } 00409 p->wrapuptime = wrapuptime; 00410 00411 if (pending) 00412 p->dead = 1; 00413 else 00414 p->dead = 0; 00415 return p; 00416 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 963 of file chan_agent.c.
References agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, f, and agent_pvt::lock.
Referenced by __login_exec().
00964 { 00965 struct agent_pvt *p; 00966 int res=0; 00967 int to = 1000; 00968 struct ast_frame *f; 00969 00970 /* Wait a second and look for something */ 00971 00972 p = (struct agent_pvt *) data; 00973 if (!p->chan) 00974 return -1; 00975 00976 for(;;) { 00977 to = ast_waitfor(p->chan, to); 00978 if (to < 0) 00979 return -1; 00980 if (!to) 00981 return 0; 00982 f = ast_read(p->chan); 00983 if (!f) 00984 return -1; 00985 if (f->frametype == AST_FRAME_DTMF) 00986 res = f->subclass; 00987 else 00988 res = 0; 00989 ast_frfree(f); 00990 ast_mutex_lock(&p->lock); 00991 if (!p->app_sleep_cond) { 00992 ast_mutex_unlock(&p->lock); 00993 return 0; 00994 } else if (res == '#') { 00995 ast_mutex_unlock(&p->lock); 00996 return 1; 00997 } 00998 ast_mutex_unlock(&p->lock); 00999 res = 0; 01000 } 01001 return res; 01002 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 444 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00445 { 00446 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00447 return -1; 00448 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Definition at line 1004 of file chan_agent.c.
References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.
01005 { 01006 struct agent_pvt *p = bridge->tech_pvt; 01007 struct ast_channel *ret = NULL; 01008 01009 if (p) { 01010 if (chan == p->chan) 01011 ret = bridge->_bridge; 01012 else if (chan == bridge->_bridge) 01013 ret = p->chan; 01014 } 01015 01016 if (option_debug) 01017 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 01018 return ret; 01019 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 699 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_NOTICE, 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.
00700 { 00701 struct agent_pvt *p = ast->tech_pvt; 00702 int res = -1; 00703 int newstate=0; 00704 ast_mutex_lock(&p->lock); 00705 p->acknowledged = 0; 00706 if (!p->chan) { 00707 if (p->pending) { 00708 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00709 newstate = AST_STATE_DIALING; 00710 res = 0; 00711 } else { 00712 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00713 res = -1; 00714 } 00715 ast_mutex_unlock(&p->lock); 00716 if (newstate) 00717 ast_setstate(ast, newstate); 00718 return res; 00719 } else if (!ast_strlen_zero(p->loginchan)) { 00720 time(&p->start); 00721 /* Call on this agent */ 00722 if (option_verbose > 2) 00723 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00724 ast_set_callerid(p->chan, 00725 ast->cid.cid_num, ast->cid.cid_name, NULL); 00726 ast_channel_inherit_variables(ast, p->chan); 00727 res = ast_call(p->chan, p->loginchan, 0); 00728 CLEANUP(ast,p); 00729 ast_mutex_unlock(&p->lock); 00730 return res; 00731 } 00732 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00733 if (option_debug > 2) 00734 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language); 00735 res = ast_streamfile(p->chan, beep, p->chan->language); 00736 if (option_debug > 2) 00737 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 00738 if (!res) { 00739 res = ast_waitstream(p->chan, ""); 00740 if (option_debug > 2) 00741 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 00742 } 00743 if (!res) { 00744 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00745 if (option_debug > 2) 00746 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res); 00747 if (res) 00748 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00749 } else { 00750 /* Agent hung-up */ 00751 p->chan = NULL; 00752 p->inherited_devicestate = -1; 00753 ast_device_state_changed("Agent/%s", p->agent); 00754 } 00755 00756 if (!res) { 00757 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00758 if (option_debug > 2) 00759 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res); 00760 if (res) 00761 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00762 } 00763 if(!res) { 00764 /* Call is immediately up, or might need ack */ 00765 if (p->ackcall > 1) 00766 newstate = AST_STATE_RINGING; 00767 else { 00768 newstate = AST_STATE_UP; 00769 if (recordagentcalls) 00770 agent_start_monitoring(ast, 0); 00771 p->acknowledged = 1; 00772 } 00773 res = 0; 00774 } 00775 CLEANUP(ast, p); 00776 ast_mutex_unlock(&p->lock); 00777 if (newstate) 00778 ast_setstate(ast, newstate); 00779 return res; 00780 }
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 424 of file chan_agent.c.
References agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_free(), ast_mutex_destroy(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00425 { 00426 struct ast_channel *chan = p->owner; 00427 p->owner = NULL; 00428 chan->tech_pvt = NULL; 00429 p->app_sleep_cond = 1; 00430 /* Release ownership of the agent to other threads (presumably running the login app). */ 00431 ast_mutex_unlock(&p->app_lock); 00432 if (chan) 00433 ast_channel_free(chan); 00434 if (p->dead) { 00435 ast_mutex_destroy(&p->lock); 00436 ast_mutex_destroy(&p->app_lock); 00437 free(p); 00438 } 00439 return 0; 00440 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 942 of file chan_agent.c.
References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, and option_debug.
Referenced by __login_exec().
00943 { 00944 struct agent_pvt *p; 00945 int res; 00946 00947 p = (struct agent_pvt *)data; 00948 00949 ast_mutex_lock(&p->lock); 00950 res = p->app_sleep_cond; 00951 if (p->lastdisc.tv_sec) { 00952 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 00953 res = 1; 00954 } 00955 ast_mutex_unlock(&p->lock); 00956 00957 if(option_debug > 4 && !res ) 00958 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res ); 00959 00960 return res; 00961 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2633 of file chan_agent.c.
References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::inherited_devicestate, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
02634 { 02635 struct agent_pvt *p; 02636 char *s; 02637 ast_group_t groupmatch; 02638 int groupoff; 02639 int waitforagent=0; 02640 int res = AST_DEVICE_INVALID; 02641 02642 s = data; 02643 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) 02644 groupmatch = (1 << groupoff); 02645 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 02646 groupmatch = (1 << groupoff); 02647 waitforagent = 1; 02648 } else 02649 groupmatch = 0; 02650 02651 /* Check actual logged in agents first */ 02652 AST_LIST_LOCK(&agents); 02653 AST_LIST_TRAVERSE(&agents, p, list) { 02654 ast_mutex_lock(&p->lock); 02655 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02656 if (p->owner) { 02657 if (res != AST_DEVICE_INUSE) 02658 res = AST_DEVICE_BUSY; 02659 } else if (p->inherited_devicestate > -1) { 02660 res = p->inherited_devicestate; 02661 } else { 02662 if (res == AST_DEVICE_BUSY) 02663 res = AST_DEVICE_INUSE; 02664 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02665 if (res == AST_DEVICE_INVALID) 02666 res = AST_DEVICE_UNKNOWN; 02667 } else if (res == AST_DEVICE_INVALID) 02668 res = AST_DEVICE_UNAVAILABLE; 02669 } 02670 if (!strcmp(data, p->agent)) { 02671 ast_mutex_unlock(&p->lock); 02672 break; 02673 } 02674 } 02675 ast_mutex_unlock(&p->lock); 02676 } 02677 AST_LIST_UNLOCK(&agents); 02678 return res; 02679 }
static int agent_devicestate_cb | ( | const char * | dev, | |
int | state, | |||
void * | data | |||
) | [static] |
Definition at line 286 of file chan_agent.c.
References agent_pvt::agent, AST_CHANNEL_NAME, ast_device_state_changed(), AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::inherited_devicestate, and agent_pvt::lock.
Referenced by load_module(), and unload_module().
00287 { 00288 int res, i; 00289 struct agent_pvt *p; 00290 char basename[AST_CHANNEL_NAME], *tmp; 00291 00292 /* Skip Agent status */ 00293 if (!strncasecmp(dev, "Agent/", 6)) { 00294 return 0; 00295 } 00296 00297 /* Try to be safe, but don't deadlock */ 00298 for (i = 0; i < 10; i++) { 00299 if ((res = AST_LIST_TRYLOCK(&agents)) == 0) { 00300 break; 00301 } 00302 } 00303 if (res) { 00304 return -1; 00305 } 00306 00307 AST_LIST_TRAVERSE(&agents, p, list) { 00308 ast_mutex_lock(&p->lock); 00309 if (p->chan) { 00310 ast_copy_string(basename, p->chan->name, sizeof(basename)); 00311 if ((tmp = strrchr(basename, '-'))) { 00312 *tmp = '\0'; 00313 } 00314 if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) { 00315 p->inherited_devicestate = state; 00316 ast_device_state_changed("Agent/%s", p->agent); 00317 } 00318 } 00319 ast_mutex_unlock(&p->lock); 00320 } 00321 AST_LIST_UNLOCK(&agents); 00322 return 0; 00323 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 677 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.
00678 { 00679 struct agent_pvt *p = ast->tech_pvt; 00680 ast_mutex_lock(&p->lock); 00681 if (p->chan) { 00682 ast_senddigit_begin(p->chan, digit); 00683 } 00684 ast_mutex_unlock(&p->lock); 00685 return 0; 00686 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 688 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.
00689 { 00690 struct agent_pvt *p = ast->tech_pvt; 00691 ast_mutex_lock(&p->lock); 00692 if (p->chan) { 00693 ast_senddigit_end(p->chan, digit, duration); 00694 } 00695 ast_mutex_unlock(&p->lock); 00696 return 0; 00697 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 650 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.
00651 { 00652 struct agent_pvt *p = newchan->tech_pvt; 00653 ast_mutex_lock(&p->lock); 00654 if (p->owner != oldchan) { 00655 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00656 ast_mutex_unlock(&p->lock); 00657 return -1; 00658 } 00659 p->owner = newchan; 00660 ast_mutex_unlock(&p->lock); 00661 return 0; 00662 }
struct ast_channel * agent_get_base_channel | ( | struct ast_channel * | chan | ) | [static] |
return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
Definition at line 796 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00797 { 00798 struct agent_pvt *p = NULL; 00799 struct ast_channel *base = chan; 00800 00801 /* chan is locked by the calling function */ 00802 if (!chan || !chan->tech_pvt) { 00803 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); 00804 return NULL; 00805 } 00806 p = chan->tech_pvt; 00807 if (p->chan) 00808 base = p->chan; 00809 return base; 00810 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 829 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_lock, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, 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_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), 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::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.
00830 { 00831 struct agent_pvt *p = ast->tech_pvt; 00832 int howlong = 0; 00833 const char *status; 00834 ast_mutex_lock(&p->lock); 00835 p->owner = NULL; 00836 ast->tech_pvt = NULL; 00837 p->app_sleep_cond = 1; 00838 p->acknowledged = 0; 00839 00840 /* if they really are hung up then set start to 0 so the test 00841 * later if we're called on an already downed channel 00842 * doesn't cause an agent to be logged out like when 00843 * agent_request() is followed immediately by agent_hangup() 00844 * as in apps/app_chanisavail.c:chanavail_exec() 00845 */ 00846 00847 if (option_debug) 00848 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00849 if (p->start && (ast->_state != AST_STATE_UP)) { 00850 howlong = time(NULL) - p->start; 00851 p->start = 0; 00852 } else if (ast->_state == AST_STATE_RESERVED) 00853 howlong = 0; 00854 else 00855 p->start = 0; 00856 if (p->chan) { 00857 p->chan->_bridge = NULL; 00858 /* If they're dead, go ahead and hang up on the agent now */ 00859 if (!ast_strlen_zero(p->loginchan)) { 00860 /* Store last disconnect time */ 00861 if (p->wrapuptime) 00862 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00863 else 00864 p->lastdisc = ast_tv(0,0); 00865 if (p->chan) { 00866 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00867 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00868 long logintime = time(NULL) - p->loginstart; 00869 p->loginstart = 0; 00870 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00871 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00872 } 00873 /* Recognize the hangup and pass it along immediately */ 00874 ast_hangup(p->chan); 00875 p->chan = NULL; 00876 p->inherited_devicestate = -1; 00877 ast_device_state_changed("Agent/%s", p->agent); 00878 } 00879 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00880 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00881 long logintime = time(NULL) - p->loginstart; 00882 p->loginstart = 0; 00883 if (!p->deferlogoff) 00884 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00885 p->deferlogoff = 0; 00886 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00887 if (persistent_agents) 00888 dump_agents(); 00889 } 00890 } else if (p->dead) { 00891 ast_channel_lock(p->chan); 00892 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00893 ast_channel_unlock(p->chan); 00894 } else if (p->loginstart) { 00895 ast_channel_lock(p->chan); 00896 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00897 S_OR(p->moh, NULL), 00898 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00899 ast_channel_unlock(p->chan); 00900 } 00901 } 00902 ast_mutex_unlock(&p->lock); 00903 00904 /* Only register a device state change if the agent is still logged in */ 00905 if (!p->loginstart) { 00906 p->loginchan[0] = '\0'; 00907 p->logincallerid[0] = '\0'; 00908 if (persistent_agents) 00909 dump_agents(); 00910 } else { 00911 ast_device_state_changed("Agent/%s", p->agent); 00912 } 00913 00914 if (p->pending) { 00915 AST_LIST_LOCK(&agents); 00916 AST_LIST_REMOVE(&agents, p, list); 00917 AST_LIST_UNLOCK(&agents); 00918 } 00919 if (p->abouttograb) { 00920 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00921 kill it later */ 00922 p->abouttograb = 0; 00923 } else if (p->dead) { 00924 ast_mutex_destroy(&p->lock); 00925 ast_mutex_destroy(&p->app_lock); 00926 free(p); 00927 } else { 00928 if (p->chan) { 00929 /* Not dead -- check availability now */ 00930 ast_mutex_lock(&p->lock); 00931 /* Store last disconnect time */ 00932 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00933 ast_mutex_unlock(&p->lock); 00934 } 00935 /* Release ownership of the agent to other threads (presumably running the login app). */ 00936 if (ast_strlen_zero(p->loginchan)) 00937 ast_mutex_unlock(&p->app_lock); 00938 } 00939 return 0; 00940 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 664 of file chan_agent.c.
References ast_check_hangup(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, ast_channel::tech, and ast_channel::tech_pvt.
00665 { 00666 struct agent_pvt *p = ast->tech_pvt; 00667 int res = -1; 00668 ast_mutex_lock(&p->lock); 00669 if (p->chan && !ast_check_hangup(p->chan)) 00670 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00671 else 00672 res = 0; 00673 ast_mutex_unlock(&p->lock); 00674 return res; 00675 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1634 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().
01635 { 01636 struct agent_pvt *p; 01637 long logintime; 01638 int ret = -1; /* Return -1 if no agent if found */ 01639 01640 AST_LIST_LOCK(&agents); 01641 AST_LIST_TRAVERSE(&agents, p, list) { 01642 if (!strcasecmp(p->agent, agent)) { 01643 ret = 0; 01644 if (p->owner || p->chan) { 01645 if (!soft) { 01646 ast_mutex_lock(&p->lock); 01647 01648 while (p->owner && ast_channel_trylock(p->owner)) { 01649 DEADLOCK_AVOIDANCE(&p->lock); 01650 } 01651 if (p->owner) { 01652 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01653 ast_channel_unlock(p->owner); 01654 } 01655 01656 while (p->chan && ast_channel_trylock(p->chan)) { 01657 DEADLOCK_AVOIDANCE(&p->lock); 01658 } 01659 if (p->chan) { 01660 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01661 ast_channel_unlock(p->chan); 01662 } 01663 01664 ast_mutex_unlock(&p->lock); 01665 } else 01666 p->deferlogoff = 1; 01667 } else { 01668 logintime = time(NULL) - p->loginstart; 01669 p->loginstart = 0; 01670 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01671 } 01672 break; 01673 } 01674 } 01675 AST_LIST_UNLOCK(&agents); 01676 01677 return ret; 01678 }
static int agent_logoff_cmd | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1680 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01681 { 01682 int ret; 01683 char *agent; 01684 01685 if (argc < 3 || argc > 4) 01686 return RESULT_SHOWUSAGE; 01687 if (argc == 4 && strcasecmp(argv[3], "soft")) 01688 return RESULT_SHOWUSAGE; 01689 01690 agent = argv[2] + 6; 01691 ret = agent_logoff(agent, argc == 4); 01692 if (ret == 0) 01693 ast_cli(fd, "Logging out %s\n", agent); 01694 01695 return RESULT_SUCCESS; 01696 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1594 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().
01595 { 01596 char *tmp = NULL; 01597 char agent[AST_MAX_AGENT]; 01598 01599 if (!ast_strlen_zero(logcommand)) 01600 tmp = logcommand; 01601 else 01602 tmp = ast_strdupa(""); 01603 01604 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01605 01606 if (!ast_strlen_zero(uniqueid)) { 01607 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01608 "Agent: %s\r\n" 01609 "Reason: %s\r\n" 01610 "Loginchan: %s\r\n" 01611 "Logintime: %ld\r\n" 01612 "Uniqueid: %s\r\n", 01613 p->agent, tmp, loginchan, logintime, uniqueid); 01614 } else { 01615 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01616 "Agent: %s\r\n" 01617 "Reason: %s\r\n" 01618 "Loginchan: %s\r\n" 01619 "Logintime: %ld\r\n", 01620 p->agent, tmp, loginchan, logintime); 01621 } 01622 01623 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01624 set_agentbycallerid(p->logincallerid, NULL); 01625 p->loginchan[0] ='\0'; 01626 p->logincallerid[0] = '\0'; 01627 p->inherited_devicestate = -1; 01628 ast_device_state_changed("Agent/%s", p->agent); 01629 if (persistent_agents) 01630 dump_agents(); 01631 01632 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static] |
Create new agent channel.
Definition at line 1022 of file chan_agent.c.
References agent_pvt::agent, agent_tech, agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_assert, ast_channel_alloc(), ast_channel_free(), AST_CONTROL_UNHOLD, AST_FLAG_BLOCKING, AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_update_use_count(), agent_pvt::chan, ast_channel::context, ast_channel::exten, language, agent_pvt::lock, LOG_ERROR, LOG_WARNING, agent_pvt::loginchan, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::owning_app, 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().
01023 { 01024 struct ast_channel *tmp; 01025 #if 0 01026 if (!p->chan) { 01027 ast_log(LOG_WARNING, "No channel? :(\n"); 01028 return NULL; 01029 } 01030 #endif 01031 if (p->pending) 01032 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, ast_random() & 0xffff); 01033 else 01034 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 01035 if (!tmp) { 01036 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01037 return NULL; 01038 } 01039 01040 tmp->tech = &agent_tech; 01041 if (p->chan) { 01042 tmp->nativeformats = p->chan->nativeformats; 01043 tmp->writeformat = p->chan->writeformat; 01044 tmp->rawwriteformat = p->chan->writeformat; 01045 tmp->readformat = p->chan->readformat; 01046 tmp->rawreadformat = p->chan->readformat; 01047 ast_string_field_set(tmp, language, p->chan->language); 01048 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01049 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01050 /* XXX Is this really all we copy form the originating channel?? */ 01051 } else { 01052 tmp->nativeformats = AST_FORMAT_SLINEAR; 01053 tmp->writeformat = AST_FORMAT_SLINEAR; 01054 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01055 tmp->readformat = AST_FORMAT_SLINEAR; 01056 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01057 } 01058 /* Safe, agentlock already held */ 01059 tmp->tech_pvt = p; 01060 p->owner = tmp; 01061 /* XXX: this needs fixing */ 01062 #if 0 01063 ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1); 01064 #endif 01065 ast_update_use_count(); 01066 tmp->priority = 1; 01067 /* Wake up and wait for other applications (by definition the login app) 01068 * to release this channel). Takes ownership of the agent channel 01069 * to this thread only. 01070 * For signalling the other thread, ast_queue_frame is used until we 01071 * can safely use signals for this purpose. The pselect() needs to be 01072 * implemented in the kernel for this. 01073 */ 01074 p->app_sleep_cond = 0; 01075 if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) { 01076 if (p->chan) { 01077 ast_queue_frame(p->chan, &ast_null_frame); 01078 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01079 ast_mutex_lock(&p->app_lock); 01080 ast_mutex_lock(&p->lock); 01081 } else { 01082 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01083 p->owner = NULL; 01084 tmp->tech_pvt = NULL; 01085 p->app_sleep_cond = 1; 01086 ast_channel_free( tmp ); 01087 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01088 ast_mutex_unlock(&p->app_lock); 01089 return NULL; 01090 } 01091 } else if (!ast_strlen_zero(p->loginchan)) { 01092 if (p->chan) 01093 ast_queue_frame(p->chan, &ast_null_frame); 01094 if (!p->chan) { 01095 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01096 p->owner = NULL; 01097 tmp->tech_pvt = NULL; 01098 p->app_sleep_cond = 1; 01099 ast_channel_free( tmp ); 01100 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01101 return NULL; 01102 } 01103 } 01104 if (p->chan) 01105 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01106 p->owning_app = pthread_self(); 01107 /* After the above step, there should not be any blockers. */ 01108 if (p->chan) { 01109 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) { 01110 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" ); 01111 ast_assert(ast_test_flag(p->chan, AST_FLAG_BLOCKING) == 0); 01112 } 01113 } 01114 return tmp; 01115 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 483 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_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_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_verbose(), agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, dump_agents(), f, ast_channel::fdno, 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_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
00484 { 00485 struct agent_pvt *p = ast->tech_pvt; 00486 struct ast_frame *f = NULL; 00487 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00488 const char *status; 00489 ast_mutex_lock(&p->lock); 00490 CHECK_FORMATS(ast, p); 00491 if (p->chan) { 00492 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00493 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00494 f = ast_read(p->chan); 00495 } else 00496 f = &ast_null_frame; 00497 if (!f) { 00498 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00499 if (p->chan) { 00500 p->chan->_bridge = NULL; 00501 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00502 for us when the PBX instance that called login finishes */ 00503 if (!ast_strlen_zero(p->loginchan)) { 00504 if (p->chan) 00505 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00506 if (p->owner->_state != AST_STATE_UP) { 00507 int howlong = time(NULL) - p->start; 00508 if (p->autologoff && howlong > p->autologoff) { 00509 long logintime = time(NULL) - p->loginstart; 00510 p->loginstart = 0; 00511 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00512 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00513 if (persistent_agents) 00514 dump_agents(); 00515 } 00516 } 00517 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00518 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00519 long logintime = time(NULL) - p->loginstart; 00520 p->loginstart = 0; 00521 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00522 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00523 } 00524 ast_hangup(p->chan); 00525 if (p->wrapuptime && p->acknowledged) 00526 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00527 } 00528 p->chan = NULL; 00529 p->inherited_devicestate = -1; 00530 ast_device_state_changed("Agent/%s", p->agent); 00531 p->acknowledged = 0; 00532 } 00533 } else { 00534 /* if acknowledgement is not required, and the channel is up, we may have missed 00535 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00536 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) 00537 p->acknowledged = 1; 00538 switch (f->frametype) { 00539 case AST_FRAME_CONTROL: 00540 if (f->subclass == AST_CONTROL_ANSWER) { 00541 if (p->ackcall) { 00542 if (option_verbose > 2) 00543 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 00544 /* Don't pass answer along */ 00545 ast_frfree(f); 00546 f = &ast_null_frame; 00547 } else { 00548 p->acknowledged = 1; 00549 /* Use the builtin answer frame for the 00550 recording start check below. */ 00551 ast_frfree(f); 00552 f = &answer_frame; 00553 } 00554 } 00555 break; 00556 case AST_FRAME_DTMF_BEGIN: 00557 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00558 if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){ 00559 ast_frfree(f); 00560 f = &ast_null_frame; 00561 } 00562 break; 00563 case AST_FRAME_DTMF_END: 00564 if (!p->acknowledged && (f->subclass == '#')) { 00565 if (option_verbose > 2) 00566 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 00567 p->acknowledged = 1; 00568 ast_frfree(f); 00569 f = &answer_frame; 00570 } else if (f->subclass == '*' && endcall) { 00571 /* terminates call */ 00572 ast_frfree(f); 00573 f = NULL; 00574 } 00575 break; 00576 case AST_FRAME_VOICE: 00577 case AST_FRAME_VIDEO: 00578 /* don't pass voice or video until the call is acknowledged */ 00579 if (!p->acknowledged) { 00580 ast_frfree(f); 00581 f = &ast_null_frame; 00582 } 00583 default: 00584 /* pass everything else on through */ 00585 break; 00586 } 00587 } 00588 00589 CLEANUP(ast,p); 00590 if (p->chan && !p->chan->_bridge) { 00591 if (strcasecmp(p->chan->tech->type, "Local")) { 00592 p->chan->_bridge = ast; 00593 if (p->chan) 00594 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00595 } 00596 } 00597 ast_mutex_unlock(&p->lock); 00598 if (recordagentcalls && f == &answer_frame) 00599 agent_start_monitoring(ast,0); 00600 return f; 00601 }
static struct ast_channel * agent_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of the Asterisk PBX interface.
Definition at line 1406 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), AST_STATE_DOWN, ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, option_debug, agent_pvt::owner, agent_pvt::pending, and s.
01407 { 01408 struct agent_pvt *p; 01409 struct ast_channel *chan = NULL; 01410 char *s; 01411 ast_group_t groupmatch; 01412 int groupoff; 01413 int waitforagent=0; 01414 int hasagent = 0; 01415 struct timeval tv; 01416 01417 s = data; 01418 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01419 groupmatch = (1 << groupoff); 01420 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01421 groupmatch = (1 << groupoff); 01422 waitforagent = 1; 01423 } else 01424 groupmatch = 0; 01425 01426 /* Check actual logged in agents first */ 01427 AST_LIST_LOCK(&agents); 01428 AST_LIST_TRAVERSE(&agents, p, list) { 01429 ast_mutex_lock(&p->lock); 01430 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01431 ast_strlen_zero(p->loginchan)) { 01432 if (p->chan) 01433 hasagent++; 01434 tv = ast_tvnow(); 01435 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01436 p->lastdisc = ast_tv(0, 0); 01437 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01438 if (!p->owner && p->chan) { 01439 /* Fixed agent */ 01440 chan = agent_new(p, AST_STATE_DOWN); 01441 } 01442 if (chan) { 01443 ast_mutex_unlock(&p->lock); 01444 break; 01445 } 01446 } 01447 } 01448 ast_mutex_unlock(&p->lock); 01449 } 01450 if (!p) { 01451 AST_LIST_TRAVERSE(&agents, p, list) { 01452 ast_mutex_lock(&p->lock); 01453 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01454 if (p->chan || !ast_strlen_zero(p->loginchan)) 01455 hasagent++; 01456 tv = ast_tvnow(); 01457 #if 0 01458 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec); 01459 #endif 01460 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01461 p->lastdisc = ast_tv(0, 0); 01462 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01463 if (!p->owner && p->chan) { 01464 /* Could still get a fixed agent */ 01465 chan = agent_new(p, AST_STATE_DOWN); 01466 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01467 /* Adjustable agent */ 01468 p->chan = ast_request("Local", format, p->loginchan, cause); 01469 if (p->chan) 01470 chan = agent_new(p, AST_STATE_DOWN); 01471 } 01472 if (chan) { 01473 ast_mutex_unlock(&p->lock); 01474 break; 01475 } 01476 } 01477 } 01478 ast_mutex_unlock(&p->lock); 01479 } 01480 } 01481 01482 if (!chan && waitforagent) { 01483 /* No agent available -- but we're requesting to wait for one. 01484 Allocate a place holder */ 01485 if (hasagent) { 01486 if (option_debug) 01487 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); 01488 p = add_agent(data, 1); 01489 p->group = groupmatch; 01490 chan = agent_new(p, AST_STATE_DOWN); 01491 if (!chan) 01492 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01493 } else 01494 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); 01495 } 01496 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01497 AST_LIST_UNLOCK(&agents); 01498 return chan; 01499 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 603 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.
00604 { 00605 struct agent_pvt *p = ast->tech_pvt; 00606 int res = -1; 00607 ast_mutex_lock(&p->lock); 00608 if (p->chan) 00609 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00610 ast_mutex_unlock(&p->lock); 00611 return res; 00612 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 614 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.
00615 { 00616 struct agent_pvt *p = ast->tech_pvt; 00617 int res = -1; 00618 ast_mutex_lock(&p->lock); 00619 if (p->chan) 00620 res = ast_sendtext(p->chan, text); 00621 ast_mutex_unlock(&p->lock); 00622 return res; 00623 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 812 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00813 { 00814 struct agent_pvt *p = NULL; 00815 00816 if (!chan || !base) { 00817 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00818 return -1; 00819 } 00820 p = chan->tech_pvt; 00821 if (!p) { 00822 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00823 return -1; 00824 } 00825 p->chan = base; 00826 return 0; 00827 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 478 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00479 { 00480 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00481 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 625 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, f, agent_pvt::lock, LOG_DEBUG, ast_channel::tech_pvt, and ast_channel::writeformat.
00626 { 00627 struct agent_pvt *p = ast->tech_pvt; 00628 int res = -1; 00629 CHECK_FORMATS(ast, p); 00630 ast_mutex_lock(&p->lock); 00631 if (!p->chan) 00632 res = 0; 00633 else { 00634 if ((f->frametype != AST_FRAME_VOICE) || 00635 (f->frametype != AST_FRAME_VIDEO) || 00636 (f->subclass == p->chan->writeformat)) { 00637 res = ast_write(p->chan, f); 00638 } else { 00639 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00640 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00641 ast->name, p->chan->name); 00642 res = 0; 00643 } 00644 } 00645 CLEANUP(ast, p); 00646 ast_mutex_unlock(&p->lock); 00647 return res; 00648 }
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 2497 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, 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, agent_pvt::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3.
Referenced by load_module().
02498 { 02499 int exitifnoagentid = 0; 02500 int nowarnings = 0; 02501 int changeoutgoing = 0; 02502 int res = 0; 02503 char agent[AST_MAX_AGENT]; 02504 02505 if (data) { 02506 if (strchr(data, 'd')) 02507 exitifnoagentid = 1; 02508 if (strchr(data, 'n')) 02509 nowarnings = 1; 02510 if (strchr(data, 'c')) 02511 changeoutgoing = 1; 02512 } 02513 if (chan->cid.cid_num) { 02514 const char *tmp; 02515 char agentvar[AST_MAX_BUF]; 02516 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02517 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02518 struct agent_pvt *p; 02519 ast_copy_string(agent, tmp, sizeof(agent)); 02520 AST_LIST_LOCK(&agents); 02521 AST_LIST_TRAVERSE(&agents, p, list) { 02522 if (!strcasecmp(p->agent, tmp)) { 02523 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02524 __agent_start_monitoring(chan, p, 1); 02525 break; 02526 } 02527 } 02528 AST_LIST_UNLOCK(&agents); 02529 02530 } else { 02531 res = -1; 02532 if (!nowarnings) 02533 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); 02534 } 02535 } else { 02536 res = -1; 02537 if (!nowarnings) 02538 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"); 02539 } 02540 /* check if there is n + 101 priority */ 02541 /*! \todo XXX Needs to check option priorityjump etc etc */ 02542 if (res) { 02543 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) { 02544 chan->priority+=100; 02545 if (option_verbose > 2) 02546 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); 02547 } else if (exitifnoagentid) 02548 return res; 02549 } 02550 return 0; 02551 }
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 1755 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::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.
01756 { 01757 struct agent_pvt *p; 01758 char username[AST_MAX_BUF]; 01759 char location[AST_MAX_BUF] = ""; 01760 char talkingto[AST_MAX_BUF] = ""; 01761 char moh[AST_MAX_BUF]; 01762 int count_agents = 0; /*!< Number of agents configured */ 01763 int online_agents = 0; /*!< Number of online agents */ 01764 int offline_agents = 0; /*!< Number of offline agents */ 01765 if (argc != 2) 01766 return RESULT_SHOWUSAGE; 01767 AST_LIST_LOCK(&agents); 01768 AST_LIST_TRAVERSE(&agents, p, list) { 01769 ast_mutex_lock(&p->lock); 01770 if (p->pending) { 01771 if (p->group) 01772 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group)); 01773 else 01774 ast_cli(fd, "-- Pending call to agent %s\n", p->agent); 01775 } else { 01776 if (!ast_strlen_zero(p->name)) 01777 snprintf(username, sizeof(username), "(%s) ", p->name); 01778 else 01779 username[0] = '\0'; 01780 if (p->chan) { 01781 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01782 if (p->owner && ast_bridged_channel(p->owner)) 01783 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01784 else 01785 strcpy(talkingto, " is idle"); 01786 online_agents++; 01787 } else if (!ast_strlen_zero(p->loginchan)) { 01788 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01789 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01790 else 01791 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01792 talkingto[0] = '\0'; 01793 online_agents++; 01794 if (p->acknowledged) 01795 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01796 } else { 01797 strcpy(location, "not logged in"); 01798 talkingto[0] = '\0'; 01799 offline_agents++; 01800 } 01801 if (!ast_strlen_zero(p->moh)) 01802 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01803 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 01804 username, location, talkingto, moh); 01805 count_agents++; 01806 } 01807 ast_mutex_unlock(&p->lock); 01808 } 01809 AST_LIST_UNLOCK(&agents); 01810 if ( !count_agents ) 01811 ast_cli(fd, "No Agents are configured in %s\n",config); 01812 else 01813 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01814 ast_cli(fd, "\n"); 01815 01816 return RESULT_SUCCESS; 01817 }
static int agents_show_online | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1820 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.
01821 { 01822 struct agent_pvt *p; 01823 char username[AST_MAX_BUF]; 01824 char location[AST_MAX_BUF] = ""; 01825 char talkingto[AST_MAX_BUF] = ""; 01826 char moh[AST_MAX_BUF]; 01827 int count_agents = 0; /* Number of agents configured */ 01828 int online_agents = 0; /* Number of online agents */ 01829 int agent_status = 0; /* 0 means offline, 1 means online */ 01830 if (argc != 3) 01831 return RESULT_SHOWUSAGE; 01832 AST_LIST_LOCK(&agents); 01833 AST_LIST_TRAVERSE(&agents, p, list) { 01834 agent_status = 0; /* reset it to offline */ 01835 ast_mutex_lock(&p->lock); 01836 if (!ast_strlen_zero(p->name)) 01837 snprintf(username, sizeof(username), "(%s) ", p->name); 01838 else 01839 username[0] = '\0'; 01840 if (p->chan) { 01841 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01842 if (p->owner && ast_bridged_channel(p->owner)) 01843 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01844 else 01845 strcpy(talkingto, " is idle"); 01846 agent_status = 1; 01847 online_agents++; 01848 } else if (!ast_strlen_zero(p->loginchan)) { 01849 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01850 talkingto[0] = '\0'; 01851 agent_status = 1; 01852 online_agents++; 01853 if (p->acknowledged) 01854 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01855 } 01856 if (!ast_strlen_zero(p->moh)) 01857 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01858 if (agent_status) 01859 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh); 01860 count_agents++; 01861 ast_mutex_unlock(&p->lock); 01862 } 01863 AST_LIST_UNLOCK(&agents); 01864 if (!count_agents) 01865 ast_cli(fd, "No Agents are configured in %s\n", config); 01866 else 01867 ast_cli(fd, "%d agents online\n", online_agents); 01868 ast_cli(fd, "\n"); 01869 return RESULT_SUCCESS; 01870 }
static int allow_multiple_login | ( | char * | chan, | |
char * | context | |||
) | [static] |
Definition at line 1386 of file chan_agent.c.
References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.
Referenced by __login_exec().
01387 { 01388 struct agent_pvt *p; 01389 char loginchan[80]; 01390 01391 if(multiplelogin) 01392 return 1; 01393 if(!chan) 01394 return 0; 01395 01396 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); 01397 01398 AST_LIST_TRAVERSE(&agents, p, list) { 01399 if(!strcasecmp(chan, p->loginchan)) 01400 return 0; 01401 } 01402 return -1; 01403 }
static AST_LIST_HEAD_STATIC | ( | agents | , | |
agent_pvt | ||||
) | [static] |
Holds the list of agents (loaded form agents.conf).
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT | , | |||
"Agent Proxy Channel" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static void callback_deprecated | ( | void | ) | [static] |
Definition at line 2376 of file chan_agent.c.
References ast_log(), depwarning, and LOG_WARNING.
Referenced by action_agent_callback_login(), and callback_exec().
02377 { 02378 static int depwarning = 0; 02379 02380 if (!depwarning) { 02381 depwarning = 1; 02382 02383 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n"); 02384 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n"); 02385 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n"); 02386 } 02387 }
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 2397 of file chan_agent.c.
References __login_exec(), callback_deprecated(), and ast_module_user::chan.
Referenced by load_module().
02398 { 02399 callback_deprecated(); 02400 02401 return __login_exec(chan, data, 1); 02402 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1272 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_FLAG_ZOMBIE, 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().
01273 { 01274 struct ast_channel *chan=NULL, *parent=NULL; 01275 struct agent_pvt *p; 01276 int res; 01277 01278 if (option_debug) 01279 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); 01280 if (needlock) 01281 AST_LIST_LOCK(&agents); 01282 AST_LIST_TRAVERSE(&agents, p, list) { 01283 if (p == newlyavailable) { 01284 continue; 01285 } 01286 ast_mutex_lock(&p->lock); 01287 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01288 if (option_debug) 01289 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01290 /* We found a pending call, time to merge */ 01291 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01292 parent = p->owner; 01293 p->abouttograb = 1; 01294 ast_mutex_unlock(&p->lock); 01295 break; 01296 } 01297 ast_mutex_unlock(&p->lock); 01298 } 01299 if (needlock) 01300 AST_LIST_UNLOCK(&agents); 01301 if (parent && chan) { 01302 if (newlyavailable->ackcall > 1) { 01303 /* Don't do beep here */ 01304 res = 0; 01305 } else { 01306 if (option_debug > 2) 01307 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01308 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01309 if (option_debug > 2) 01310 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01311 if (!res) { 01312 res = ast_waitstream(newlyavailable->chan, ""); 01313 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01314 } 01315 } 01316 if (!res) { 01317 /* Note -- parent may have disappeared */ 01318 if (p->abouttograb) { 01319 newlyavailable->acknowledged = 1; 01320 /* Safe -- agent lock already held */ 01321 ast_setstate(parent, AST_STATE_UP); 01322 ast_setstate(chan, AST_STATE_UP); 01323 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01324 /* Go ahead and mark the channel as a zombie so that masquerade will 01325 destroy it for us, and we need not call ast_hangup */ 01326 ast_mutex_lock(&parent->lock); 01327 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01328 ast_channel_masquerade(parent, chan); 01329 ast_mutex_unlock(&parent->lock); 01330 p->abouttograb = 0; 01331 } else { 01332 if (option_debug) 01333 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); 01334 agent_cleanup(newlyavailable); 01335 } 01336 } else { 01337 if (option_debug) 01338 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); 01339 agent_cleanup(newlyavailable); 01340 } 01341 } 01342 return 0; 01343 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1345 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::agent, 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().
01346 { 01347 struct agent_pvt *p; 01348 int res=0; 01349 01350 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); 01351 if (needlock) 01352 AST_LIST_LOCK(&agents); 01353 AST_LIST_TRAVERSE(&agents, p, list) { 01354 if (p == newlyavailable) { 01355 continue; 01356 } 01357 ast_mutex_lock(&p->lock); 01358 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01359 if (option_debug) 01360 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01361 ast_mutex_unlock(&p->lock); 01362 break; 01363 } 01364 ast_mutex_unlock(&p->lock); 01365 } 01366 if (needlock) 01367 AST_LIST_UNLOCK(&agents); 01368 if (p) { 01369 ast_mutex_unlock(&newlyavailable->lock); 01370 if (option_debug > 2) 01371 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01372 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01373 if (option_debug > 2) 01374 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01375 if (!res) { 01376 res = ast_waitstream(newlyavailable->chan, ""); 01377 if (option_debug) 01378 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01379 } 01380 ast_mutex_lock(&newlyavailable->lock); 01381 } 01382 return res; 01383 }
static char* complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1728 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.
01729 { 01730 char *ret = NULL; 01731 01732 if (pos == 2) { 01733 struct agent_pvt *p; 01734 char name[AST_MAX_AGENT]; 01735 int which = 0, len = strlen(word); 01736 01737 AST_LIST_LOCK(&agents); 01738 AST_LIST_TRAVERSE(&agents, p, list) { 01739 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01740 if (!strncasecmp(word, name, len) && ++which > state) { 01741 ret = ast_strdup(name); 01742 break; 01743 } 01744 } 01745 AST_LIST_UNLOCK(&agents); 01746 } else if (pos == 3 && state == 0) 01747 return ast_strdup("soft"); 01748 01749 return ret; 01750 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2556 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(), agent_logoff_maintenance(), and agent_read().
02557 { 02558 struct agent_pvt *cur_agent = NULL; 02559 char buf[256]; 02560 02561 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02562 if (cur_agent->chan) 02563 continue; 02564 02565 if (!ast_strlen_zero(cur_agent->loginchan)) { 02566 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02567 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02568 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02569 else if (option_debug) 02570 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02571 } else { 02572 /* Delete - no agent or there is an error */ 02573 ast_db_del(pa_family, cur_agent->agent); 02574 } 02575 } 02576 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2684 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02685 { 02686 struct agent_pvt *cur; 02687 02688 AST_LIST_TRAVERSE(&agents, cur, list) { 02689 if (!strcmp(cur->agent, agentid)) 02690 break; 02691 } 02692 02693 return cur; 02694 }
static int function_agent | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2696 of file chan_agent.c.
References agent_pvt::agent, AST_APP_ARG, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_agent(), LOG_WARNING, and parse().
02697 { 02698 char *parse; 02699 AST_DECLARE_APP_ARGS(args, 02700 AST_APP_ARG(agentid); 02701 AST_APP_ARG(item); 02702 ); 02703 char *tmp; 02704 struct agent_pvt *agent; 02705 02706 buf[0] = '\0'; 02707 02708 if (ast_strlen_zero(data)) { 02709 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02710 return -1; 02711 } 02712 02713 parse = ast_strdupa(data); 02714 02715 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02716 if (!args.item) 02717 args.item = "status"; 02718 02719 AST_LIST_LOCK(&agents); 02720 02721 if (!(agent = find_agent(args.agentid))) { 02722 AST_LIST_UNLOCK(&agents); 02723 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02724 return -1; 02725 } 02726 02727 if (!strcasecmp(args.item, "status")) { 02728 char *status = "LOGGEDOUT"; 02729 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02730 status = "LOGGEDIN"; 02731 ast_copy_string(buf, status, len); 02732 } else if (!strcasecmp(args.item, "password")) 02733 ast_copy_string(buf, agent->password, len); 02734 else if (!strcasecmp(args.item, "name")) 02735 ast_copy_string(buf, agent->name, len); 02736 else if (!strcasecmp(args.item, "mohclass")) 02737 ast_copy_string(buf, agent->moh, len); 02738 else if (!strcasecmp(args.item, "channel")) { 02739 if (agent->chan) { 02740 ast_copy_string(buf, agent->chan->name, len); 02741 tmp = strrchr(buf, '-'); 02742 if (tmp) 02743 *tmp = '\0'; 02744 } 02745 } else if (!strcasecmp(args.item, "exten")) 02746 ast_copy_string(buf, agent->loginchan, len); 02747 02748 AST_LIST_UNLOCK(&agents); 02749 02750 return 0; 02751 }
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 2776 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().
02777 { 02778 /* Make sure we can register our agent channel type */ 02779 if (ast_channel_register(&agent_tech)) { 02780 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02781 return -1; 02782 } 02783 /* Read in the config */ 02784 if (!read_agent_config()) 02785 return AST_MODULE_LOAD_DECLINE; 02786 if (persistent_agents) 02787 reload_agents(); 02788 /* Dialplan applications */ 02789 ast_register_application(app, login_exec, synopsis, descrip); 02790 ast_register_application(app2, callback_exec, synopsis2, descrip2); 02791 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02792 02793 /* Manager commands */ 02794 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02795 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02796 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login); 02797 02798 /* CLI Commands */ 02799 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02800 02801 /* Dialplan Functions */ 02802 ast_custom_function_register(&agent_function); 02803 02804 ast_devstate_add(agent_devicestate_cb, NULL); 02805 02806 return 0; 02807 }
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 2371 of file chan_agent.c.
References __login_exec(), and ast_module_user::chan.
Referenced by load_module().
02372 { 02373 return __login_exec(chan, data, 0); 02374 }
static force_inline int powerof | ( | unsigned int | d | ) | [static] |
static int read_agent_config | ( | void | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1123 of file chan_agent.c.
References add_agent(), agent_pvt::app_lock, ast_category_browse(), ast_config_destroy(), ast_config_load(), 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, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01124 { 01125 struct ast_config *cfg; 01126 struct ast_config *ucfg; 01127 struct ast_variable *v; 01128 struct agent_pvt *p; 01129 const char *general_val; 01130 const char *catname; 01131 const char *hasagent; 01132 int genhasagent; 01133 01134 group = 0; 01135 autologoff = 0; 01136 wrapuptime = 0; 01137 ackcall = 0; 01138 endcall = 1; 01139 cfg = ast_config_load(config); 01140 if (!cfg) { 01141 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01142 return 0; 01143 } 01144 AST_LIST_LOCK(&agents); 01145 AST_LIST_TRAVERSE(&agents, p, list) { 01146 p->dead = 1; 01147 } 01148 strcpy(moh, "default"); 01149 /* set the default recording values */ 01150 recordagentcalls = 0; 01151 strcpy(recordformat, "wav"); 01152 strcpy(recordformatext, "wav"); 01153 urlprefix[0] = '\0'; 01154 savecallsin[0] = '\0'; 01155 01156 /* Read in [general] section for persistence */ 01157 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01158 persistent_agents = ast_true(general_val); 01159 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01160 01161 /* Read in the [agents] section */ 01162 v = ast_variable_browse(cfg, "agents"); 01163 while(v) { 01164 /* Create the interface list */ 01165 if (!strcasecmp(v->name, "agent")) { 01166 add_agent(v->value, 0); 01167 } else if (!strcasecmp(v->name, "group")) { 01168 group = ast_get_group(v->value); 01169 } else if (!strcasecmp(v->name, "autologoff")) { 01170 autologoff = atoi(v->value); 01171 if (autologoff < 0) 01172 autologoff = 0; 01173 } else if (!strcasecmp(v->name, "ackcall")) { 01174 if (!strcasecmp(v->value, "always")) 01175 ackcall = 2; 01176 else if (ast_true(v->value)) 01177 ackcall = 1; 01178 else 01179 ackcall = 0; 01180 } else if (!strcasecmp(v->name, "endcall")) { 01181 endcall = ast_true(v->value); 01182 } else if (!strcasecmp(v->name, "wrapuptime")) { 01183 wrapuptime = atoi(v->value); 01184 if (wrapuptime < 0) 01185 wrapuptime = 0; 01186 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01187 maxlogintries = atoi(v->value); 01188 if (maxlogintries < 0) 01189 maxlogintries = 0; 01190 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01191 strcpy(agentgoodbye,v->value); 01192 } else if (!strcasecmp(v->name, "musiconhold")) { 01193 ast_copy_string(moh, v->value, sizeof(moh)); 01194 } else if (!strcasecmp(v->name, "updatecdr")) { 01195 if (ast_true(v->value)) 01196 updatecdr = 1; 01197 else 01198 updatecdr = 0; 01199 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01200 if (ast_true(v->value)) 01201 autologoffunavail = 1; 01202 else 01203 autologoffunavail = 0; 01204 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01205 recordagentcalls = ast_true(v->value); 01206 } else if (!strcasecmp(v->name, "recordformat")) { 01207 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01208 if (!strcasecmp(v->value, "wav49")) 01209 strcpy(recordformatext, "WAV"); 01210 else 01211 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01212 } else if (!strcasecmp(v->name, "urlprefix")) { 01213 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01214 if (urlprefix[strlen(urlprefix) - 1] != '/') 01215 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01216 } else if (!strcasecmp(v->name, "savecallsin")) { 01217 if (v->value[0] == '/') 01218 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01219 else 01220 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01221 if (savecallsin[strlen(savecallsin) - 1] != '/') 01222 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01223 } else if (!strcasecmp(v->name, "custom_beep")) { 01224 ast_copy_string(beep, v->value, sizeof(beep)); 01225 } 01226 v = v->next; 01227 } 01228 if ((ucfg = ast_config_load("users.conf"))) { 01229 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01230 catname = ast_category_browse(ucfg, NULL); 01231 while(catname) { 01232 if (strcasecmp(catname, "general")) { 01233 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01234 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01235 char tmp[256]; 01236 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01237 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01238 if (!fullname) 01239 fullname = ""; 01240 if (!secret) 01241 secret = ""; 01242 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01243 add_agent(tmp, 0); 01244 } 01245 } 01246 catname = ast_category_browse(ucfg, catname); 01247 } 01248 ast_config_destroy(ucfg); 01249 } 01250 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01251 if (p->dead) { 01252 AST_LIST_REMOVE_CURRENT(&agents, list); 01253 /* Destroy if appropriate */ 01254 if (!p->owner) { 01255 if (!p->chan) { 01256 ast_mutex_destroy(&p->lock); 01257 ast_mutex_destroy(&p->app_lock); 01258 free(p); 01259 } else { 01260 /* Cause them to hang up */ 01261 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01262 } 01263 } 01264 } 01265 } 01266 AST_LIST_TRAVERSE_SAFE_END 01267 AST_LIST_UNLOCK(&agents); 01268 ast_config_destroy(cfg); 01269 return 1; 01270 }
static int reload | ( | void | ) | [static] |
Definition at line 2809 of file chan_agent.c.
References read_agent_config(), and reload_agents().
Referenced by moh_cli(), reload(), rpt_do_reload(), and show_console().
02810 { 02811 read_agent_config(); 02812 if (persistent_agents) 02813 reload_agents(); 02814 return 0; 02815 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2581 of file chan_agent.c.
References agent_pvt::agent, 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().
02582 { 02583 char *agent_num; 02584 struct ast_db_entry *db_tree; 02585 struct ast_db_entry *entry; 02586 struct agent_pvt *cur_agent; 02587 char agent_data[256]; 02588 char *parse; 02589 char *agent_chan; 02590 char *agent_callerid; 02591 02592 db_tree = ast_db_gettree(pa_family, NULL); 02593 02594 AST_LIST_LOCK(&agents); 02595 for (entry = db_tree; entry; entry = entry->next) { 02596 agent_num = entry->key + strlen(pa_family) + 2; 02597 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02598 ast_mutex_lock(&cur_agent->lock); 02599 if (strcmp(agent_num, cur_agent->agent) == 0) 02600 break; 02601 ast_mutex_unlock(&cur_agent->lock); 02602 } 02603 if (!cur_agent) { 02604 ast_db_del(pa_family, agent_num); 02605 continue; 02606 } else 02607 ast_mutex_unlock(&cur_agent->lock); 02608 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02609 if (option_debug) 02610 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02611 parse = agent_data; 02612 agent_chan = strsep(&parse, ";"); 02613 agent_callerid = strsep(&parse, ";"); 02614 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02615 if (agent_callerid) { 02616 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02617 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02618 } else 02619 cur_agent->logincallerid[0] = '\0'; 02620 if (cur_agent->loginstart == 0) 02621 time(&cur_agent->loginstart); 02622 ast_device_state_changed("Agent/%s", cur_agent->agent); 02623 } 02624 } 02625 AST_LIST_UNLOCK(&agents); 02626 if (db_tree) { 02627 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02628 ast_db_freetree(db_tree); 02629 } 02630 }
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 783 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().
00784 { 00785 char buf[AST_MAX_BUF]; 00786 00787 /* if there is no Caller ID, nothing to do */ 00788 if (ast_strlen_zero(callerid)) 00789 return; 00790 00791 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00792 pbx_builtin_setvar_helper(NULL, buf, agent); 00793 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2817 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.
Referenced by load_module().
02818 { 02819 struct agent_pvt *p; 02820 /* First, take us out of the channel loop */ 02821 ast_channel_unregister(&agent_tech); 02822 /* Delete devicestate subscription */ 02823 ast_devstate_del(agent_devicestate_cb, NULL); 02824 /* Unregister dialplan functions */ 02825 ast_custom_function_unregister(&agent_function); 02826 /* Unregister CLI commands */ 02827 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02828 /* Unregister dialplan applications */ 02829 ast_unregister_application(app); 02830 ast_unregister_application(app2); 02831 ast_unregister_application(app3); 02832 /* Unregister manager command */ 02833 ast_manager_unregister("Agents"); 02834 ast_manager_unregister("AgentLogoff"); 02835 ast_manager_unregister("AgentCallbackLogin"); 02836 /* Unregister channel */ 02837 AST_LIST_LOCK(&agents); 02838 /* Hangup all interfaces if they have an owner */ 02839 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02840 if (p->owner) 02841 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02842 free(p); 02843 } 02844 AST_LIST_UNLOCK(&agents); 02845 return 0; 02846 }
int ackcall [static] |
Definition at line 159 of file chan_agent.c.
char agent_logoff_usage[] [static] |
Initial value:
"Usage: agent logoff <channel> [soft]\n" " Sets an agent as no longer logged in.\n" " If 'soft' is specified, do not hangup existing calls.\n"
Definition at line 1882 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 262 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(), add_extensions(), ael2_semantic_check(), answer_exec_enable(), ast_pbx_run_app(), async_wait(), check_app_args(), check_pval_item(), conf_run(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_context_add_extension(), handle_context_add_extension_deprecated(), handle_exec(), load_module(), page_exec(), pbx_builtin_execiftime(), pbx_exec(), pbx_extension_helper(), realtime_exec(), try_calling(), tryexec_exec(), and unload_module().
const char app2[] = "AgentCallbackLogin" [static] |
Definition at line 83 of file chan_agent.c.
Referenced by _macro_exec(), load_module(), and unload_module().
const char app3[] = "AgentMonitorOutgoing" [static] |
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] |
struct ast_cli_entry cli_show_agents_deprecated [static] |
Initial value:
{ { "show", "agents", NULL }, agents_show, NULL, NULL, NULL }
Definition at line 1887 of file chan_agent.c.
struct ast_cli_entry cli_show_agents_online_deprecated [static] |
Initial value:
{ { "show", "agents", "online" }, agents_show_online, NULL, NULL, NULL }
Definition at line 1892 of file chan_agent.c.
const char config[] = "agents.conf" [static] |
Definition at line 80 of file chan_agent.c.
Referenced by app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_next(), ast_variable_retrieve(), builtin_atxfer(), category_get(), do_atxfer(), do_reload(), load_module(), load_odbc_config(), misdn_cfg_init(), park_exec(), parse_config(), pbx_load_module(), read_config_maps(), reload(), reload_config(), and set_config_flags().
const char descrip[] [static] |
const char descrip2[] [static] |
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_get_group(), 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] |
Initial value:
"Description: Sets an agent as no longer logged in.\n" "Variables: (Names marked with * are required)\n" " *Agent: Agent ID of the agent to log off\n" " Soft: Set to 'true' to not hangup existing calls\n"
Definition at line 129 of file chan_agent.c.
const char mandescr_agents[] [static] |
Initial value:
"Description: Will list info about all possible agents.\n" "Variables: NONE\n"
Definition at line 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 ast_moh_destroy(), ast_moh_destroy_one(), get_mohbyname(), init_classes(), moh_generate(), moh_register(), 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] |
Initial value:
"Usage: agent show online\n" " Provides a list of all online agents.\n"
Definition at line 1878 of file chan_agent.c.
char show_agents_usage[] [static] |
Initial value:
"Usage: agent show\n" " Provides summary information on agents.\n"
Definition at line 1874 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] |
int wrapuptime [static] |
Definition at line 158 of file chan_agent.c.