#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_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 229 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 409 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().
00410 { 00411 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00412 char filename[AST_MAX_BUF]; 00413 int res = -1; 00414 if (!p) 00415 return -1; 00416 if (!ast->monitor) { 00417 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00418 /* substitute . for - */ 00419 if ((pointer = strchr(filename, '.'))) 00420 *pointer = '-'; 00421 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00422 ast_monitor_start(ast, recordformat, tmp, needlock); 00423 ast_monitor_setjoinfiles(ast, 1); 00424 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00425 #if 0 00426 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00427 #endif 00428 if (!ast->cdr) 00429 ast->cdr = ast_cdr_alloc(); 00430 ast_cdr_setuserfield(ast, tmp2); 00431 res = 0; 00432 } else 00433 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00434 return res; 00435 }
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 1860 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_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::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().
01861 { 01862 int res=0; 01863 int tries = 0; 01864 int max_login_tries = maxlogintries; 01865 struct agent_pvt *p; 01866 struct ast_module_user *u; 01867 int login_state = 0; 01868 char user[AST_MAX_AGENT] = ""; 01869 char pass[AST_MAX_AGENT]; 01870 char agent[AST_MAX_AGENT] = ""; 01871 char xpass[AST_MAX_AGENT] = ""; 01872 char *errmsg; 01873 char *parse; 01874 AST_DECLARE_APP_ARGS(args, 01875 AST_APP_ARG(agent_id); 01876 AST_APP_ARG(options); 01877 AST_APP_ARG(extension); 01878 ); 01879 const char *tmpoptions = NULL; 01880 char *context = NULL; 01881 int play_announcement = 1; 01882 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01883 int update_cdr = updatecdr; 01884 char *filename = "agent-loginok"; 01885 char tmpchan[AST_MAX_BUF] = ""; 01886 01887 u = ast_module_user_add(chan); 01888 01889 parse = ast_strdupa(data); 01890 01891 AST_STANDARD_APP_ARGS(args, parse); 01892 01893 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01894 01895 /* Set Channel Specific Login Overrides */ 01896 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01897 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01898 if (max_login_tries < 0) 01899 max_login_tries = 0; 01900 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01901 if (option_verbose > 2) 01902 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); 01903 } 01904 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01905 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01906 update_cdr = 1; 01907 else 01908 update_cdr = 0; 01909 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01910 if (option_verbose > 2) 01911 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01912 } 01913 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01914 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01915 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01916 if (option_verbose > 2) 01917 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01918 } 01919 /* End Channel Specific Login Overrides */ 01920 01921 if (callbackmode && args.extension) { 01922 parse = args.extension; 01923 args.extension = strsep(&parse, "@"); 01924 context = parse; 01925 } 01926 01927 if (!ast_strlen_zero(args.options)) { 01928 if (strchr(args.options, 's')) { 01929 play_announcement = 0; 01930 } 01931 } 01932 01933 if (chan->_state != AST_STATE_UP) 01934 res = ast_answer(chan); 01935 if (!res) { 01936 if (!ast_strlen_zero(args.agent_id)) 01937 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01938 else 01939 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01940 } 01941 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01942 tries++; 01943 /* Check for password */ 01944 AST_LIST_LOCK(&agents); 01945 AST_LIST_TRAVERSE(&agents, p, list) { 01946 if (!strcmp(p->agent, user) && !p->pending) 01947 ast_copy_string(xpass, p->password, sizeof(xpass)); 01948 } 01949 AST_LIST_UNLOCK(&agents); 01950 if (!res) { 01951 if (!ast_strlen_zero(xpass)) 01952 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01953 else 01954 pass[0] = '\0'; 01955 } 01956 errmsg = "agent-incorrect"; 01957 01958 #if 0 01959 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01960 #endif 01961 01962 /* Check again for accuracy */ 01963 AST_LIST_LOCK(&agents); 01964 AST_LIST_TRAVERSE(&agents, p, list) { 01965 ast_mutex_lock(&p->lock); 01966 if (!strcmp(p->agent, user) && 01967 !strcmp(p->password, pass) && !p->pending) { 01968 login_state = 1; /* Successful Login */ 01969 01970 /* Ensure we can't be gotten until we're done */ 01971 gettimeofday(&p->lastdisc, NULL); 01972 p->lastdisc.tv_sec++; 01973 01974 /* Set Channel Specific Agent Overrides */ 01975 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01976 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 01977 p->ackcall = 2; 01978 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 01979 p->ackcall = 1; 01980 else 01981 p->ackcall = 0; 01982 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01983 if (option_verbose > 2) 01984 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 01985 } 01986 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01987 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01988 if (p->autologoff < 0) 01989 p->autologoff = 0; 01990 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 01991 if (option_verbose > 2) 01992 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 01993 } 01994 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 01995 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 01996 if (p->wrapuptime < 0) 01997 p->wrapuptime = 0; 01998 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 01999 if (option_verbose > 2) 02000 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 02001 } 02002 /* End Channel Specific Agent Overrides */ 02003 if (!p->chan) { 02004 char last_loginchan[80] = ""; 02005 long logintime; 02006 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02007 02008 if (callbackmode) { 02009 int pos = 0; 02010 /* Retrieve login chan */ 02011 for (;;) { 02012 if (!ast_strlen_zero(args.extension)) { 02013 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 02014 res = 0; 02015 } else 02016 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 02017 if (ast_strlen_zero(tmpchan) ) 02018 break; 02019 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 02020 if(!allow_multiple_login(tmpchan,context) ) { 02021 args.extension = NULL; 02022 pos = 0; 02023 } else 02024 break; 02025 } 02026 if (args.extension) { 02027 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 02028 args.extension = NULL; 02029 pos = 0; 02030 } else { 02031 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 02032 res = ast_streamfile(chan, "invalid", chan->language); 02033 if (!res) 02034 res = ast_waitstream(chan, AST_DIGIT_ANY); 02035 if (res > 0) { 02036 tmpchan[0] = res; 02037 tmpchan[1] = '\0'; 02038 pos = 1; 02039 } else { 02040 tmpchan[0] = '\0'; 02041 pos = 0; 02042 } 02043 } 02044 } 02045 args.extension = tmpchan; 02046 if (!res) { 02047 set_agentbycallerid(p->logincallerid, NULL); 02048 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 02049 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 02050 else { 02051 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 02052 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 02053 } 02054 p->acknowledged = 0; 02055 if (ast_strlen_zero(p->loginchan)) { 02056 login_state = 2; 02057 filename = "agent-loggedoff"; 02058 } else { 02059 if (chan->cid.cid_num) { 02060 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 02061 set_agentbycallerid(p->logincallerid, p->agent); 02062 } else 02063 p->logincallerid[0] = '\0'; 02064 } 02065 02066 if(update_cdr && chan->cdr) 02067 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02068 02069 } 02070 } else { 02071 p->loginchan[0] = '\0'; 02072 p->logincallerid[0] = '\0'; 02073 p->acknowledged = 0; 02074 } 02075 ast_mutex_unlock(&p->lock); 02076 AST_LIST_UNLOCK(&agents); 02077 if( !res && play_announcement==1 ) 02078 res = ast_streamfile(chan, filename, chan->language); 02079 if (!res) 02080 ast_waitstream(chan, ""); 02081 AST_LIST_LOCK(&agents); 02082 ast_mutex_lock(&p->lock); 02083 if (!res) { 02084 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02085 if (res) 02086 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02087 } 02088 if (!res) { 02089 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02090 if (res) 02091 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02092 } 02093 /* Check once more just in case */ 02094 if (p->chan) 02095 res = -1; 02096 if (callbackmode && !res) { 02097 /* Just say goodbye and be done with it */ 02098 if (!ast_strlen_zero(p->loginchan)) { 02099 if (p->loginstart == 0) 02100 time(&p->loginstart); 02101 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02102 "Agent: %s\r\n" 02103 "Loginchan: %s\r\n" 02104 "Uniqueid: %s\r\n", 02105 p->agent, p->loginchan, chan->uniqueid); 02106 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02107 if (option_verbose > 1) 02108 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02109 ast_device_state_changed("Agent/%s", p->agent); 02110 if (persistent_agents) 02111 dump_agents(); 02112 } else { 02113 logintime = time(NULL) - p->loginstart; 02114 p->loginstart = 0; 02115 02116 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02117 if (option_verbose > 1) 02118 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02119 } 02120 AST_LIST_UNLOCK(&agents); 02121 if (!res) 02122 res = ast_safe_sleep(chan, 500); 02123 ast_mutex_unlock(&p->lock); 02124 } else if (!res) { 02125 ast_indicate_data(chan, AST_CONTROL_HOLD, 02126 S_OR(p->moh, NULL), 02127 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02128 if (p->loginstart == 0) 02129 time(&p->loginstart); 02130 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02131 "Agent: %s\r\n" 02132 "Channel: %s\r\n" 02133 "Uniqueid: %s\r\n", 02134 p->agent, chan->name, chan->uniqueid); 02135 if (update_cdr && chan->cdr) 02136 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02137 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02138 if (option_verbose > 1) 02139 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02140 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02141 /* Login this channel and wait for it to go away */ 02142 p->chan = chan; 02143 if (p->ackcall > 1) 02144 check_beep(p, 0); 02145 else 02146 check_availability(p, 0); 02147 ast_mutex_unlock(&p->lock); 02148 AST_LIST_UNLOCK(&agents); 02149 ast_device_state_changed("Agent/%s", p->agent); 02150 while (res >= 0) { 02151 ast_mutex_lock(&p->lock); 02152 if (p->deferlogoff && p->chan) { 02153 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02154 p->deferlogoff = 0; 02155 } 02156 if (p->chan != chan) 02157 res = -1; 02158 ast_mutex_unlock(&p->lock); 02159 /* Yield here so other interested threads can kick in. */ 02160 sched_yield(); 02161 if (res) 02162 break; 02163 02164 AST_LIST_LOCK(&agents); 02165 ast_mutex_lock(&p->lock); 02166 if (p->lastdisc.tv_sec) { 02167 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02168 if (option_debug) 02169 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02170 p->lastdisc = ast_tv(0, 0); 02171 ast_device_state_changed("Agent/%s", p->agent); 02172 if (p->ackcall > 1) 02173 check_beep(p, 0); 02174 else 02175 check_availability(p, 0); 02176 } 02177 } 02178 ast_mutex_unlock(&p->lock); 02179 AST_LIST_UNLOCK(&agents); 02180 /* Synchronize channel ownership between call to agent and itself. */ 02181 ast_mutex_lock( &p->app_lock ); 02182 ast_mutex_lock(&p->lock); 02183 p->owning_app = pthread_self(); 02184 ast_mutex_unlock(&p->lock); 02185 if (p->ackcall > 1) 02186 res = agent_ack_sleep(p); 02187 else 02188 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02189 ast_mutex_unlock( &p->app_lock ); 02190 if ((p->ackcall > 1) && (res == 1)) { 02191 AST_LIST_LOCK(&agents); 02192 ast_mutex_lock(&p->lock); 02193 check_availability(p, 0); 02194 ast_mutex_unlock(&p->lock); 02195 AST_LIST_UNLOCK(&agents); 02196 res = 0; 02197 } 02198 sched_yield(); 02199 } 02200 ast_mutex_lock(&p->lock); 02201 if (res && p->owner) 02202 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02203 /* Log us off if appropriate */ 02204 if (p->chan == chan) 02205 p->chan = NULL; 02206 p->acknowledged = 0; 02207 logintime = time(NULL) - p->loginstart; 02208 p->loginstart = 0; 02209 ast_mutex_unlock(&p->lock); 02210 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02211 "Agent: %s\r\n" 02212 "Logintime: %ld\r\n" 02213 "Uniqueid: %s\r\n", 02214 p->agent, logintime, chan->uniqueid); 02215 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02216 if (option_verbose > 1) 02217 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02218 /* If there is no owner, go ahead and kill it now */ 02219 ast_device_state_changed("Agent/%s", p->agent); 02220 if (p->dead && !p->owner) { 02221 ast_mutex_destroy(&p->lock); 02222 ast_mutex_destroy(&p->app_lock); 02223 free(p); 02224 } 02225 } 02226 else { 02227 ast_mutex_unlock(&p->lock); 02228 p = NULL; 02229 } 02230 res = -1; 02231 } else { 02232 ast_mutex_unlock(&p->lock); 02233 errmsg = "agent-alreadyon"; 02234 p = NULL; 02235 } 02236 break; 02237 } 02238 ast_mutex_unlock(&p->lock); 02239 } 02240 if (!p) 02241 AST_LIST_UNLOCK(&agents); 02242 02243 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02244 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02245 } 02246 02247 if (!res) 02248 res = ast_safe_sleep(chan, 500); 02249 02250 /* AgentLogin() exit */ 02251 if (!callbackmode) { 02252 ast_module_user_remove(u); 02253 return -1; 02254 } else { /* AgentCallbackLogin() exit*/ 02255 /* Set variables */ 02256 if (login_state > 0) { 02257 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user); 02258 if (login_state==1) { 02259 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on"); 02260 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension); 02261 } else 02262 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off"); 02263 } else { 02264 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail"); 02265 } 02266 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) { 02267 ast_module_user_remove(u); 02268 return 0; 02269 } 02270 /* Do we need to play agent-goodbye now that we will be hanging up? */ 02271 if (play_announcement) { 02272 if (!res) 02273 res = ast_safe_sleep(chan, 1000); 02274 res = ast_streamfile(chan, agent_goodbye, chan->language); 02275 if (!res) 02276 res = ast_waitstream(chan, ""); 02277 if (!res) 02278 res = ast_safe_sleep(chan, 1000); 02279 } 02280 } 02281 02282 ast_module_user_remove(u); 02283 02284 /* We should never get here if next priority exists when in callbackmode */ 02285 return -1; 02286 }
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 2337 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().
02338 { 02339 const char *agent = astman_get_header(m, "Agent"); 02340 const char *exten = astman_get_header(m, "Exten"); 02341 const char *context = astman_get_header(m, "Context"); 02342 const char *wrapuptime_s = astman_get_header(m, "WrapupTime"); 02343 const char *ackcall_s = astman_get_header(m, "AckCall"); 02344 struct agent_pvt *p; 02345 int login_state = 0; 02346 02347 callback_deprecated(); 02348 02349 if (ast_strlen_zero(agent)) { 02350 astman_send_error(s, m, "No agent specified"); 02351 return 0; 02352 } 02353 02354 if (ast_strlen_zero(exten)) { 02355 astman_send_error(s, m, "No extension specified"); 02356 return 0; 02357 } 02358 02359 AST_LIST_LOCK(&agents); 02360 AST_LIST_TRAVERSE(&agents, p, list) { 02361 if (strcmp(p->agent, agent) || p->pending) 02362 continue; 02363 if (p->chan) { 02364 login_state = 2; /* already logged in (and on the phone)*/ 02365 break; 02366 } 02367 ast_mutex_lock(&p->lock); 02368 login_state = 1; /* Successful Login */ 02369 02370 if (ast_strlen_zero(context)) 02371 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan)); 02372 else 02373 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context); 02374 02375 if (!ast_strlen_zero(wrapuptime_s)) { 02376 p->wrapuptime = atoi(wrapuptime_s); 02377 if (p->wrapuptime < 0) 02378 p->wrapuptime = 0; 02379 } 02380 02381 if (ast_true(ackcall_s)) 02382 p->ackcall = 1; 02383 else 02384 p->ackcall = 0; 02385 02386 if (p->loginstart == 0) 02387 time(&p->loginstart); 02388 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02389 "Agent: %s\r\n" 02390 "Loginchan: %s\r\n", 02391 p->agent, p->loginchan); 02392 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02393 if (option_verbose > 1) 02394 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02395 ast_device_state_changed("Agent/%s", p->agent); 02396 ast_mutex_unlock(&p->lock); 02397 if (persistent_agents) 02398 dump_agents(); 02399 } 02400 AST_LIST_UNLOCK(&agents); 02401 02402 if (login_state == 1) 02403 astman_send_ack(s, m, "Agent logged in"); 02404 else if (login_state == 0) 02405 astman_send_error(s, m, "No such agent"); 02406 else if (login_state == 2) 02407 astman_send_error(s, m, "Agent already logged in"); 02408 02409 return 0; 02410 }
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 1648 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().
01649 { 01650 const char *agent = astman_get_header(m, "Agent"); 01651 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01652 int soft; 01653 int ret; /* return value of agent_logoff */ 01654 01655 if (ast_strlen_zero(agent)) { 01656 astman_send_error(s, m, "No agent specified"); 01657 return 0; 01658 } 01659 01660 soft = ast_true(soft_s) ? 1 : 0; 01661 ret = agent_logoff(agent, soft); 01662 if (ret == 0) 01663 astman_send_ack(s, m, "Agent logged out"); 01664 else 01665 astman_send_error(s, m, "No such agent"); 01666 01667 return 0; 01668 }
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 1462 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().
01463 { 01464 const char *id = astman_get_header(m,"ActionID"); 01465 char idText[256] = ""; 01466 char chanbuf[256]; 01467 struct agent_pvt *p; 01468 char *username = NULL; 01469 char *loginChan = NULL; 01470 char *talkingtoChan = NULL; 01471 char *status = NULL; 01472 01473 if (!ast_strlen_zero(id)) 01474 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01475 astman_send_ack(s, m, "Agents will follow"); 01476 AST_LIST_LOCK(&agents); 01477 AST_LIST_TRAVERSE(&agents, p, list) { 01478 ast_mutex_lock(&p->lock); 01479 01480 /* Status Values: 01481 AGENT_LOGGEDOFF - Agent isn't logged in 01482 AGENT_IDLE - Agent is logged in, and waiting for call 01483 AGENT_ONCALL - Agent is logged in, and on a call 01484 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01485 01486 username = S_OR(p->name, "None"); 01487 01488 /* Set a default status. It 'should' get changed. */ 01489 status = "AGENT_UNKNOWN"; 01490 01491 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01492 loginChan = p->loginchan; 01493 talkingtoChan = "n/a"; 01494 status = "AGENT_IDLE"; 01495 if (p->acknowledged) { 01496 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01497 loginChan = chanbuf; 01498 } 01499 } else if (p->chan) { 01500 loginChan = ast_strdupa(p->chan->name); 01501 if (p->owner && p->owner->_bridge) { 01502 if (ast_bridged_channel(p->owner)) { 01503 talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, "")); 01504 } else { 01505 talkingtoChan = "n/a"; 01506 } 01507 status = "AGENT_ONCALL"; 01508 } else { 01509 talkingtoChan = "n/a"; 01510 status = "AGENT_IDLE"; 01511 } 01512 } else { 01513 loginChan = "n/a"; 01514 talkingtoChan = "n/a"; 01515 status = "AGENT_LOGGEDOFF"; 01516 } 01517 01518 astman_append(s, "Event: Agents\r\n" 01519 "Agent: %s\r\n" 01520 "Name: %s\r\n" 01521 "Status: %s\r\n" 01522 "LoggedInChan: %s\r\n" 01523 "LoggedInTime: %d\r\n" 01524 "TalkingTo: %s\r\n" 01525 "%s" 01526 "\r\n", 01527 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); 01528 ast_mutex_unlock(&p->lock); 01529 } 01530 AST_LIST_UNLOCK(&agents); 01531 astman_append(s, "Event: AgentsComplete\r\n" 01532 "%s" 01533 "\r\n",idText); 01534 return 0; 01535 }
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 293 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().
00294 { 00295 char *parse; 00296 AST_DECLARE_APP_ARGS(args, 00297 AST_APP_ARG(agt); 00298 AST_APP_ARG(password); 00299 AST_APP_ARG(name); 00300 ); 00301 char *password = NULL; 00302 char *name = NULL; 00303 char *agt = NULL; 00304 struct agent_pvt *p; 00305 00306 parse = ast_strdupa(agent); 00307 00308 /* Extract username (agt), password and name from agent (args). */ 00309 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 00310 00311 if(args.argc == 0) { 00312 ast_log(LOG_WARNING, "A blank agent line!\n"); 00313 return NULL; 00314 } 00315 00316 if(ast_strlen_zero(args.agt) ) { 00317 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00318 return NULL; 00319 } else 00320 agt = args.agt; 00321 00322 if(!ast_strlen_zero(args.password)) { 00323 password = args.password; 00324 while (*password && *password < 33) password++; 00325 } 00326 if(!ast_strlen_zero(args.name)) { 00327 name = args.name; 00328 while (*name && *name < 33) name++; 00329 } 00330 00331 /* Are we searching for the agent here ? To see if it exists already ? */ 00332 AST_LIST_TRAVERSE(&agents, p, list) { 00333 if (!pending && !strcmp(p->agent, agt)) 00334 break; 00335 } 00336 if (!p) { 00337 // Build the agent. 00338 if (!(p = ast_calloc(1, sizeof(*p)))) 00339 return NULL; 00340 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00341 ast_mutex_init(&p->lock); 00342 ast_mutex_init(&p->app_lock); 00343 p->owning_app = (pthread_t) -1; 00344 p->app_sleep_cond = 1; 00345 p->group = group; 00346 p->pending = pending; 00347 AST_LIST_INSERT_TAIL(&agents, p, list); 00348 } 00349 00350 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00351 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00352 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00353 p->ackcall = ackcall; 00354 p->autologoff = autologoff; 00355 00356 /* If someone reduces the wrapuptime and reloads, we want it 00357 * to change the wrapuptime immediately on all calls */ 00358 if (p->wrapuptime > wrapuptime) { 00359 struct timeval now = ast_tvnow(); 00360 /* XXX check what is this exactly */ 00361 00362 /* We won't be pedantic and check the tv_usec val */ 00363 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00364 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00365 p->lastdisc.tv_usec = now.tv_usec; 00366 } 00367 } 00368 p->wrapuptime = wrapuptime; 00369 00370 if (pending) 00371 p->dead = 1; 00372 else 00373 p->dead = 0; 00374 return p; 00375 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 906 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().
00907 { 00908 struct agent_pvt *p; 00909 int res=0; 00910 int to = 1000; 00911 struct ast_frame *f; 00912 00913 /* Wait a second and look for something */ 00914 00915 p = (struct agent_pvt *) data; 00916 if (!p->chan) 00917 return -1; 00918 00919 for(;;) { 00920 to = ast_waitfor(p->chan, to); 00921 if (to < 0) 00922 return -1; 00923 if (!to) 00924 return 0; 00925 f = ast_read(p->chan); 00926 if (!f) 00927 return -1; 00928 if (f->frametype == AST_FRAME_DTMF) 00929 res = f->subclass; 00930 else 00931 res = 0; 00932 ast_frfree(f); 00933 ast_mutex_lock(&p->lock); 00934 if (!p->app_sleep_cond) { 00935 ast_mutex_unlock(&p->lock); 00936 return 0; 00937 } else if (res == '#') { 00938 ast_mutex_unlock(&p->lock); 00939 return 1; 00940 } 00941 ast_mutex_unlock(&p->lock); 00942 res = 0; 00943 } 00944 return res; 00945 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 403 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00404 { 00405 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00406 return -1; 00407 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Definition at line 947 of file chan_agent.c.
References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.
00948 { 00949 struct agent_pvt *p = bridge->tech_pvt; 00950 struct ast_channel *ret = NULL; 00951 00952 if (p) { 00953 if (chan == p->chan) 00954 ret = bridge->_bridge; 00955 else if (chan == bridge->_bridge) 00956 ret = p->chan; 00957 } 00958 00959 if (option_debug) 00960 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 00961 return ret; 00962 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 646 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_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::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.
00647 { 00648 struct agent_pvt *p = ast->tech_pvt; 00649 int res = -1; 00650 int newstate=0; 00651 ast_mutex_lock(&p->lock); 00652 p->acknowledged = 0; 00653 if (!p->chan) { 00654 if (p->pending) { 00655 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00656 newstate = AST_STATE_DIALING; 00657 res = 0; 00658 } else { 00659 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00660 res = -1; 00661 } 00662 ast_mutex_unlock(&p->lock); 00663 if (newstate) 00664 ast_setstate(ast, newstate); 00665 return res; 00666 } else if (!ast_strlen_zero(p->loginchan)) { 00667 time(&p->start); 00668 /* Call on this agent */ 00669 if (option_verbose > 2) 00670 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00671 ast_set_callerid(p->chan, 00672 ast->cid.cid_num, ast->cid.cid_name, NULL); 00673 ast_channel_inherit_variables(ast, p->chan); 00674 res = ast_call(p->chan, p->loginchan, 0); 00675 CLEANUP(ast,p); 00676 ast_mutex_unlock(&p->lock); 00677 return res; 00678 } 00679 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00680 if (option_debug > 2) 00681 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language); 00682 res = ast_streamfile(p->chan, beep, p->chan->language); 00683 if (option_debug > 2) 00684 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 00685 if (!res) { 00686 res = ast_waitstream(p->chan, ""); 00687 if (option_debug > 2) 00688 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 00689 } 00690 if (!res) { 00691 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00692 if (option_debug > 2) 00693 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res); 00694 if (res) 00695 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00696 } else { 00697 /* Agent hung-up */ 00698 p->chan = NULL; 00699 } 00700 00701 if (!res) { 00702 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00703 if (option_debug > 2) 00704 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res); 00705 if (res) 00706 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00707 } 00708 if(!res) { 00709 /* Call is immediately up, or might need ack */ 00710 if (p->ackcall > 1) 00711 newstate = AST_STATE_RINGING; 00712 else { 00713 newstate = AST_STATE_UP; 00714 if (recordagentcalls) 00715 agent_start_monitoring(ast, 0); 00716 p->acknowledged = 1; 00717 } 00718 res = 0; 00719 } 00720 CLEANUP(ast, p); 00721 ast_mutex_unlock(&p->lock); 00722 if (newstate) 00723 ast_setstate(ast, newstate); 00724 return res; 00725 }
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 383 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().
00384 { 00385 struct ast_channel *chan = p->owner; 00386 p->owner = NULL; 00387 chan->tech_pvt = NULL; 00388 p->app_sleep_cond = 1; 00389 /* Release ownership of the agent to other threads (presumably running the login app). */ 00390 ast_mutex_unlock(&p->app_lock); 00391 if (chan) 00392 ast_channel_free(chan); 00393 if (p->dead) { 00394 ast_mutex_destroy(&p->lock); 00395 ast_mutex_destroy(&p->app_lock); 00396 free(p); 00397 } 00398 return 0; 00399 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 885 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().
00886 { 00887 struct agent_pvt *p; 00888 int res; 00889 00890 p = (struct agent_pvt *)data; 00891 00892 ast_mutex_lock(&p->lock); 00893 res = p->app_sleep_cond; 00894 if (p->lastdisc.tv_sec) { 00895 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 00896 res = 1; 00897 } 00898 ast_mutex_unlock(&p->lock); 00899 00900 if(option_debug > 4 && !res ) 00901 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res ); 00902 00903 return res; 00904 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2556 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::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
02557 { 02558 struct agent_pvt *p; 02559 char *s; 02560 ast_group_t groupmatch; 02561 int groupoff; 02562 int waitforagent=0; 02563 int res = AST_DEVICE_INVALID; 02564 02565 s = data; 02566 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) 02567 groupmatch = (1 << groupoff); 02568 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 02569 groupmatch = (1 << groupoff); 02570 waitforagent = 1; 02571 } else 02572 groupmatch = 0; 02573 02574 /* Check actual logged in agents first */ 02575 AST_LIST_LOCK(&agents); 02576 AST_LIST_TRAVERSE(&agents, p, list) { 02577 ast_mutex_lock(&p->lock); 02578 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02579 if (p->owner) { 02580 if (res != AST_DEVICE_INUSE) 02581 res = AST_DEVICE_BUSY; 02582 } else { 02583 if (res == AST_DEVICE_BUSY) 02584 res = AST_DEVICE_INUSE; 02585 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02586 if (res == AST_DEVICE_INVALID) 02587 res = AST_DEVICE_UNKNOWN; 02588 } else if (res == AST_DEVICE_INVALID) 02589 res = AST_DEVICE_UNAVAILABLE; 02590 } 02591 if (!strcmp(data, p->agent)) { 02592 ast_mutex_unlock(&p->lock); 02593 break; 02594 } 02595 } 02596 ast_mutex_unlock(&p->lock); 02597 } 02598 AST_LIST_UNLOCK(&agents); 02599 return res; 02600 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 624 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.
00625 { 00626 struct agent_pvt *p = ast->tech_pvt; 00627 ast_mutex_lock(&p->lock); 00628 if (p->chan) { 00629 ast_senddigit_begin(p->chan, digit); 00630 } 00631 ast_mutex_unlock(&p->lock); 00632 return 0; 00633 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 635 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.
00636 { 00637 struct agent_pvt *p = ast->tech_pvt; 00638 ast_mutex_lock(&p->lock); 00639 if (p->chan) { 00640 ast_senddigit_end(p->chan, digit, duration); 00641 } 00642 ast_mutex_unlock(&p->lock); 00643 return 0; 00644 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 597 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.
00598 { 00599 struct agent_pvt *p = newchan->tech_pvt; 00600 ast_mutex_lock(&p->lock); 00601 if (p->owner != oldchan) { 00602 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00603 ast_mutex_unlock(&p->lock); 00604 return -1; 00605 } 00606 p->owner = newchan; 00607 ast_mutex_unlock(&p->lock); 00608 return 0; 00609 }
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 741 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00742 { 00743 struct agent_pvt *p = NULL; 00744 struct ast_channel *base = chan; 00745 00746 /* chan is locked by the calling function */ 00747 if (!chan || !chan->tech_pvt) { 00748 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); 00749 return NULL; 00750 } 00751 p = chan->tech_pvt; 00752 if (p->chan) 00753 base = p->chan; 00754 return base; 00755 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 774 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::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.
00775 { 00776 struct agent_pvt *p = ast->tech_pvt; 00777 int howlong = 0; 00778 const char *status; 00779 ast_mutex_lock(&p->lock); 00780 p->owner = NULL; 00781 ast->tech_pvt = NULL; 00782 p->app_sleep_cond = 1; 00783 p->acknowledged = 0; 00784 00785 /* if they really are hung up then set start to 0 so the test 00786 * later if we're called on an already downed channel 00787 * doesn't cause an agent to be logged out like when 00788 * agent_request() is followed immediately by agent_hangup() 00789 * as in apps/app_chanisavail.c:chanavail_exec() 00790 */ 00791 00792 if (option_debug) 00793 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00794 if (p->start && (ast->_state != AST_STATE_UP)) { 00795 howlong = time(NULL) - p->start; 00796 p->start = 0; 00797 } else if (ast->_state == AST_STATE_RESERVED) 00798 howlong = 0; 00799 else 00800 p->start = 0; 00801 if (p->chan) { 00802 p->chan->_bridge = NULL; 00803 /* If they're dead, go ahead and hang up on the agent now */ 00804 if (!ast_strlen_zero(p->loginchan)) { 00805 /* Store last disconnect time */ 00806 if (p->wrapuptime) 00807 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00808 else 00809 p->lastdisc = ast_tv(0,0); 00810 if (p->chan) { 00811 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00812 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00813 long logintime = time(NULL) - p->loginstart; 00814 p->loginstart = 0; 00815 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00816 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00817 } 00818 /* Recognize the hangup and pass it along immediately */ 00819 ast_hangup(p->chan); 00820 p->chan = NULL; 00821 } 00822 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00823 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00824 long logintime = time(NULL) - p->loginstart; 00825 p->loginstart = 0; 00826 if (!p->deferlogoff) 00827 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00828 p->deferlogoff = 0; 00829 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00830 if (persistent_agents) 00831 dump_agents(); 00832 } 00833 } else if (p->dead) { 00834 ast_channel_lock(p->chan); 00835 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00836 ast_channel_unlock(p->chan); 00837 } else if (p->loginstart) { 00838 ast_channel_lock(p->chan); 00839 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00840 S_OR(p->moh, NULL), 00841 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00842 ast_channel_unlock(p->chan); 00843 } 00844 } 00845 ast_mutex_unlock(&p->lock); 00846 00847 /* Only register a device state change if the agent is still logged in */ 00848 if (!p->loginstart) { 00849 p->loginchan[0] = '\0'; 00850 p->logincallerid[0] = '\0'; 00851 if (persistent_agents) 00852 dump_agents(); 00853 } else { 00854 ast_device_state_changed("Agent/%s", p->agent); 00855 } 00856 00857 if (p->pending) { 00858 AST_LIST_LOCK(&agents); 00859 AST_LIST_REMOVE(&agents, p, list); 00860 AST_LIST_UNLOCK(&agents); 00861 } 00862 if (p->abouttograb) { 00863 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00864 kill it later */ 00865 p->abouttograb = 0; 00866 } else if (p->dead) { 00867 ast_mutex_destroy(&p->lock); 00868 ast_mutex_destroy(&p->app_lock); 00869 free(p); 00870 } else { 00871 if (p->chan) { 00872 /* Not dead -- check availability now */ 00873 ast_mutex_lock(&p->lock); 00874 /* Store last disconnect time */ 00875 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00876 ast_mutex_unlock(&p->lock); 00877 } 00878 /* Release ownership of the agent to other threads (presumably running the login app). */ 00879 if (ast_strlen_zero(p->loginchan)) 00880 ast_mutex_unlock(&p->app_lock); 00881 } 00882 return 0; 00883 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 611 of file chan_agent.c.
References ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, ast_channel::tech, and ast_channel::tech_pvt.
00612 { 00613 struct agent_pvt *p = ast->tech_pvt; 00614 int res = -1; 00615 ast_mutex_lock(&p->lock); 00616 if (p->chan) 00617 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00618 else 00619 res = 0; 00620 ast_mutex_unlock(&p->lock); 00621 return res; 00622 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1576 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().
01577 { 01578 struct agent_pvt *p; 01579 long logintime; 01580 int ret = -1; /* Return -1 if no agent if found */ 01581 01582 AST_LIST_LOCK(&agents); 01583 AST_LIST_TRAVERSE(&agents, p, list) { 01584 if (!strcasecmp(p->agent, agent)) { 01585 ret = 0; 01586 if (p->owner || p->chan) { 01587 if (!soft) { 01588 ast_mutex_lock(&p->lock); 01589 01590 while (p->owner && ast_channel_trylock(p->owner)) { 01591 DEADLOCK_AVOIDANCE(&p->lock); 01592 } 01593 if (p->owner) { 01594 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01595 ast_channel_unlock(p->owner); 01596 } 01597 01598 while (p->chan && ast_channel_trylock(p->chan)) { 01599 DEADLOCK_AVOIDANCE(&p->lock); 01600 } 01601 if (p->chan) { 01602 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01603 ast_channel_unlock(p->chan); 01604 } 01605 01606 ast_mutex_unlock(&p->lock); 01607 } else 01608 p->deferlogoff = 1; 01609 } else { 01610 logintime = time(NULL) - p->loginstart; 01611 p->loginstart = 0; 01612 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01613 } 01614 break; 01615 } 01616 } 01617 AST_LIST_UNLOCK(&agents); 01618 01619 return ret; 01620 }
static int agent_logoff_cmd | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1622 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01623 { 01624 int ret; 01625 char *agent; 01626 01627 if (argc < 3 || argc > 4) 01628 return RESULT_SHOWUSAGE; 01629 if (argc == 4 && strcasecmp(argv[3], "soft")) 01630 return RESULT_SHOWUSAGE; 01631 01632 agent = argv[2] + 6; 01633 ret = agent_logoff(agent, argc == 4); 01634 if (ret == 0) 01635 ast_cli(fd, "Logging out %s\n", agent); 01636 01637 return RESULT_SUCCESS; 01638 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1537 of file chan_agent.c.
References agent_pvt::agent, ast_device_state_changed(), AST_MAX_AGENT, ast_queue_log(), ast_strdupa, ast_strlen_zero(), dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event(), and set_agentbycallerid().
Referenced by __login_exec(), agent_hangup(), agent_logoff(), and agent_read().
01538 { 01539 char *tmp = NULL; 01540 char agent[AST_MAX_AGENT]; 01541 01542 if (!ast_strlen_zero(logcommand)) 01543 tmp = logcommand; 01544 else 01545 tmp = ast_strdupa(""); 01546 01547 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01548 01549 if (!ast_strlen_zero(uniqueid)) { 01550 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01551 "Agent: %s\r\n" 01552 "Reason: %s\r\n" 01553 "Loginchan: %s\r\n" 01554 "Logintime: %ld\r\n" 01555 "Uniqueid: %s\r\n", 01556 p->agent, tmp, loginchan, logintime, uniqueid); 01557 } else { 01558 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01559 "Agent: %s\r\n" 01560 "Reason: %s\r\n" 01561 "Loginchan: %s\r\n" 01562 "Logintime: %ld\r\n", 01563 p->agent, tmp, loginchan, logintime); 01564 } 01565 01566 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01567 set_agentbycallerid(p->logincallerid, NULL); 01568 p->loginchan[0] ='\0'; 01569 p->logincallerid[0] = '\0'; 01570 ast_device_state_changed("Agent/%s", p->agent); 01571 if (persistent_agents) 01572 dump_agents(); 01573 01574 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static] |
Create new agent channel.
Definition at line 965 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().
00966 { 00967 struct ast_channel *tmp; 00968 #if 0 00969 if (!p->chan) { 00970 ast_log(LOG_WARNING, "No channel? :(\n"); 00971 return NULL; 00972 } 00973 #endif 00974 if (p->pending) 00975 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); 00976 else 00977 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 00978 if (!tmp) { 00979 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 00980 return NULL; 00981 } 00982 00983 tmp->tech = &agent_tech; 00984 if (p->chan) { 00985 tmp->nativeformats = p->chan->nativeformats; 00986 tmp->writeformat = p->chan->writeformat; 00987 tmp->rawwriteformat = p->chan->writeformat; 00988 tmp->readformat = p->chan->readformat; 00989 tmp->rawreadformat = p->chan->readformat; 00990 ast_string_field_set(tmp, language, p->chan->language); 00991 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 00992 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 00993 /* XXX Is this really all we copy form the originating channel?? */ 00994 } else { 00995 tmp->nativeformats = AST_FORMAT_SLINEAR; 00996 tmp->writeformat = AST_FORMAT_SLINEAR; 00997 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 00998 tmp->readformat = AST_FORMAT_SLINEAR; 00999 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01000 } 01001 /* Safe, agentlock already held */ 01002 tmp->tech_pvt = p; 01003 p->owner = tmp; 01004 /* XXX: this needs fixing */ 01005 #if 0 01006 ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1); 01007 #endif 01008 ast_update_use_count(); 01009 tmp->priority = 1; 01010 /* Wake up and wait for other applications (by definition the login app) 01011 * to release this channel). Takes ownership of the agent channel 01012 * to this thread only. 01013 * For signalling the other thread, ast_queue_frame is used until we 01014 * can safely use signals for this purpose. The pselect() needs to be 01015 * implemented in the kernel for this. 01016 */ 01017 p->app_sleep_cond = 0; 01018 if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) { 01019 if (p->chan) { 01020 ast_queue_frame(p->chan, &ast_null_frame); 01021 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01022 ast_mutex_lock(&p->app_lock); 01023 ast_mutex_lock(&p->lock); 01024 } else { 01025 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01026 p->owner = NULL; 01027 tmp->tech_pvt = NULL; 01028 p->app_sleep_cond = 1; 01029 ast_channel_free( tmp ); 01030 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01031 ast_mutex_unlock(&p->app_lock); 01032 return NULL; 01033 } 01034 } else if (!ast_strlen_zero(p->loginchan)) { 01035 if (p->chan) 01036 ast_queue_frame(p->chan, &ast_null_frame); 01037 if (!p->chan) { 01038 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01039 p->owner = NULL; 01040 tmp->tech_pvt = NULL; 01041 p->app_sleep_cond = 1; 01042 ast_channel_free( tmp ); 01043 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01044 return NULL; 01045 } 01046 } 01047 if (p->chan) 01048 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01049 p->owning_app = pthread_self(); 01050 /* After the above step, there should not be any blockers. */ 01051 if (p->chan) { 01052 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) { 01053 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" ); 01054 ast_assert(0); 01055 } 01056 } 01057 return tmp; 01058 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 442 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, AST_CONTROL_ANSWER, ast_copy_flags, 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::chan, CHECK_FORMATS, CLEANUP, f, ast_channel::fdno, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_verbose, pbx_builtin_getvar_helper(), ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
00443 { 00444 struct agent_pvt *p = ast->tech_pvt; 00445 struct ast_frame *f = NULL; 00446 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00447 const char *status; 00448 ast_mutex_lock(&p->lock); 00449 CHECK_FORMATS(ast, p); 00450 if (p->chan) { 00451 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00452 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00453 f = ast_read(p->chan); 00454 } else 00455 f = &ast_null_frame; 00456 if (!f) { 00457 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00458 if (p->chan) { 00459 p->chan->_bridge = NULL; 00460 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00461 for us when the PBX instance that called login finishes */ 00462 if (!ast_strlen_zero(p->loginchan)) { 00463 if (p->chan) 00464 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00465 00466 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00467 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00468 long logintime = time(NULL) - p->loginstart; 00469 p->loginstart = 0; 00470 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00471 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00472 } 00473 ast_hangup(p->chan); 00474 if (p->wrapuptime && p->acknowledged) 00475 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00476 } 00477 p->chan = NULL; 00478 p->acknowledged = 0; 00479 } 00480 } else { 00481 /* if acknowledgement is not required, and the channel is up, we may have missed 00482 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00483 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) 00484 p->acknowledged = 1; 00485 switch (f->frametype) { 00486 case AST_FRAME_CONTROL: 00487 if (f->subclass == AST_CONTROL_ANSWER) { 00488 if (p->ackcall) { 00489 if (option_verbose > 2) 00490 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 00491 /* Don't pass answer along */ 00492 ast_frfree(f); 00493 f = &ast_null_frame; 00494 } else { 00495 p->acknowledged = 1; 00496 /* Use the builtin answer frame for the 00497 recording start check below. */ 00498 ast_frfree(f); 00499 f = &answer_frame; 00500 } 00501 } 00502 break; 00503 case AST_FRAME_DTMF_BEGIN: 00504 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00505 if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){ 00506 ast_frfree(f); 00507 f = &ast_null_frame; 00508 } 00509 break; 00510 case AST_FRAME_DTMF_END: 00511 if (!p->acknowledged && (f->subclass == '#')) { 00512 if (option_verbose > 2) 00513 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 00514 p->acknowledged = 1; 00515 ast_frfree(f); 00516 f = &answer_frame; 00517 } else if (f->subclass == '*' && endcall) { 00518 /* terminates call */ 00519 ast_frfree(f); 00520 f = NULL; 00521 } 00522 break; 00523 case AST_FRAME_VOICE: 00524 case AST_FRAME_VIDEO: 00525 /* don't pass voice or video until the call is acknowledged */ 00526 if (!p->acknowledged) { 00527 ast_frfree(f); 00528 f = &ast_null_frame; 00529 } 00530 default: 00531 /* pass everything else on through */ 00532 break; 00533 } 00534 } 00535 00536 CLEANUP(ast,p); 00537 if (p->chan && !p->chan->_bridge) { 00538 if (strcasecmp(p->chan->tech->type, "Local")) { 00539 p->chan->_bridge = ast; 00540 if (p->chan) 00541 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00542 } 00543 } 00544 ast_mutex_unlock(&p->lock); 00545 if (recordagentcalls && f == &answer_frame) 00546 agent_start_monitoring(ast,0); 00547 return f; 00548 }
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 1349 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.
01350 { 01351 struct agent_pvt *p; 01352 struct ast_channel *chan = NULL; 01353 char *s; 01354 ast_group_t groupmatch; 01355 int groupoff; 01356 int waitforagent=0; 01357 int hasagent = 0; 01358 struct timeval tv; 01359 01360 s = data; 01361 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01362 groupmatch = (1 << groupoff); 01363 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01364 groupmatch = (1 << groupoff); 01365 waitforagent = 1; 01366 } else 01367 groupmatch = 0; 01368 01369 /* Check actual logged in agents first */ 01370 AST_LIST_LOCK(&agents); 01371 AST_LIST_TRAVERSE(&agents, p, list) { 01372 ast_mutex_lock(&p->lock); 01373 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01374 ast_strlen_zero(p->loginchan)) { 01375 if (p->chan) 01376 hasagent++; 01377 tv = ast_tvnow(); 01378 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01379 p->lastdisc = ast_tv(0, 0); 01380 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01381 if (!p->owner && p->chan) { 01382 /* Fixed agent */ 01383 chan = agent_new(p, AST_STATE_DOWN); 01384 } 01385 if (chan) { 01386 ast_mutex_unlock(&p->lock); 01387 break; 01388 } 01389 } 01390 } 01391 ast_mutex_unlock(&p->lock); 01392 } 01393 if (!p) { 01394 AST_LIST_TRAVERSE(&agents, p, list) { 01395 ast_mutex_lock(&p->lock); 01396 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01397 if (p->chan || !ast_strlen_zero(p->loginchan)) 01398 hasagent++; 01399 tv = ast_tvnow(); 01400 #if 0 01401 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec); 01402 #endif 01403 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01404 p->lastdisc = ast_tv(0, 0); 01405 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01406 if (!p->owner && p->chan) { 01407 /* Could still get a fixed agent */ 01408 chan = agent_new(p, AST_STATE_DOWN); 01409 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01410 /* Adjustable agent */ 01411 p->chan = ast_request("Local", format, p->loginchan, cause); 01412 if (p->chan) 01413 chan = agent_new(p, AST_STATE_DOWN); 01414 } 01415 if (chan) { 01416 ast_mutex_unlock(&p->lock); 01417 break; 01418 } 01419 } 01420 } 01421 ast_mutex_unlock(&p->lock); 01422 } 01423 } 01424 01425 if (!chan && waitforagent) { 01426 /* No agent available -- but we're requesting to wait for one. 01427 Allocate a place holder */ 01428 if (hasagent) { 01429 if (option_debug) 01430 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); 01431 p = add_agent(data, 1); 01432 p->group = groupmatch; 01433 chan = agent_new(p, AST_STATE_DOWN); 01434 if (!chan) 01435 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01436 } else 01437 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); 01438 } 01439 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01440 AST_LIST_UNLOCK(&agents); 01441 return chan; 01442 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 550 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.
00551 { 00552 struct agent_pvt *p = ast->tech_pvt; 00553 int res = -1; 00554 ast_mutex_lock(&p->lock); 00555 if (p->chan) 00556 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00557 ast_mutex_unlock(&p->lock); 00558 return res; 00559 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 561 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.
00562 { 00563 struct agent_pvt *p = ast->tech_pvt; 00564 int res = -1; 00565 ast_mutex_lock(&p->lock); 00566 if (p->chan) 00567 res = ast_sendtext(p->chan, text); 00568 ast_mutex_unlock(&p->lock); 00569 return res; 00570 }
int agent_set_base_channel | ( | struct ast_channel * | chan, | |
struct ast_channel * | base | |||
) | [static] |
Definition at line 757 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00758 { 00759 struct agent_pvt *p = NULL; 00760 00761 if (!chan || !base) { 00762 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00763 return -1; 00764 } 00765 p = chan->tech_pvt; 00766 if (!p) { 00767 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00768 return -1; 00769 } 00770 p->chan = base; 00771 return 0; 00772 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 437 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00438 { 00439 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00440 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 572 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.
00573 { 00574 struct agent_pvt *p = ast->tech_pvt; 00575 int res = -1; 00576 CHECK_FORMATS(ast, p); 00577 ast_mutex_lock(&p->lock); 00578 if (!p->chan) 00579 res = 0; 00580 else { 00581 if ((f->frametype != AST_FRAME_VOICE) || 00582 (f->frametype != AST_FRAME_VIDEO) || 00583 (f->subclass == p->chan->writeformat)) { 00584 res = ast_write(p->chan, f); 00585 } else { 00586 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00587 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00588 ast->name, p->chan->name); 00589 res = 0; 00590 } 00591 } 00592 CLEANUP(ast, p); 00593 ast_mutex_unlock(&p->lock); 00594 return res; 00595 }
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 2420 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().
02421 { 02422 int exitifnoagentid = 0; 02423 int nowarnings = 0; 02424 int changeoutgoing = 0; 02425 int res = 0; 02426 char agent[AST_MAX_AGENT]; 02427 02428 if (data) { 02429 if (strchr(data, 'd')) 02430 exitifnoagentid = 1; 02431 if (strchr(data, 'n')) 02432 nowarnings = 1; 02433 if (strchr(data, 'c')) 02434 changeoutgoing = 1; 02435 } 02436 if (chan->cid.cid_num) { 02437 const char *tmp; 02438 char agentvar[AST_MAX_BUF]; 02439 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02440 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02441 struct agent_pvt *p; 02442 ast_copy_string(agent, tmp, sizeof(agent)); 02443 AST_LIST_LOCK(&agents); 02444 AST_LIST_TRAVERSE(&agents, p, list) { 02445 if (!strcasecmp(p->agent, tmp)) { 02446 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02447 __agent_start_monitoring(chan, p, 1); 02448 break; 02449 } 02450 } 02451 AST_LIST_UNLOCK(&agents); 02452 02453 } else { 02454 res = -1; 02455 if (!nowarnings) 02456 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); 02457 } 02458 } else { 02459 res = -1; 02460 if (!nowarnings) 02461 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"); 02462 } 02463 /* check if there is n + 101 priority */ 02464 /*! \todo XXX Needs to check option priorityjump etc etc */ 02465 if (res) { 02466 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) { 02467 chan->priority+=100; 02468 if (option_verbose > 2) 02469 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); 02470 } else if (exitifnoagentid) 02471 return res; 02472 } 02473 return 0; 02474 }
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 1697 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.
01698 { 01699 struct agent_pvt *p; 01700 char username[AST_MAX_BUF]; 01701 char location[AST_MAX_BUF] = ""; 01702 char talkingto[AST_MAX_BUF] = ""; 01703 char moh[AST_MAX_BUF]; 01704 int count_agents = 0; /*!< Number of agents configured */ 01705 int online_agents = 0; /*!< Number of online agents */ 01706 int offline_agents = 0; /*!< Number of offline agents */ 01707 if (argc != 2) 01708 return RESULT_SHOWUSAGE; 01709 AST_LIST_LOCK(&agents); 01710 AST_LIST_TRAVERSE(&agents, p, list) { 01711 ast_mutex_lock(&p->lock); 01712 if (p->pending) { 01713 if (p->group) 01714 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group)); 01715 else 01716 ast_cli(fd, "-- Pending call to agent %s\n", p->agent); 01717 } else { 01718 if (!ast_strlen_zero(p->name)) 01719 snprintf(username, sizeof(username), "(%s) ", p->name); 01720 else 01721 username[0] = '\0'; 01722 if (p->chan) { 01723 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01724 if (p->owner && ast_bridged_channel(p->owner)) 01725 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01726 else 01727 strcpy(talkingto, " is idle"); 01728 online_agents++; 01729 } else if (!ast_strlen_zero(p->loginchan)) { 01730 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01731 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01732 else 01733 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01734 talkingto[0] = '\0'; 01735 online_agents++; 01736 if (p->acknowledged) 01737 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01738 } else { 01739 strcpy(location, "not logged in"); 01740 talkingto[0] = '\0'; 01741 offline_agents++; 01742 } 01743 if (!ast_strlen_zero(p->moh)) 01744 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01745 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 01746 username, location, talkingto, moh); 01747 count_agents++; 01748 } 01749 ast_mutex_unlock(&p->lock); 01750 } 01751 AST_LIST_UNLOCK(&agents); 01752 if ( !count_agents ) 01753 ast_cli(fd, "No Agents are configured in %s\n",config); 01754 else 01755 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01756 ast_cli(fd, "\n"); 01757 01758 return RESULT_SUCCESS; 01759 }
static int agents_show_online | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1762 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.
01763 { 01764 struct agent_pvt *p; 01765 char username[AST_MAX_BUF]; 01766 char location[AST_MAX_BUF] = ""; 01767 char talkingto[AST_MAX_BUF] = ""; 01768 char moh[AST_MAX_BUF]; 01769 int count_agents = 0; /* Number of agents configured */ 01770 int online_agents = 0; /* Number of online agents */ 01771 int agent_status = 0; /* 0 means offline, 1 means online */ 01772 if (argc != 3) 01773 return RESULT_SHOWUSAGE; 01774 AST_LIST_LOCK(&agents); 01775 AST_LIST_TRAVERSE(&agents, p, list) { 01776 agent_status = 0; /* reset it to offline */ 01777 ast_mutex_lock(&p->lock); 01778 if (!ast_strlen_zero(p->name)) 01779 snprintf(username, sizeof(username), "(%s) ", p->name); 01780 else 01781 username[0] = '\0'; 01782 if (p->chan) { 01783 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01784 if (p->owner && ast_bridged_channel(p->owner)) 01785 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01786 else 01787 strcpy(talkingto, " is idle"); 01788 agent_status = 1; 01789 online_agents++; 01790 } else if (!ast_strlen_zero(p->loginchan)) { 01791 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01792 talkingto[0] = '\0'; 01793 agent_status = 1; 01794 online_agents++; 01795 if (p->acknowledged) 01796 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01797 } 01798 if (!ast_strlen_zero(p->moh)) 01799 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01800 if (agent_status) 01801 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh); 01802 count_agents++; 01803 ast_mutex_unlock(&p->lock); 01804 } 01805 AST_LIST_UNLOCK(&agents); 01806 if (!count_agents) 01807 ast_cli(fd, "No Agents are configured in %s\n", config); 01808 else 01809 ast_cli(fd, "%d agents online\n", online_agents); 01810 ast_cli(fd, "\n"); 01811 return RESULT_SUCCESS; 01812 }
static int allow_multiple_login | ( | char * | chan, | |
char * | context | |||
) | [static] |
Definition at line 1329 of file chan_agent.c.
References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.
Referenced by __login_exec().
01330 { 01331 struct agent_pvt *p; 01332 char loginchan[80]; 01333 01334 if(multiplelogin) 01335 return 1; 01336 if(!chan) 01337 return 0; 01338 01339 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); 01340 01341 AST_LIST_TRAVERSE(&agents, p, list) { 01342 if(!strcasecmp(chan, p->loginchan)) 01343 return 0; 01344 } 01345 return -1; 01346 }
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 2301 of file chan_agent.c.
References ast_log(), depwarning, and LOG_WARNING.
Referenced by action_agent_callback_login(), and callback_exec().
02302 { 02303 static int depwarning = 0; 02304 02305 if (!depwarning) { 02306 depwarning = 1; 02307 02308 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n"); 02309 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n"); 02310 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n"); 02311 } 02312 }
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 2322 of file chan_agent.c.
References __login_exec(), callback_deprecated(), and ast_module_user::chan.
Referenced by load_module().
02323 { 02324 callback_deprecated(); 02325 02326 return __login_exec(chan, data, 1); 02327 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1215 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().
01216 { 01217 struct ast_channel *chan=NULL, *parent=NULL; 01218 struct agent_pvt *p; 01219 int res; 01220 01221 if (option_debug) 01222 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); 01223 if (needlock) 01224 AST_LIST_LOCK(&agents); 01225 AST_LIST_TRAVERSE(&agents, p, list) { 01226 if (p == newlyavailable) { 01227 continue; 01228 } 01229 ast_mutex_lock(&p->lock); 01230 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01231 if (option_debug) 01232 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01233 /* We found a pending call, time to merge */ 01234 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01235 parent = p->owner; 01236 p->abouttograb = 1; 01237 ast_mutex_unlock(&p->lock); 01238 break; 01239 } 01240 ast_mutex_unlock(&p->lock); 01241 } 01242 if (needlock) 01243 AST_LIST_UNLOCK(&agents); 01244 if (parent && chan) { 01245 if (newlyavailable->ackcall > 1) { 01246 /* Don't do beep here */ 01247 res = 0; 01248 } else { 01249 if (option_debug > 2) 01250 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01251 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01252 if (option_debug > 2) 01253 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01254 if (!res) { 01255 res = ast_waitstream(newlyavailable->chan, ""); 01256 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01257 } 01258 } 01259 if (!res) { 01260 /* Note -- parent may have disappeared */ 01261 if (p->abouttograb) { 01262 newlyavailable->acknowledged = 1; 01263 /* Safe -- agent lock already held */ 01264 ast_setstate(parent, AST_STATE_UP); 01265 ast_setstate(chan, AST_STATE_UP); 01266 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01267 /* Go ahead and mark the channel as a zombie so that masquerade will 01268 destroy it for us, and we need not call ast_hangup */ 01269 ast_mutex_lock(&parent->lock); 01270 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01271 ast_channel_masquerade(parent, chan); 01272 ast_mutex_unlock(&parent->lock); 01273 p->abouttograb = 0; 01274 } else { 01275 if (option_debug) 01276 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); 01277 agent_cleanup(newlyavailable); 01278 } 01279 } else { 01280 if (option_debug) 01281 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); 01282 agent_cleanup(newlyavailable); 01283 } 01284 } 01285 return 0; 01286 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1288 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().
01289 { 01290 struct agent_pvt *p; 01291 int res=0; 01292 01293 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); 01294 if (needlock) 01295 AST_LIST_LOCK(&agents); 01296 AST_LIST_TRAVERSE(&agents, p, list) { 01297 if (p == newlyavailable) { 01298 continue; 01299 } 01300 ast_mutex_lock(&p->lock); 01301 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01302 if (option_debug) 01303 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01304 ast_mutex_unlock(&p->lock); 01305 break; 01306 } 01307 ast_mutex_unlock(&p->lock); 01308 } 01309 if (needlock) 01310 AST_LIST_UNLOCK(&agents); 01311 if (p) { 01312 ast_mutex_unlock(&newlyavailable->lock); 01313 if (option_debug > 2) 01314 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01315 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01316 if (option_debug > 2) 01317 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01318 if (!res) { 01319 res = ast_waitstream(newlyavailable->chan, ""); 01320 if (option_debug) 01321 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01322 } 01323 ast_mutex_lock(&newlyavailable->lock); 01324 } 01325 return res; 01326 }
static char* complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1670 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.
01671 { 01672 char *ret = NULL; 01673 01674 if (pos == 2) { 01675 struct agent_pvt *p; 01676 char name[AST_MAX_AGENT]; 01677 int which = 0, len = strlen(word); 01678 01679 AST_LIST_LOCK(&agents); 01680 AST_LIST_TRAVERSE(&agents, p, list) { 01681 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01682 if (!strncasecmp(word, name, len) && ++which > state) { 01683 ret = ast_strdup(name); 01684 break; 01685 } 01686 } 01687 AST_LIST_UNLOCK(&agents); 01688 } else if (pos == 3 && state == 0) 01689 return ast_strdup("soft"); 01690 01691 return ret; 01692 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2479 of file chan_agent.c.
References agent_pvt::agent, ast_db_del(), ast_db_put(), AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), agent_pvt::chan, LOG_DEBUG, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, and option_debug.
Referenced by __login_exec(), action_agent_callback_login(), agent_hangup(), and agent_logoff_maintenance().
02480 { 02481 struct agent_pvt *cur_agent = NULL; 02482 char buf[256]; 02483 02484 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02485 if (cur_agent->chan) 02486 continue; 02487 02488 if (!ast_strlen_zero(cur_agent->loginchan)) { 02489 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02490 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02491 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02492 else if (option_debug) 02493 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02494 } else { 02495 /* Delete - no agent or there is an error */ 02496 ast_db_del(pa_family, cur_agent->agent); 02497 } 02498 } 02499 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2605 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02606 { 02607 struct agent_pvt *cur; 02608 02609 AST_LIST_TRAVERSE(&agents, cur, list) { 02610 if (!strcmp(cur->agent, agentid)) 02611 break; 02612 } 02613 02614 return cur; 02615 }
static int function_agent | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2617 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().
02618 { 02619 char *parse; 02620 AST_DECLARE_APP_ARGS(args, 02621 AST_APP_ARG(agentid); 02622 AST_APP_ARG(item); 02623 ); 02624 char *tmp; 02625 struct agent_pvt *agent; 02626 02627 buf[0] = '\0'; 02628 02629 if (ast_strlen_zero(data)) { 02630 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02631 return -1; 02632 } 02633 02634 parse = ast_strdupa(data); 02635 02636 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02637 if (!args.item) 02638 args.item = "status"; 02639 02640 AST_LIST_LOCK(&agents); 02641 02642 if (!(agent = find_agent(args.agentid))) { 02643 AST_LIST_UNLOCK(&agents); 02644 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02645 return -1; 02646 } 02647 02648 if (!strcasecmp(args.item, "status")) { 02649 char *status = "LOGGEDOUT"; 02650 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02651 status = "LOGGEDIN"; 02652 ast_copy_string(buf, status, len); 02653 } else if (!strcasecmp(args.item, "password")) 02654 ast_copy_string(buf, agent->password, len); 02655 else if (!strcasecmp(args.item, "name")) 02656 ast_copy_string(buf, agent->name, len); 02657 else if (!strcasecmp(args.item, "mohclass")) 02658 ast_copy_string(buf, agent->moh, len); 02659 else if (!strcasecmp(args.item, "channel")) { 02660 if (agent->chan) { 02661 ast_copy_string(buf, agent->chan->name, len); 02662 tmp = strrchr(buf, '-'); 02663 if (tmp) 02664 *tmp = '\0'; 02665 } 02666 } else if (!strcasecmp(args.item, "exten")) 02667 ast_copy_string(buf, agent->loginchan, len); 02668 02669 AST_LIST_UNLOCK(&agents); 02670 02671 return 0; 02672 }
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 2697 of file chan_agent.c.
References action_agent_callback_login(), action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register(), ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, ast_register_application(), callback_exec(), cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().
02698 { 02699 /* Make sure we can register our agent channel type */ 02700 if (ast_channel_register(&agent_tech)) { 02701 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02702 return -1; 02703 } 02704 /* Read in the config */ 02705 if (!read_agent_config()) 02706 return AST_MODULE_LOAD_DECLINE; 02707 if (persistent_agents) 02708 reload_agents(); 02709 /* Dialplan applications */ 02710 ast_register_application(app, login_exec, synopsis, descrip); 02711 ast_register_application(app2, callback_exec, synopsis2, descrip2); 02712 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02713 02714 /* Manager commands */ 02715 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02716 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02717 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login); 02718 02719 /* CLI Commands */ 02720 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02721 02722 /* Dialplan Functions */ 02723 ast_custom_function_register(&agent_function); 02724 02725 return 0; 02726 }
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 2296 of file chan_agent.c.
References __login_exec(), and ast_module_user::chan.
Referenced by load_module().
02297 { 02298 return __login_exec(chan, data, 0); 02299 }
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 1066 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().
01067 { 01068 struct ast_config *cfg; 01069 struct ast_config *ucfg; 01070 struct ast_variable *v; 01071 struct agent_pvt *p; 01072 const char *general_val; 01073 const char *catname; 01074 const char *hasagent; 01075 int genhasagent; 01076 01077 group = 0; 01078 autologoff = 0; 01079 wrapuptime = 0; 01080 ackcall = 0; 01081 endcall = 1; 01082 cfg = ast_config_load(config); 01083 if (!cfg) { 01084 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01085 return 0; 01086 } 01087 AST_LIST_LOCK(&agents); 01088 AST_LIST_TRAVERSE(&agents, p, list) { 01089 p->dead = 1; 01090 } 01091 strcpy(moh, "default"); 01092 /* set the default recording values */ 01093 recordagentcalls = 0; 01094 strcpy(recordformat, "wav"); 01095 strcpy(recordformatext, "wav"); 01096 urlprefix[0] = '\0'; 01097 savecallsin[0] = '\0'; 01098 01099 /* Read in [general] section for persistence */ 01100 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01101 persistent_agents = ast_true(general_val); 01102 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01103 01104 /* Read in the [agents] section */ 01105 v = ast_variable_browse(cfg, "agents"); 01106 while(v) { 01107 /* Create the interface list */ 01108 if (!strcasecmp(v->name, "agent")) { 01109 add_agent(v->value, 0); 01110 } else if (!strcasecmp(v->name, "group")) { 01111 group = ast_get_group(v->value); 01112 } else if (!strcasecmp(v->name, "autologoff")) { 01113 autologoff = atoi(v->value); 01114 if (autologoff < 0) 01115 autologoff = 0; 01116 } else if (!strcasecmp(v->name, "ackcall")) { 01117 if (!strcasecmp(v->value, "always")) 01118 ackcall = 2; 01119 else if (ast_true(v->value)) 01120 ackcall = 1; 01121 else 01122 ackcall = 0; 01123 } else if (!strcasecmp(v->name, "endcall")) { 01124 endcall = ast_true(v->value); 01125 } else if (!strcasecmp(v->name, "wrapuptime")) { 01126 wrapuptime = atoi(v->value); 01127 if (wrapuptime < 0) 01128 wrapuptime = 0; 01129 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01130 maxlogintries = atoi(v->value); 01131 if (maxlogintries < 0) 01132 maxlogintries = 0; 01133 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01134 strcpy(agentgoodbye,v->value); 01135 } else if (!strcasecmp(v->name, "musiconhold")) { 01136 ast_copy_string(moh, v->value, sizeof(moh)); 01137 } else if (!strcasecmp(v->name, "updatecdr")) { 01138 if (ast_true(v->value)) 01139 updatecdr = 1; 01140 else 01141 updatecdr = 0; 01142 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01143 if (ast_true(v->value)) 01144 autologoffunavail = 1; 01145 else 01146 autologoffunavail = 0; 01147 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01148 recordagentcalls = ast_true(v->value); 01149 } else if (!strcasecmp(v->name, "recordformat")) { 01150 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01151 if (!strcasecmp(v->value, "wav49")) 01152 strcpy(recordformatext, "WAV"); 01153 else 01154 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01155 } else if (!strcasecmp(v->name, "urlprefix")) { 01156 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01157 if (urlprefix[strlen(urlprefix) - 1] != '/') 01158 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01159 } else if (!strcasecmp(v->name, "savecallsin")) { 01160 if (v->value[0] == '/') 01161 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01162 else 01163 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01164 if (savecallsin[strlen(savecallsin) - 1] != '/') 01165 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01166 } else if (!strcasecmp(v->name, "custom_beep")) { 01167 ast_copy_string(beep, v->value, sizeof(beep)); 01168 } 01169 v = v->next; 01170 } 01171 if ((ucfg = ast_config_load("users.conf"))) { 01172 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01173 catname = ast_category_browse(ucfg, NULL); 01174 while(catname) { 01175 if (strcasecmp(catname, "general")) { 01176 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01177 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01178 char tmp[256]; 01179 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01180 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01181 if (!fullname) 01182 fullname = ""; 01183 if (!secret) 01184 secret = ""; 01185 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01186 add_agent(tmp, 0); 01187 } 01188 } 01189 catname = ast_category_browse(ucfg, catname); 01190 } 01191 ast_config_destroy(ucfg); 01192 } 01193 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01194 if (p->dead) { 01195 AST_LIST_REMOVE_CURRENT(&agents, list); 01196 /* Destroy if appropriate */ 01197 if (!p->owner) { 01198 if (!p->chan) { 01199 ast_mutex_destroy(&p->lock); 01200 ast_mutex_destroy(&p->app_lock); 01201 free(p); 01202 } else { 01203 /* Cause them to hang up */ 01204 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01205 } 01206 } 01207 } 01208 } 01209 AST_LIST_TRAVERSE_SAFE_END 01210 AST_LIST_UNLOCK(&agents); 01211 ast_config_destroy(cfg); 01212 return 1; 01213 }
static int reload | ( | void | ) | [static] |
Definition at line 2728 of file chan_agent.c.
References read_agent_config(), and reload_agents().
Referenced by moh_cli(), reload(), rpt_do_reload(), and show_console().
02729 { 02730 read_agent_config(); 02731 if (persistent_agents) 02732 reload_agents(); 02733 return 0; 02734 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2504 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().
02505 { 02506 char *agent_num; 02507 struct ast_db_entry *db_tree; 02508 struct ast_db_entry *entry; 02509 struct agent_pvt *cur_agent; 02510 char agent_data[256]; 02511 char *parse; 02512 char *agent_chan; 02513 char *agent_callerid; 02514 02515 db_tree = ast_db_gettree(pa_family, NULL); 02516 02517 AST_LIST_LOCK(&agents); 02518 for (entry = db_tree; entry; entry = entry->next) { 02519 agent_num = entry->key + strlen(pa_family) + 2; 02520 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02521 ast_mutex_lock(&cur_agent->lock); 02522 if (strcmp(agent_num, cur_agent->agent) == 0) 02523 break; 02524 ast_mutex_unlock(&cur_agent->lock); 02525 } 02526 if (!cur_agent) { 02527 ast_db_del(pa_family, agent_num); 02528 continue; 02529 } else 02530 ast_mutex_unlock(&cur_agent->lock); 02531 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02532 if (option_debug) 02533 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02534 parse = agent_data; 02535 agent_chan = strsep(&parse, ";"); 02536 agent_callerid = strsep(&parse, ";"); 02537 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02538 if (agent_callerid) { 02539 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02540 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02541 } else 02542 cur_agent->logincallerid[0] = '\0'; 02543 if (cur_agent->loginstart == 0) 02544 time(&cur_agent->loginstart); 02545 ast_device_state_changed("Agent/%s", cur_agent->agent); 02546 } 02547 } 02548 AST_LIST_UNLOCK(&agents); 02549 if (db_tree) { 02550 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02551 ast_db_freetree(db_tree); 02552 } 02553 }
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 728 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().
00729 { 00730 char buf[AST_MAX_BUF]; 00731 00732 /* if there is no Caller ID, nothing to do */ 00733 if (ast_strlen_zero(callerid)) 00734 return; 00735 00736 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00737 pbx_builtin_setvar_helper(NULL, buf, agent); 00738 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2736 of file chan_agent.c.
References agent_function, agent_tech, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), AST_LIST_HEAD_DESTROY, 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().
02737 { 02738 struct agent_pvt *p; 02739 /* First, take us out of the channel loop */ 02740 ast_channel_unregister(&agent_tech); 02741 /* Unregister dialplan functions */ 02742 ast_custom_function_unregister(&agent_function); 02743 /* Unregister CLI commands */ 02744 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02745 /* Unregister dialplan applications */ 02746 ast_unregister_application(app); 02747 ast_unregister_application(app2); 02748 ast_unregister_application(app3); 02749 /* Unregister manager command */ 02750 ast_manager_unregister("Agents"); 02751 ast_manager_unregister("AgentLogoff"); 02752 ast_manager_unregister("AgentCallbackLogin"); 02753 /* Unregister channel */ 02754 AST_LIST_LOCK(&agents); 02755 /* Hangup all interfaces if they have an owner */ 02756 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02757 if (p->owner) 02758 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02759 free(p); 02760 } 02761 AST_LIST_UNLOCK(&agents); 02762 AST_LIST_HEAD_DESTROY(&agents); 02763 return 0; 02764 }
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 1824 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 261 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 1829 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 1834 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 1820 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 1816 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.