#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"
Include dependency graph for chan_agent.c:

Go to the source code of this file.
Data Structures | |
| struct | agent_pvt |
| Structure representing an agent. More... | |
Defines | |
| #define | AST_MAX_AGENT 80 |
| #define | AST_MAX_BUF 256 |
| #define | AST_MAX_FILENAME_LEN 256 |
| #define | CHECK_FORMATS(ast, p) |
| #define | CLEANUP(ast, p) |
| Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
| #define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
| #define | PA_MAX_LEN 2048 |
Functions | |
| static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
| static int | __login_exec (struct ast_channel *chan, void *data, int callbackmode) |
| Log in agent application. | |
| static int | action_agent_callback_login (struct mansession *s, const struct message *m) |
| static int | action_agent_logoff (struct mansession *s, const struct message *m) |
| static int | action_agents (struct mansession *s, const struct message *m) |
| static struct agent_pvt * | add_agent (char *agent, int pending) |
| static int | agent_ack_sleep (void *data) |
| static int | agent_answer (struct ast_channel *ast) |
| static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
| static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
| static int | agent_cleanup (struct agent_pvt *p) |
| static int | agent_cont_sleep (void *data) |
| static int | agent_devicestate (void *data) |
| Part of PBX channel interface. | |
| static int | agent_devicestate_cb (const char *dev, int state, void *data) |
| static int | agent_digit_begin (struct ast_channel *ast, char digit) |
| static int | agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
| static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
| static struct ast_channel * | agent_get_base_channel (struct ast_channel *chan) |
| return the channel or base channel if one exists. This function assumes the channel it is called on is already locked | |
| static int | agent_hangup (struct ast_channel *ast) |
| static int | agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
| static int | agent_logoff (const char *agent, int soft) |
| static int | agent_logoff_cmd (int fd, int argc, char **argv) |
| static void | agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand) |
| static struct ast_channel * | agent_new (struct agent_pvt *p, int state) |
| Create new agent channel. | |
| static struct ast_frame * | agent_read (struct ast_channel *ast) |
| static struct ast_channel * | agent_request (const char *type, int format, void *data, int *cause) |
| Part of the Asterisk PBX interface. | |
| static int | agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen) |
| static int | agent_sendtext (struct ast_channel *ast, const char *text) |
| static int | agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base) |
| static int | agent_start_monitoring (struct ast_channel *ast, int needlock) |
| static int | agent_write (struct ast_channel *ast, struct ast_frame *f) |
| static int | agentmonitoroutgoing_exec (struct ast_channel *chan, void *data) |
| Called by the AgentMonitorOutgoing application (from the dial plan). | |
| static int | agents_show (int fd, int argc, char **argv) |
| static int | agents_show_online (int fd, int argc, char **argv) |
| static int | allow_multiple_login (char *chan, char *context) |
| static | AST_LIST_HEAD_STATIC (agents, agent_pvt) |
| AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,) | |
| static void | callback_deprecated (void) |
| static int | callback_exec (struct ast_channel *chan, void *data) |
| static int | check_availability (struct agent_pvt *newlyavailable, int needlock) |
| static int | check_beep (struct agent_pvt *newlyavailable, int needlock) |
| static char * | complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state) |
| static void | dump_agents (void) |
| Dump AgentCallbackLogin agents to the ASTdb database for persistence. | |
| static struct agent_pvt * | find_agent (char *agentid) |
| static int | function_agent (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
| static int | load_module (void) |
| Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file. | |
| static int | login_exec (struct ast_channel *chan, void *data) |
| static force_inline int | powerof (unsigned int d) |
| static int | read_agent_config (void) |
| static int | reload (void) |
| static void | reload_agents (void) |
| Reload the persistent agents from astdb. | |
| static void | set_agentbycallerid (const char *callerid, const char *agent) |
| store/clear the global variable that stores agentid based on the callerid | |
| static int | unload_module (void) |
Variables | |
| static int | ackcall |
| ast_custom_function | agent_function |
| static char | agent_logoff_usage [] |
| static struct ast_channel_tech | agent_tech |
| Channel interface description for PBX integration. | |
| static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye" |
| static const char | app [] = "AgentLogin" |
| static const char | app2 [] = "AgentCallbackLogin" |
| static const char | app3 [] = "AgentMonitorOutgoing" |
| static int | autologoff |
| static int | autologoffunavail = 0 |
| static char | beep [AST_MAX_BUF] = "beep" |
| static struct ast_cli_entry | cli_agents [] |
| static struct ast_cli_entry | cli_show_agents_deprecated |
| static struct ast_cli_entry | cli_show_agents_online_deprecated |
| static const char | config [] = "agents.conf" |
| static const char | descrip [] |
| static const char | descrip2 [] |
| static const char | descrip3 [] |
| static int | endcall |
| static ast_group_t | group |
| static const char | mandescr_agent_callback_login [] |
| static const char | mandescr_agent_logoff [] |
| static const char | mandescr_agents [] |
| static int | maxlogintries = 3 |
| static char | moh [80] = "default" |
| static int | multiplelogin = 1 |
| static const char | pa_family [] = "Agents" |
| static int | persistent_agents = 0 |
| static int | recordagentcalls = 0 |
| static char | recordformat [AST_MAX_BUF] = "" |
| static char | recordformatext [AST_MAX_BUF] = "" |
| static char | savecallsin [AST_MAX_BUF] = "" |
| static char | show_agents_online_usage [] |
| static char | show_agents_usage [] |
| static const char | synopsis [] = "Call agent login" |
| static const char | synopsis2 [] = "Call agent callback login" |
| static const char | synopsis3 [] = "Record agent's outgoing call" |
| static const char | tdesc [] = "Call Agent Proxy Channel" |
| static int | updatecdr = 0 |
| static char | urlprefix [AST_MAX_BUF] = "" |
| static int | wrapuptime |
This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.
Definition in file chan_agent.c.
| #define AST_MAX_AGENT 80 |
Agent ID or Password max length
Definition at line 146 of file chan_agent.c.
Referenced by __login_exec(), agent_logoff_maintenance(), agentmonitoroutgoing_exec(), and complete_agent_logoff_cmd().
| #define AST_MAX_BUF 256 |
Definition at line 147 of file chan_agent.c.
Referenced by __agent_start_monitoring(), __login_exec(), agentmonitoroutgoing_exec(), agents_show(), agents_show_online(), and set_agentbycallerid().
| #define AST_MAX_FILENAME_LEN 256 |
| #define CHECK_FORMATS | ( | ast, | |||
| p | ) |
| #define CLEANUP | ( | ast, | |||
| p | ) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
Definition at line 230 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
| #define GETAGENTBYCALLERID "AGENTBYCALLERID" |
Definition at line 175 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().
| #define PA_MAX_LEN 2048 |
The maximum length of each persistent member agent database entry
Definition at line 151 of file chan_agent.c.
| static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
| struct agent_pvt * | p, | |||
| int | needlock | |||
| ) | [static] |
Definition at line 450 of file chan_agent.c.
References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose(), ast_channel::cdr, LOG_ERROR, and ast_channel::monitor.
Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().
00451 { 00452 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00453 char filename[AST_MAX_BUF]; 00454 int res = -1; 00455 if (!p) 00456 return -1; 00457 if (!ast->monitor) { 00458 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00459 /* substitute . for - */ 00460 if ((pointer = strchr(filename, '.'))) 00461 *pointer = '-'; 00462 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00463 ast_monitor_start(ast, recordformat, tmp, needlock); 00464 ast_monitor_setjoinfiles(ast, 1); 00465 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00466 #if 0 00467 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00468 #endif 00469 if (!ast->cdr) 00470 ast->cdr = ast_cdr_alloc(); 00471 ast_cdr_setuserfield(ast, tmp2); 00472 res = 0; 00473 } else 00474 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00475 return res; 00476 }
| static int __login_exec | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| int | callbackmode | |||
| ) | [static] |
Log in agent application.
| chan | ||
| data | ||
| callbackmode | non-zero for AgentCallbackLogin |
Definition at line 1918 of file chan_agent.c.
References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
Referenced by callback_exec(), and login_exec().
01919 { 01920 int res=0; 01921 int tries = 0; 01922 int max_login_tries = maxlogintries; 01923 struct agent_pvt *p; 01924 struct ast_module_user *u; 01925 int login_state = 0; 01926 char user[AST_MAX_AGENT] = ""; 01927 char pass[AST_MAX_AGENT]; 01928 char agent[AST_MAX_AGENT] = ""; 01929 char xpass[AST_MAX_AGENT] = ""; 01930 char *errmsg; 01931 char *parse; 01932 AST_DECLARE_APP_ARGS(args, 01933 AST_APP_ARG(agent_id); 01934 AST_APP_ARG(options); 01935 AST_APP_ARG(extension); 01936 ); 01937 const char *tmpoptions = NULL; 01938 char *context = NULL; 01939 int play_announcement = 1; 01940 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01941 int update_cdr = updatecdr; 01942 char *filename = "agent-loginok"; 01943 char tmpchan[AST_MAX_BUF] = ""; 01944 01945 u = ast_module_user_add(chan); 01946 01947 parse = ast_strdupa(data); 01948 01949 AST_STANDARD_APP_ARGS(args, parse); 01950 01951 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01952 01953 ast_channel_lock(chan); 01954 /* Set Channel Specific Login Overrides */ 01955 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01956 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01957 if (max_login_tries < 0) 01958 max_login_tries = 0; 01959 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01960 if (option_verbose > 2) 01961 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 01962 } 01963 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01964 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01965 update_cdr = 1; 01966 else 01967 update_cdr = 0; 01968 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01969 if (option_verbose > 2) 01970 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01971 } 01972 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01973 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01974 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01975 if (option_verbose > 2) 01976 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01977 } 01978 ast_channel_unlock(chan); 01979 /* End Channel Specific Login Overrides */ 01980 01981 if (callbackmode && args.extension) { 01982 parse = args.extension; 01983 args.extension = strsep(&parse, "@"); 01984 context = parse; 01985 } 01986 01987 if (!ast_strlen_zero(args.options)) { 01988 if (strchr(args.options, 's')) { 01989 play_announcement = 0; 01990 } 01991 } 01992 01993 if (chan->_state != AST_STATE_UP) 01994 res = ast_answer(chan); 01995 if (!res) { 01996 if (!ast_strlen_zero(args.agent_id)) 01997 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01998 else 01999 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 02000 } 02001 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 02002 tries++; 02003 /* Check for password */ 02004 AST_LIST_LOCK(&agents); 02005 AST_LIST_TRAVERSE(&agents, p, list) { 02006 if (!strcmp(p->agent, user) && !p->pending) 02007 ast_copy_string(xpass, p->password, sizeof(xpass)); 02008 } 02009 AST_LIST_UNLOCK(&agents); 02010 if (!res) { 02011 if (!ast_strlen_zero(xpass)) 02012 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 02013 else 02014 pass[0] = '\0'; 02015 } 02016 errmsg = "agent-incorrect"; 02017 02018 #if 0 02019 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 02020 #endif 02021 02022 /* Check again for accuracy */ 02023 AST_LIST_LOCK(&agents); 02024 AST_LIST_TRAVERSE(&agents, p, list) { 02025 int unlock_channel = 1; 02026 ast_channel_lock(chan); 02027 ast_mutex_lock(&p->lock); 02028 if (!strcmp(p->agent, user) && 02029 !strcmp(p->password, pass) && !p->pending) { 02030 login_state = 1; /* Successful Login */ 02031 02032 /* Ensure we can't be gotten until we're done */ 02033 gettimeofday(&p->lastdisc, NULL); 02034 p->lastdisc.tv_sec++; 02035 02036 /* Set Channel Specific Agent Overrides */ 02037 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02038 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 02039 p->ackcall = 2; 02040 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 02041 p->ackcall = 1; 02042 else 02043 p->ackcall = 0; 02044 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02045 if (option_verbose > 2) 02046 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 02047 } else { 02048 p->ackcall = ackcall; 02049 } 02050 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02051 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02052 if (p->autologoff < 0) 02053 p->autologoff = 0; 02054 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02055 if (option_verbose > 2) 02056 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 02057 } else { 02058 p->autologoff = autologoff; 02059 } 02060 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02061 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02062 if (p->wrapuptime < 0) 02063 p->wrapuptime = 0; 02064 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02065 if (option_verbose > 2) 02066 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 02067 } else { 02068 p->wrapuptime = wrapuptime; 02069 } 02070 ast_channel_unlock(chan); 02071 unlock_channel = 0; 02072 /* End Channel Specific Agent Overrides */ 02073 if (!p->chan) { 02074 char last_loginchan[80] = ""; 02075 long logintime; 02076 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02077 02078 if (callbackmode) { 02079 int pos = 0; 02080 /* Retrieve login chan */ 02081 for (;;) { 02082 if (!ast_strlen_zero(args.extension)) { 02083 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 02084 res = 0; 02085 } else 02086 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 02087 if (ast_strlen_zero(tmpchan) ) 02088 break; 02089 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 02090 if(!allow_multiple_login(tmpchan,context) ) { 02091 args.extension = NULL; 02092 pos = 0; 02093 } else 02094 break; 02095 } 02096 if (args.extension) { 02097 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 02098 args.extension = NULL; 02099 pos = 0; 02100 } else { 02101 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 02102 res = ast_streamfile(chan, "invalid", chan->language); 02103 if (!res) 02104 res = ast_waitstream(chan, AST_DIGIT_ANY); 02105 if (res > 0) { 02106 tmpchan[0] = res; 02107 tmpchan[1] = '\0'; 02108 pos = 1; 02109 } else { 02110 tmpchan[0] = '\0'; 02111 pos = 0; 02112 } 02113 } 02114 } 02115 args.extension = tmpchan; 02116 if (!res) { 02117 set_agentbycallerid(p->logincallerid, NULL); 02118 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 02119 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 02120 else { 02121 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 02122 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 02123 } 02124 p->acknowledged = 0; 02125 if (ast_strlen_zero(p->loginchan)) { 02126 login_state = 2; 02127 filename = "agent-loggedoff"; 02128 } else { 02129 if (chan->cid.cid_num) { 02130 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 02131 set_agentbycallerid(p->logincallerid, p->agent); 02132 } else 02133 p->logincallerid[0] = '\0'; 02134 } 02135 02136 if(update_cdr && chan->cdr) 02137 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02138 02139 } 02140 } else { 02141 p->loginchan[0] = '\0'; 02142 p->logincallerid[0] = '\0'; 02143 p->acknowledged = 0; 02144 } 02145 ast_mutex_unlock(&p->lock); 02146 AST_LIST_UNLOCK(&agents); 02147 if( !res && play_announcement==1 ) 02148 res = ast_streamfile(chan, filename, chan->language); 02149 if (!res) 02150 ast_waitstream(chan, ""); 02151 AST_LIST_LOCK(&agents); 02152 ast_mutex_lock(&p->lock); 02153 if (!res) { 02154 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02155 if (res) 02156 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02157 } 02158 if (!res) { 02159 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02160 if (res) 02161 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02162 } 02163 /* Check once more just in case */ 02164 if (p->chan) 02165 res = -1; 02166 if (callbackmode && !res) { 02167 /* Just say goodbye and be done with it */ 02168 if (!ast_strlen_zero(p->loginchan)) { 02169 if (p->loginstart == 0) 02170 time(&p->loginstart); 02171 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02172 "Agent: %s\r\n" 02173 "Loginchan: %s\r\n" 02174 "Uniqueid: %s\r\n", 02175 p->agent, p->loginchan, chan->uniqueid); 02176 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02177 if (option_verbose > 1) 02178 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02179 ast_device_state_changed("Agent/%s", p->agent); 02180 if (persistent_agents) 02181 dump_agents(); 02182 } else { 02183 logintime = time(NULL) - p->loginstart; 02184 p->loginstart = 0; 02185 02186 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02187 if (option_verbose > 1) 02188 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02189 } 02190 AST_LIST_UNLOCK(&agents); 02191 if (!res) 02192 res = ast_safe_sleep(chan, 500); 02193 ast_mutex_unlock(&p->lock); 02194 } else if (!res) { 02195 ast_indicate_data(chan, AST_CONTROL_HOLD, 02196 S_OR(p->moh, NULL), 02197 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02198 if (p->loginstart == 0) 02199 time(&p->loginstart); 02200 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02201 "Agent: %s\r\n" 02202 "Channel: %s\r\n" 02203 "Uniqueid: %s\r\n", 02204 p->agent, chan->name, chan->uniqueid); 02205 if (update_cdr && chan->cdr) 02206 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02207 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02208 if (option_verbose > 1) 02209 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02210 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02211 /* Login this channel and wait for it to go away */ 02212 p->chan = chan; 02213 if (p->ackcall > 1) 02214 check_beep(p, 0); 02215 else 02216 check_availability(p, 0); 02217 ast_mutex_unlock(&p->lock); 02218 AST_LIST_UNLOCK(&agents); 02219 ast_device_state_changed("Agent/%s", p->agent); 02220 while (res >= 0) { 02221 ast_mutex_lock(&p->lock); 02222 if (p->deferlogoff && p->chan) { 02223 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02224 p->deferlogoff = 0; 02225 } 02226 if (p->chan != chan) 02227 res = -1; 02228 ast_mutex_unlock(&p->lock); 02229 /* Yield here so other interested threads can kick in. */ 02230 sched_yield(); 02231 if (res) 02232 break; 02233 02234 AST_LIST_LOCK(&agents); 02235 ast_mutex_lock(&p->lock); 02236 if (p->lastdisc.tv_sec) { 02237 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02238 if (option_debug) 02239 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02240 p->lastdisc = ast_tv(0, 0); 02241 ast_device_state_changed("Agent/%s", p->agent); 02242 if (p->ackcall > 1) 02243 check_beep(p, 0); 02244 else 02245 check_availability(p, 0); 02246 } 02247 } 02248 ast_mutex_unlock(&p->lock); 02249 AST_LIST_UNLOCK(&agents); 02250 /* Synchronize channel ownership between call to agent and itself. */ 02251 ast_mutex_lock( &p->app_lock ); 02252 ast_mutex_lock(&p->lock); 02253 p->owning_app = pthread_self(); 02254 ast_mutex_unlock(&p->lock); 02255 if (p->ackcall > 1) 02256 res = agent_ack_sleep(p); 02257 else 02258 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02259 ast_mutex_unlock( &p->app_lock ); 02260 if ((p->ackcall > 1) && (res == 1)) { 02261 AST_LIST_LOCK(&agents); 02262 ast_mutex_lock(&p->lock); 02263 check_availability(p, 0); 02264 ast_mutex_unlock(&p->lock); 02265 AST_LIST_UNLOCK(&agents); 02266 res = 0; 02267 } 02268 sched_yield(); 02269 } 02270 ast_mutex_lock(&p->lock); 02271 if (res && p->owner) 02272 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02273 /* Log us off if appropriate */ 02274 if (p->chan == chan) { 02275 p->chan = NULL; 02276 p->inherited_devicestate = -1; 02277 } 02278 p->acknowledged = 0; 02279 logintime = time(NULL) - p->loginstart; 02280 p->loginstart = 0; 02281 ast_mutex_unlock(&p->lock); 02282 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02283 "Agent: %s\r\n" 02284 "Logintime: %ld\r\n" 02285 "Uniqueid: %s\r\n", 02286 p->agent, logintime, chan->uniqueid); 02287 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02288 if (option_verbose > 1) 02289 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02290 /* If there is no owner, go ahead and kill it now */ 02291 ast_device_state_changed("Agent/%s", p->agent); 02292 if (p->dead && !p->owner) { 02293 ast_mutex_destroy(&p->lock); 02294 ast_mutex_destroy(&p->app_lock); 02295 free(p); 02296 } 02297 } 02298 else { 02299 ast_mutex_unlock(&p->lock); 02300 p = NULL; 02301 } 02302 res = -1; 02303 } else { 02304 ast_mutex_unlock(&p->lock); 02305 errmsg = "agent-alreadyon"; 02306 p = NULL; 02307 } 02308 break; 02309 } 02310 ast_m