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