#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
Include dependency graph for chan_agent.c:
Go to the source code of this file.
Data Structures | |
struct | agent_pvt |
Structure representing an agent. More... | |
Defines | |
#define | AST_MAX_AGENT 80 |
#define | AST_MAX_BUF 256 |
#define | AST_MAX_FILENAME_LEN 256 |
#define | CHECK_FORMATS(ast, p) |
#define | CLEANUP(ast, p) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
#define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
#define | PA_MAX_LEN 2048 |
Functions | |
static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
static int | __login_exec (struct ast_channel *chan, void *data, int callbackmode) |
Log in agent application. | |
static int | action_agent_callback_login (struct mansession *s, const struct message *m) |
static int | action_agent_logoff (struct mansession *s, const struct message *m) |
static int | action_agents (struct mansession *s, const struct message *m) |
static struct agent_pvt * | add_agent (char *agent, int pending) |
static int | agent_ack_sleep (void *data) |
static int | agent_answer (struct ast_channel *ast) |
static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
static int | agent_cleanup (struct agent_pvt *p) |
static int | agent_cont_sleep (void *data) |
static int | agent_devicestate (void *data) |
Part of PBX channel interface. | |
static int | agent_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 int | agent_hangup (struct ast_channel *ast) |
static int | agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
static int | agent_logoff (const char *agent, int soft) |
static int | agent_logoff_cmd (int fd, int argc, char **argv) |
static void | agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand) |
static struct ast_channel * | agent_new (struct agent_pvt *p, int state) |
Create new agent channel. | |
static struct ast_frame * | agent_read (struct ast_channel *ast) |
static struct ast_channel * | agent_request (const char *type, int format, void *data, int *cause) |
Part of the Asterisk PBX interface. | |
static int | agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen) |
static int | agent_sendtext (struct ast_channel *ast, const char *text) |
static int | agent_start_monitoring (struct ast_channel *ast, int needlock) |
static int | agent_write (struct ast_channel *ast, struct ast_frame *f) |
static int | agentmonitoroutgoing_exec (struct ast_channel *chan, void *data) |
Called by the AgentMonitorOutgoing application (from the dial plan). | |
static int | agents_show (int fd, int argc, char **argv) |
static int | agents_show_online (int fd, int argc, char **argv) |
static int | allow_multiple_login (char *chan, char *context) |
static | AST_LIST_HEAD_STATIC (agents, agent_pvt) |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,) | |
static void | callback_deprecated (void) |
static int | callback_exec (struct ast_channel *chan, void *data) |
static int | check_availability (struct agent_pvt *newlyavailable, int needlock) |
static int | check_beep (struct agent_pvt *newlyavailable, int needlock) |
static char * | complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state) |
static void | dump_agents (void) |
Dump AgentCallbackLogin agents to the ASTdb database for persistence. | |
static struct agent_pvt * | find_agent (char *agentid) |
static int | function_agent (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) |
static int | load_module (void) |
Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file. | |
static int | login_exec (struct ast_channel *chan, void *data) |
static force_inline int | powerof (unsigned int d) |
static int | read_agent_config (void) |
static int | reload (void) |
static void | reload_agents (void) |
Reload the persistent agents from astdb. | |
static void | set_agentbycallerid (const char *callerid, const char *agent) |
store/clear the global variable that stores agentid based on the callerid | |
static int | unload_module (void) |
Variables | |
static int | ackcall |
ast_custom_function | agent_function |
static char | agent_logoff_usage [] |
static struct ast_channel_tech | agent_tech |
Channel interface description for PBX integration. | |
static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye" |
static const char | app [] = "AgentLogin" |
static const char | app2 [] = "AgentCallbackLogin" |
static const char | app3 [] = "AgentMonitorOutgoing" |
static int | autologoff |
static int | autologoffunavail = 0 |
static char | beep [AST_MAX_BUF] = "beep" |
static struct ast_cli_entry | cli_agents [] |
static struct ast_cli_entry | cli_show_agents_deprecated |
static struct ast_cli_entry | cli_show_agents_online_deprecated |
static const char | config [] = "agents.conf" |
static const char | descrip [] |
static const char | descrip2 [] |
static const char | descrip3 [] |
static int | endcall |
static ast_group_t | group |
static const char | mandescr_agent_callback_login [] |
static const char | mandescr_agent_logoff [] |
static const char | mandescr_agents [] |
static int | maxlogintries = 3 |
static char | moh [80] = "default" |
static int | multiplelogin = 1 |
static const char | pa_family [] = "/Agents" |
static int | persistent_agents = 0 |
static int | recordagentcalls = 0 |
static char | recordformat [AST_MAX_BUF] = "" |
static char | recordformatext [AST_MAX_BUF] = "" |
static char | savecallsin [AST_MAX_BUF] = "" |
static char | show_agents_online_usage [] |
static char | show_agents_usage [] |
static const char | synopsis [] = "Call agent login" |
static const char | synopsis2 [] = "Call agent callback login" |
static const char | synopsis3 [] = "Record agent's outgoing call" |
static const char | tdesc [] = "Call Agent Proxy Channel" |
static int | updatecdr = 0 |
static char | urlprefix [AST_MAX_BUF] = "" |
static int | wrapuptime |
This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.
Definition in file chan_agent.c.
#define AST_MAX_AGENT 80 |
Agent ID or Password max length
Definition at line 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 402 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().
00403 { 00404 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00405 char filename[AST_MAX_BUF]; 00406 int res = -1; 00407 if (!p) 00408 return -1; 00409 if (!ast->monitor) { 00410 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00411 /* substitute . for - */ 00412 if ((pointer = strchr(filename, '.'))) 00413 *pointer = '-'; 00414 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename); 00415 ast_monitor_start(ast, recordformat, tmp, needlock); 00416 ast_monitor_setjoinfiles(ast, 1); 00417 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext); 00418 #if 0 00419 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00420 #endif 00421 if (!ast->cdr) 00422 ast->cdr = ast_cdr_alloc(); 00423 ast_cdr_setuserfield(ast, tmp2); 00424 res = 0; 00425 } else 00426 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00427 return res; 00428 }
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 1779 of file chan_agent.c.
References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, context, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
Referenced by callback_exec(), and login_exec().
01780 { 01781 int res=0; 01782 int tries = 0; 01783 int max_login_tries = maxlogintries; 01784 struct agent_pvt *p; 01785 struct ast_module_user *u; 01786 int login_state = 0; 01787 char user[AST_MAX_AGENT] = ""; 01788 char pass[AST_MAX_AGENT]; 01789 char agent[AST_MAX_AGENT] = ""; 01790 char xpass[AST_MAX_AGENT] = ""; 01791 char *errmsg; 01792 char *parse; 01793 AST_DECLARE_APP_ARGS(args, 01794 AST_APP_ARG(agent_id); 01795 AST_APP_ARG(options); 01796 AST_APP_ARG(extension); 01797 ); 01798 const char *tmpoptions = NULL; 01799 char *context = NULL; 01800 int play_announcement = 1; 01801 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01802 int update_cdr = updatecdr; 01803 char *filename = "agent-loginok"; 01804 char tmpchan[AST_MAX_BUF] = ""; 01805 01806 u = ast_module_user_add(chan); 01807 01808 parse = ast_strdupa(data); 01809 01810 AST_STANDARD_APP_ARGS(args, parse); 01811 01812 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01813 01814 /* Set Channel Specific Login Overrides */ 01815 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01816 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01817 if (max_login_tries < 0) 01818 max_login_tries = 0; 01819 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01820 if (option_verbose > 2) 01821 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); 01822 } 01823 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01824 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01825 update_cdr = 1; 01826 else 01827 update_cdr = 0; 01828 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01829 if (option_verbose > 2) 01830 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01831 } 01832 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01833 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01834 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01835 if (option_verbose > 2) 01836 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01837 } 01838 /* End Channel Specific Login Overrides */ 01839 01840 if (callbackmode && args.extension) { 01841 parse = args.extension; 01842 args.extension = strsep(&parse, "@"); 01843 context = parse; 01844 } 01845 01846 if (!ast_strlen_zero(args.options)) { 01847 if (strchr(args.options, 's')) { 01848 play_announcement = 0; 01849 } 01850 } 01851 01852 if (chan->_state != AST_STATE_UP) 01853 res = ast_answer(chan); 01854 if (!res) { 01855 if (!ast_strlen_zero(args.agent_id)) 01856 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01857 else 01858 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01859 } 01860 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01861 tries++; 01862 /* Check for password */ 01863 AST_LIST_LOCK(&agents); 01864 AST_LIST_TRAVERSE(&agents, p, list) { 01865 if (!strcmp(p->agent, user) && !p->pending) 01866 ast_copy_string(xpass, p->password, sizeof(xpass)); 01867 } 01868 AST_LIST_UNLOCK(&agents); 01869 if (!res) { 01870 if (!ast_strlen_zero(xpass)) 01871 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01872 else 01873 pass[0] = '\0'; 01874 } 01875 errmsg = "agent-incorrect"; 01876 01877 #if 0 01878 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01879 #endif 01880 01881 /* Check again for accuracy */ 01882 AST_LIST_LOCK(&agents); 01883 AST_LIST_TRAVERSE(&agents, p, list) { 01884 ast_mutex_lock(&p->lock); 01885 if (!strcmp(p->agent, user) && 01886 !strcmp(p->password, pass) && !p->pending) { 01887 login_state = 1; /* Successful Login */ 01888 01889 /* Ensure we can't be gotten until we're done */ 01890 gettimeofday(&p->lastdisc, NULL); 01891 p->lastdisc.tv_sec++; 01892 01893 /* Set Channel Specific Agent Overrides */ 01894 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01895 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 01896 p->ackcall = 2; 01897 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 01898 p->ackcall = 1; 01899 else 01900 p->ackcall = 0; 01901 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01902 if (option_verbose > 2) 01903 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 01904 } 01905 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01906 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01907 if (p->autologoff < 0) 01908 p->autologoff = 0; 01909 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 01910 if (option_verbose > 2) 01911 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 01912 } 01913 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 01914 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 01915 if (p->wrapuptime < 0) 01916 p->wrapuptime = 0; 01917 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 01918 if (option_verbose > 2) 01919 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 01920 } 01921 /* End Channel Specific Agent Overrides */ 01922 if (!p->chan) { 01923 char last_loginchan[80] = ""; 01924 long logintime; 01925 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01926 01927 if (callbackmode) { 01928 int pos = 0; 01929 /* Retrieve login chan */ 01930 for (;;) { 01931 if (!ast_strlen_zero(args.extension)) { 01932 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 01933 res = 0; 01934 } else 01935 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 01936 if (ast_strlen_zero(tmpchan) ) 01937 break; 01938 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 01939 if(!allow_multiple_login(tmpchan,context) ) { 01940 args.extension = NULL; 01941 pos = 0; 01942 } else 01943 break; 01944 } 01945 if (args.extension) { 01946 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 01947 args.extension = NULL; 01948 pos = 0; 01949 } else { 01950 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 01951 res = ast_streamfile(chan, "invalid", chan->language); 01952 if (!res) 01953 res = ast_waitstream(chan, AST_DIGIT_ANY); 01954 if (res > 0) { 01955 tmpchan[0] = res; 01956 tmpchan[1] = '\0'; 01957 pos = 1; 01958 } else { 01959 tmpchan[0] = '\0'; 01960 pos = 0; 01961 } 01962 } 01963 } 01964 args.extension = tmpchan; 01965 if (!res) { 01966 set_agentbycallerid(p->logincallerid, NULL); 01967 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 01968 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 01969 else { 01970 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 01971 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 01972 } 01973 p->acknowledged = 0; 01974 if (ast_strlen_zero(p->loginchan)) { 01975 login_state = 2; 01976 filename = "agent-loggedoff"; 01977 } else { 01978 if (chan->cid.cid_num) { 01979 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 01980 set_agentbycallerid(p->logincallerid, p->agent); 01981 } else 01982 p->logincallerid[0] = '\0'; 01983 } 01984 01985 if(update_cdr && chan->cdr) 01986 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 01987 01988 } 01989 } else { 01990 p->loginchan[0] = '\0'; 01991 p->logincallerid[0] = '\0'; 01992 p->acknowledged = 0; 01993 } 01994 ast_mutex_unlock(&p->lock); 01995 AST_LIST_UNLOCK(&agents); 01996 if( !res && play_announcement==1 ) 01997 res = ast_streamfile(chan, filename, chan->language); 01998 if (!res) 01999 ast_waitstream(chan, ""); 02000 AST_LIST_LOCK(&agents); 02001 ast_mutex_lock(&p->lock); 02002 if (!res) { 02003 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02004 if (res) 02005 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02006 } 02007 if (!res) { 02008 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02009 if (res) 02010 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02011 } 02012 /* Check once more just in case */ 02013 if (p->chan) 02014 res = -1; 02015 if (callbackmode && !res) { 02016 /* Just say goodbye and be done with it */ 02017 if (!ast_strlen_zero(p->loginchan)) { 02018 if (p->loginstart == 0) 02019 time(&p->loginstart); 02020 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02021 "Agent: %s\r\n" 02022 "Loginchan: %s\r\n" 02023 "Uniqueid: %s\r\n", 02024 p->agent, p->loginchan, chan->uniqueid); 02025 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02026 if (option_verbose > 1) 02027 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02028 ast_device_state_changed("Agent/%s", p->agent); 02029 if (persistent_agents) 02030 dump_agents(); 02031 } else { 02032 logintime = time(NULL) - p->loginstart; 02033 p->loginstart = 0; 02034 02035 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02036 if (option_verbose > 1) 02037 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02038 } 02039 AST_LIST_UNLOCK(&agents); 02040 if (!res) 02041 res = ast_safe_sleep(chan, 500); 02042 ast_mutex_unlock(&p->lock); 02043 } else if (!res) { 02044 ast_indicate_data(chan, AST_CONTROL_HOLD, 02045 S_OR(p->moh, NULL), 02046 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02047 if (p->loginstart == 0) 02048 time(&p->loginstart); 02049 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02050 "Agent: %s\r\n" 02051 "Channel: %s\r\n" 02052 "Uniqueid: %s\r\n", 02053 p->agent, chan->name, chan->uniqueid); 02054 if (update_cdr && chan->cdr) 02055 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02056 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02057 if (option_verbose > 1) 02058 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02059 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02060 /* Login this channel and wait for it to go away */ 02061 p->chan = chan; 02062 if (p->ackcall > 1) 02063 check_beep(p, 0); 02064 else 02065 check_availability(p, 0); 02066 ast_mutex_unlock(&p->lock); 02067 AST_LIST_UNLOCK(&agents); 02068 ast_device_state_changed("Agent/%s", p->agent); 02069 while (res >= 0) { 02070 ast_mutex_lock(&p->lock); 02071 if (p->chan != chan) 02072 res = -1; 02073 ast_mutex_unlock(&p->lock); 02074 /* Yield here so other interested threads can kick in. */ 02075 sched_yield(); 02076 if (res) 02077 break; 02078 02079 AST_LIST_LOCK(&agents); 02080 ast_mutex_lock(&p->lock); 02081 if (p->lastdisc.tv_sec) { 02082 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) { 02083 if (option_debug) 02084 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02085 p->lastdisc = ast_tv(0, 0); 02086 if (p->ackcall > 1) 02087 check_beep(p, 0); 02088 else 02089 check_availability(p, 0); 02090 } 02091 } 02092 ast_mutex_unlock(&p->lock); 02093 AST_LIST_UNLOCK(&agents); 02094 /* Synchronize channel ownership between call to agent and itself. */ 02095 ast_mutex_lock( &p->app_lock ); 02096 ast_mutex_lock(&p->lock); 02097 p->owning_app = pthread_self(); 02098 ast_mutex_unlock(&p->lock); 02099 if (p->ackcall > 1) 02100 res = agent_ack_sleep(p); 02101 else 02102 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02103 ast_mutex_unlock( &p->app_lock ); 02104 if ((p->ackcall > 1) && (res == 1)) { 02105 AST_LIST_LOCK(&agents); 02106 ast_mutex_lock(&p->lock); 02107 check_availability(p, 0); 02108 ast_mutex_unlock(&p->lock); 02109 AST_LIST_UNLOCK(&agents); 02110 res = 0; 02111 } 02112 sched_yield(); 02113 } 02114 ast_mutex_lock(&p->lock); 02115 if (res && p->owner) 02116 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02117 /* Log us off if appropriate */ 02118 if (p->chan == chan) 02119 p->chan = NULL; 02120 p->acknowledged = 0; 02121 logintime = time(NULL) - p->loginstart; 02122 p->loginstart = 0; 02123 ast_mutex_unlock(&p->lock); 02124 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02125 "Agent: %s\r\n" 02126 "Logintime: %ld\r\n" 02127 "Uniqueid: %s\r\n", 02128 p->agent, logintime, chan->uniqueid); 02129 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02130 if (option_verbose > 1) 02131 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02132 /* If there is no owner, go ahead and kill it now */ 02133 ast_device_state_changed("Agent/%s", p->agent); 02134 if (p->dead && !p->owner) { 02135 ast_mutex_destroy(&p->lock); 02136 ast_mutex_destroy(&p->app_lock); 02137 free(p); 02138 } 02139 } 02140 else { 02141 ast_mutex_unlock(&p->lock); 02142 p = NULL; 02143 } 02144 res = -1; 02145 } else { 02146 ast_mutex_unlock(&p->lock); 02147 errmsg = "agent-alreadyon"; 02148 p = NULL; 02149 } 02150 break; 02151 } 02152 ast_mutex_unlock(&p->lock); 02153 } 02154 if (!p) 02155 AST_LIST_UNLOCK(&agents); 02156 02157 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02158 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02159 } 02160 02161 if (!res) 02162 res = ast_safe_sleep(chan, 500); 02163 02164 /* AgentLogin() exit */ 02165 if (!callbackmode) { 02166 ast_module_user_remove(u); 02167 return -1; 02168 } else { /* AgentCallbackLogin() exit*/ 02169 /* Set variables */ 02170 if (login_state > 0) { 02171 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user); 02172 if (login_state==1) { 02173 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on"); 02174 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension); 02175 } else 02176 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off"); 02177 } else { 02178 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail"); 02179 } 02180 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) { 02181 ast_module_user_remove(u); 02182 return 0; 02183 } 02184 /* Do we need to play agent-goodbye now that we will be hanging up? */ 02185 if (play_announcement) { 02186 if (!res) 02187 res = ast_safe_sleep(chan, 1000); 02188 res = ast_streamfile(chan, agent_goodbye, chan->language); 02189 if (!res) 02190 res = ast_waitstream(chan, ""); 02191 if (!res) 02192 res = ast_safe_sleep(chan, 1000); 02193 } 02194 } 02195 02196 ast_module_user_remove(u); 02197 02198 /* We should never get here if next priority exists when in callbackmode */ 02199 return -1; 02200 }
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 2251 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, ast_device_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_verbose(), astman_get_header(), astman_send_ack(), astman_send_error(), callback_deprecated(), agent_pvt::chan, context, dump_agents(), EVENT_FLAG_AGENT, exten, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), option_verbose, agent_pvt::pending, s, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.
Referenced by load_module().
02252 { 02253 const char *agent = astman_get_header(m, "Agent"); 02254 const char *exten = astman_get_header(m, "Exten"); 02255 const char *context = astman_get_header(m, "Context"); 02256 const char *wrapuptime_s = astman_get_header(m, "WrapupTime"); 02257 const char *ackcall_s = astman_get_header(m, "AckCall"); 02258 struct agent_pvt *p; 02259 int login_state = 0; 02260 02261 callback_deprecated(); 02262 02263 if (ast_strlen_zero(agent)) { 02264 astman_send_error(s, m, "No agent specified"); 02265 return 0; 02266 } 02267 02268 if (ast_strlen_zero(exten)) { 02269 astman_send_error(s, m, "No extension specified"); 02270 return 0; 02271 } 02272 02273 AST_LIST_LOCK(&agents); 02274 AST_LIST_TRAVERSE(&agents, p, list) { 02275 if (strcmp(p->agent, agent) || p->pending) 02276 continue; 02277 if (p->chan) { 02278 login_state = 2; /* already logged in (and on the phone)*/ 02279 break; 02280 } 02281 ast_mutex_lock(&p->lock); 02282 login_state = 1; /* Successful Login */ 02283 02284 if (ast_strlen_zero(context)) 02285 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan)); 02286 else 02287 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context); 02288 02289 if (!ast_strlen_zero(wrapuptime_s)) { 02290 p->wrapuptime = atoi(wrapuptime_s); 02291 if (p->wrapuptime < 0) 02292 p->wrapuptime = 0; 02293 } 02294 02295 if (ast_true(ackcall_s)) 02296 p->ackcall = 1; 02297 else 02298 p->ackcall = 0; 02299 02300 if (p->loginstart == 0) 02301 time(&p->loginstart); 02302 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02303 "Agent: %s\r\n" 02304 "Loginchan: %s\r\n", 02305 p->agent, p->loginchan); 02306 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02307 if (option_verbose > 1) 02308 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02309 ast_device_state_changed("Agent/%s", p->agent); 02310 ast_mutex_unlock(&p->lock); 02311 if (persistent_agents) 02312 dump_agents(); 02313 } 02314 AST_LIST_UNLOCK(&agents); 02315 02316 if (login_state == 1) 02317 astman_send_ack(s, m, "Agent logged in"); 02318 else if (login_state == 0) 02319 astman_send_error(s, m, "No such agent"); 02320 else if (login_state == 2) 02321 astman_send_error(s, m, "Agent already logged in"); 02322 02323 return 0; 02324 }
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 1573 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and s.
Referenced by load_module().
01574 { 01575 const char *agent = astman_get_header(m, "Agent"); 01576 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01577 int soft; 01578 int ret; /* return value of agent_logoff */ 01579 01580 if (ast_strlen_zero(agent)) { 01581 astman_send_error(s, m, "No agent specified"); 01582 return 0; 01583 } 01584 01585 soft = ast_true(soft_s) ? 1 : 0; 01586 ret = agent_logoff(agent, soft); 01587 if (ret == 0) 01588 astman_send_ack(s, m, "Agent logged out"); 01589 else 01590 astman_send_error(s, m, "No such agent"); 01591 01592 return 0; 01593 }
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 1408 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, S_OR, and username.
Referenced by load_module().
01409 { 01410 const char *id = astman_get_header(m,"ActionID"); 01411 char idText[256] = ""; 01412 char chanbuf[256]; 01413 struct agent_pvt *p; 01414 char *username = NULL; 01415 char *loginChan = NULL; 01416 char *talkingtoChan = NULL; 01417 char *status = NULL; 01418 01419 if (!ast_strlen_zero(id)) 01420 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01421 astman_send_ack(s, m, "Agents will follow"); 01422 AST_LIST_LOCK(&agents); 01423 AST_LIST_TRAVERSE(&agents, p, list) { 01424 ast_mutex_lock(&p->lock); 01425 01426 /* Status Values: 01427 AGENT_LOGGEDOFF - Agent isn't logged in 01428 AGENT_IDLE - Agent is logged in, and waiting for call 01429 AGENT_ONCALL - Agent is logged in, and on a call 01430 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01431 01432 username = S_OR(p->name, "None"); 01433 01434 /* Set a default status. It 'should' get changed. */ 01435 status = "AGENT_UNKNOWN"; 01436 01437 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01438 loginChan = p->loginchan; 01439 talkingtoChan = "n/a"; 01440 status = "AGENT_IDLE"; 01441 if (p->acknowledged) { 01442 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01443 loginChan = chanbuf; 01444 } 01445 } else if (p->chan) { 01446 loginChan = ast_strdupa(p->chan->name); 01447 if (p->owner && p->owner->_bridge) { 01448 talkingtoChan = p->chan->cid.cid_num; 01449 status = "AGENT_ONCALL"; 01450 } else { 01451 talkingtoChan = "n/a"; 01452 status = "AGENT_IDLE"; 01453 } 01454 } else { 01455 loginChan = "n/a"; 01456 talkingtoChan = "n/a"; 01457 status = "AGENT_LOGGEDOFF"; 01458 } 01459 01460 astman_append(s, "Event: Agents\r\n" 01461 "Agent: %s\r\n" 01462 "Name: %s\r\n" 01463 "Status: %s\r\n" 01464 "LoggedInChan: %s\r\n" 01465 "LoggedInTime: %d\r\n" 01466 "TalkingTo: %s\r\n" 01467 "%s" 01468 "\r\n", 01469 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); 01470 ast_mutex_unlock(&p->lock); 01471 } 01472 AST_LIST_UNLOCK(&agents); 01473 astman_append(s, "Event: AgentsComplete\r\n" 01474 "%s" 01475 "\r\n",idText); 01476 return 0; 01477 }
static struct agent_pvt* add_agent | ( | char * | agent, | |
int | pending | |||
) | [static] |
Adds an agent to the global list of agents.
agent | A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" | |
pending | If it is pending or not. |
Definition at line 286 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::lastdisc, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00287 { 00288 char *parse; 00289 AST_DECLARE_APP_ARGS(args, 00290 AST_APP_ARG(agt); 00291 AST_APP_ARG(password); 00292 AST_APP_ARG(name); 00293 ); 00294 char *password = NULL; 00295 char *name = NULL; 00296 char *agt = NULL; 00297 struct agent_pvt *p; 00298 00299 parse = ast_strdupa(agent); 00300 00301 /* Extract username (agt), password and name from agent (args). */ 00302 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 00303 00304 if(args.argc == 0) { 00305 ast_log(LOG_WARNING, "A blank agent line!\n"); 00306 return NULL; 00307 } 00308 00309 if(ast_strlen_zero(args.agt) ) { 00310 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00311 return NULL; 00312 } else 00313 agt = args.agt; 00314 00315 if(!ast_strlen_zero(args.password)) { 00316 password = args.password; 00317 while (*password && *password < 33) password++; 00318 } 00319 if(!ast_strlen_zero(args.name)) { 00320 name = args.name; 00321 while (*name && *name < 33) name++; 00322 } 00323 00324 /* Are we searching for the agent here ? To see if it exists already ? */ 00325 AST_LIST_TRAVERSE(&agents, p, list) { 00326 if (!pending && !strcmp(p->agent, agt)) 00327 break; 00328 } 00329 if (!p) { 00330 // Build the agent. 00331 if (!(p = ast_calloc(1, sizeof(*p)))) 00332 return NULL; 00333 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00334 ast_mutex_init(&p->lock); 00335 ast_mutex_init(&p->app_lock); 00336 p->owning_app = (pthread_t) -1; 00337 p->app_sleep_cond = 1; 00338 p->group = group; 00339 p->pending = pending; 00340 AST_LIST_INSERT_TAIL(&agents, p, list); 00341 } 00342 00343 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00344 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00345 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00346 p->ackcall = ackcall; 00347 p->autologoff = autologoff; 00348 00349 /* If someone reduces the wrapuptime and reloads, we want it 00350 * to change the wrapuptime immediately on all calls */ 00351 if (p->wrapuptime > wrapuptime) { 00352 struct timeval now = ast_tvnow(); 00353 /* XXX check what is this exactly */ 00354 00355 /* We won't be pedantic and check the tv_usec val */ 00356 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00357 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00358 p->lastdisc.tv_usec = now.tv_usec; 00359 } 00360 } 00361 p->wrapuptime = wrapuptime; 00362 00363 if (pending) 00364 p->dead = 1; 00365 else 00366 p->dead = 0; 00367 return p; 00368 }
static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 855 of file chan_agent.c.
References agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree(), ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, f, and agent_pvt::lock.
Referenced by __login_exec().
00856 { 00857 struct agent_pvt *p; 00858 int res=0; 00859 int to = 1000; 00860 struct ast_frame *f; 00861 00862 /* Wait a second and look for something */ 00863 00864 p = (struct agent_pvt *) data; 00865 if (!p->chan) 00866 return -1; 00867 00868 for(;;) { 00869 to = ast_waitfor(p->chan, to); 00870 if (to < 0) 00871 return -1; 00872 if (!to) 00873 return 0; 00874 f = ast_read(p->chan); 00875 if (!f) 00876 return -1; 00877 if (f->frametype == AST_FRAME_DTMF) 00878 res = f->subclass; 00879 else 00880 res = 0; 00881 ast_frfree(f); 00882 ast_mutex_lock(&p->lock); 00883 if (!p->app_sleep_cond) { 00884 ast_mutex_unlock(&p->lock); 00885 return 0; 00886 } else if (res == '#') { 00887 ast_mutex_unlock(&p->lock); 00888 return 1; 00889 } 00890 ast_mutex_unlock(&p->lock); 00891 res = 0; 00892 } 00893 return res; 00894 }
static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 396 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00397 { 00398 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00399 return -1; 00400 }
static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
struct ast_channel * | bridge | |||
) | [static] |
Definition at line 896 of file chan_agent.c.
References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.
00897 { 00898 struct agent_pvt *p = bridge->tech_pvt; 00899 struct ast_channel *ret = NULL; 00900 00901 if (p) { 00902 if (chan == p->chan) 00903 ret = bridge->_bridge; 00904 else if (chan == bridge->_bridge) 00905 ret = p->chan; 00906 } 00907 00908 if (option_debug) 00909 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 00910 return ret; 00911 }
static int agent_call | ( | struct ast_channel * | ast, | |
char * | dest, | |||
int | timeout | |||
) | [static] |
Definition at line 629 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.
00630 { 00631 struct agent_pvt *p = ast->tech_pvt; 00632 int res = -1; 00633 int newstate=0; 00634 ast_mutex_lock(&p->lock); 00635 p->acknowledged = 0; 00636 if (!p->chan) { 00637 if (p->pending) { 00638 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00639 newstate = AST_STATE_DIALING; 00640 res = 0; 00641 } else { 00642 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00643 res = -1; 00644 } 00645 ast_mutex_unlock(&p->lock); 00646 if (newstate) 00647 ast_setstate(ast, newstate); 00648 return res; 00649 } else if (!ast_strlen_zero(p->loginchan)) { 00650 time(&p->start); 00651 /* Call on this agent */ 00652 if (option_verbose > 2) 00653 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00654 ast_set_callerid(p->chan, 00655 ast->cid.cid_num, ast->cid.cid_name, NULL); 00656 ast_channel_inherit_variables(ast, p->chan); 00657 res = ast_call(p->chan, p->loginchan, 0); 00658 CLEANUP(ast,p); 00659 ast_mutex_unlock(&p->lock); 00660 return res; 00661 } 00662 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00663 if (option_debug > 2) 00664 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language); 00665 res = ast_streamfile(p->chan, beep, p->chan->language); 00666 if (option_debug > 2) 00667 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 00668 if (!res) { 00669 res = ast_waitstream(p->chan, ""); 00670 if (option_debug > 2) 00671 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 00672 } 00673 if (!res) { 00674 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00675 if (option_debug > 2) 00676 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res); 00677 if (res) 00678 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00679 } else { 00680 /* Agent hung-up */ 00681 p->chan = NULL; 00682 } 00683 00684 if (!res) { 00685 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00686 if (option_debug > 2) 00687 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res); 00688 if (res) 00689 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00690 } 00691 if(!res) { 00692 /* Call is immediately up, or might need ack */ 00693 if (p->ackcall > 1) 00694 newstate = AST_STATE_RINGING; 00695 else { 00696 newstate = AST_STATE_UP; 00697 if (recordagentcalls) 00698 agent_start_monitoring(ast, 0); 00699 p->acknowledged = 1; 00700 } 00701 res = 0; 00702 } 00703 CLEANUP(ast, p); 00704 ast_mutex_unlock(&p->lock); 00705 if (newstate) 00706 ast_setstate(ast, newstate); 00707 return res; 00708 }
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 376 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().
00377 { 00378 struct ast_channel *chan = p->owner; 00379 p->owner = NULL; 00380 chan->tech_pvt = NULL; 00381 p->app_sleep_cond = 1; 00382 /* Release ownership of the agent to other threads (presumably running the login app). */ 00383 ast_mutex_unlock(&p->app_lock); 00384 if (chan) 00385 ast_channel_free(chan); 00386 if (p->dead) { 00387 ast_mutex_destroy(&p->lock); 00388 ast_mutex_destroy(&p->app_lock); 00389 free(p); 00390 } 00391 return 0; 00392 }
static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 834 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, option_debug, and agent_pvt::wrapuptime.
Referenced by __login_exec().
00835 { 00836 struct agent_pvt *p; 00837 int res; 00838 00839 p = (struct agent_pvt *)data; 00840 00841 ast_mutex_lock(&p->lock); 00842 res = p->app_sleep_cond; 00843 if (p->lastdisc.tv_sec) { 00844 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 00845 res = 1; 00846 } 00847 ast_mutex_unlock(&p->lock); 00848 00849 if(option_debug > 4 && !res ) 00850 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res ); 00851 00852 return res; 00853 }
static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2470 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.
02471 { 02472 struct agent_pvt *p; 02473 char *s; 02474 ast_group_t groupmatch; 02475 int groupoff; 02476 int waitforagent=0; 02477 int res = AST_DEVICE_INVALID; 02478 02479 s = data; 02480 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) 02481 groupmatch = (1 << groupoff); 02482 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 02483 groupmatch = (1 << groupoff); 02484 waitforagent = 1; 02485 } else 02486 groupmatch = 0; 02487 02488 /* Check actual logged in agents first */ 02489 AST_LIST_LOCK(&agents); 02490 AST_LIST_TRAVERSE(&agents, p, list) { 02491 ast_mutex_lock(&p->lock); 02492 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02493 if (p->owner) { 02494 if (res != AST_DEVICE_INUSE) 02495 res = AST_DEVICE_BUSY; 02496 } else { 02497 if (res == AST_DEVICE_BUSY) 02498 res = AST_DEVICE_INUSE; 02499 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02500 if (res == AST_DEVICE_INVALID) 02501 res = AST_DEVICE_UNKNOWN; 02502 } else if (res == AST_DEVICE_INVALID) 02503 res = AST_DEVICE_UNAVAILABLE; 02504 } 02505 if (!strcmp(data, p->agent)) { 02506 ast_mutex_unlock(&p->lock); 02507 break; 02508 } 02509 } 02510 ast_mutex_unlock(&p->lock); 02511 } 02512 AST_LIST_UNLOCK(&agents); 02513 return res; 02514 }
static int agent_digit_begin | ( | struct ast_channel * | ast, | |
char | digit | |||
) | [static] |
Definition at line 611 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.
00612 { 00613 struct agent_pvt *p = ast->tech_pvt; 00614 ast_mutex_lock(&p->lock); 00615 ast_senddigit_begin(p->chan, digit); 00616 ast_mutex_unlock(&p->lock); 00617 return 0; 00618 }
static int agent_digit_end | ( | struct ast_channel * | ast, | |
char | digit, | |||
unsigned int | duration | |||
) | [static] |
Definition at line 620 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.
00621 { 00622 struct agent_pvt *p = ast->tech_pvt; 00623 ast_mutex_lock(&p->lock); 00624 ast_senddigit_end(p->chan, digit, duration); 00625 ast_mutex_unlock(&p->lock); 00626 return 0; 00627 }
static int agent_fixup | ( | struct ast_channel * | oldchan, | |
struct ast_channel * | newchan | |||
) | [static] |
Definition at line 584 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.
00585 { 00586 struct agent_pvt *p = newchan->tech_pvt; 00587 ast_mutex_lock(&p->lock); 00588 if (p->owner != oldchan) { 00589 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00590 ast_mutex_unlock(&p->lock); 00591 return -1; 00592 } 00593 p->owner = newchan; 00594 ast_mutex_unlock(&p->lock); 00595 return 0; 00596 }
static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 723 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.
00724 { 00725 struct agent_pvt *p = ast->tech_pvt; 00726 int howlong = 0; 00727 const char *status; 00728 ast_mutex_lock(&p->lock); 00729 p->owner = NULL; 00730 ast->tech_pvt = NULL; 00731 p->app_sleep_cond = 1; 00732 p->acknowledged = 0; 00733 00734 /* if they really are hung up then set start to 0 so the test 00735 * later if we're called on an already downed channel 00736 * doesn't cause an agent to be logged out like when 00737 * agent_request() is followed immediately by agent_hangup() 00738 * as in apps/app_chanisavail.c:chanavail_exec() 00739 */ 00740 00741 if (option_debug) 00742 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00743 if (p->start && (ast->_state != AST_STATE_UP)) { 00744 howlong = time(NULL) - p->start; 00745 p->start = 0; 00746 } else if (ast->_state == AST_STATE_RESERVED) 00747 howlong = 0; 00748 else 00749 p->start = 0; 00750 if (p->chan) { 00751 p->chan->_bridge = NULL; 00752 /* If they're dead, go ahead and hang up on the agent now */ 00753 if (!ast_strlen_zero(p->loginchan)) { 00754 /* Store last disconnect time */ 00755 if (p->wrapuptime) 00756 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00757 else 00758 p->lastdisc = ast_tv(0,0); 00759 if (p->chan) { 00760 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00761 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00762 long logintime = time(NULL) - p->loginstart; 00763 p->loginstart = 0; 00764 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00765 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00766 } 00767 /* Recognize the hangup and pass it along immediately */ 00768 ast_hangup(p->chan); 00769 p->chan = NULL; 00770 } 00771 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00772 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00773 long logintime = time(NULL) - p->loginstart; 00774 p->loginstart = 0; 00775 if (!p->deferlogoff) 00776 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00777 p->deferlogoff = 0; 00778 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00779 if (persistent_agents) 00780 dump_agents(); 00781 } 00782 } else if (p->dead) { 00783 ast_channel_lock(p->chan); 00784 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00785 ast_channel_unlock(p->chan); 00786 } else if (p->loginstart) { 00787 ast_channel_lock(p->chan); 00788 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00789 S_OR(p->moh, NULL), 00790 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00791 ast_channel_unlock(p->chan); 00792 } 00793 } 00794 ast_mutex_unlock(&p->lock); 00795 00796 /* Only register a device state change if the agent is still logged in */ 00797 if (!p->loginstart) { 00798 p->loginchan[0] = '\0'; 00799 p->logincallerid[0] = '\0'; 00800 if (persistent_agents) 00801 dump_agents(); 00802 } else { 00803 ast_device_state_changed("Agent/%s", p->agent); 00804 } 00805 00806 if (p->pending) { 00807 AST_LIST_LOCK(&agents); 00808 AST_LIST_REMOVE(&agents, p, list); 00809 AST_LIST_UNLOCK(&agents); 00810 } 00811 if (p->abouttograb) { 00812 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00813 kill it later */ 00814 p->abouttograb = 0; 00815 } else if (p->dead) { 00816 ast_mutex_destroy(&p->lock); 00817 ast_mutex_destroy(&p->app_lock); 00818 free(p); 00819 } else { 00820 if (p->chan) { 00821 /* Not dead -- check availability now */ 00822 ast_mutex_lock(&p->lock); 00823 /* Store last disconnect time */ 00824 p->lastdisc = ast_tvnow(); 00825 ast_mutex_unlock(&p->lock); 00826 } 00827 /* Release ownership of the agent to other threads (presumably running the login app). */ 00828 if (ast_strlen_zero(p->loginchan)) 00829 ast_mutex_unlock(&p->app_lock); 00830 } 00831 return 0; 00832 }
static int agent_indicate | ( | struct ast_channel * | ast, | |
int | condition, | |||
const void * | data, | |||
size_t | datalen | |||
) | [static] |
Definition at line 598 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.
00599 { 00600 struct agent_pvt *p = ast->tech_pvt; 00601 int res = -1; 00602 ast_mutex_lock(&p->lock); 00603 if (p->chan) 00604 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00605 else 00606 res = 0; 00607 ast_mutex_unlock(&p->lock); 00608 return res; 00609 }
static int agent_logoff | ( | const char * | agent, | |
int | soft | |||
) | [static] |
Definition at line 1518 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().
01519 { 01520 struct agent_pvt *p; 01521 long logintime; 01522 int ret = -1; /* Return -1 if no agent if found */ 01523 01524 AST_LIST_TRAVERSE(&agents, p, list) { 01525 if (!strcasecmp(p->agent, agent)) { 01526 ret = 0; 01527 if (p->owner || p->chan) { 01528 p->deferlogoff = 1; 01529 if (!soft) { 01530 if (p->owner) 01531 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01532 if (p->chan) 01533 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01534 } 01535 } else { 01536 logintime = time(NULL) - p->loginstart; 01537 p->loginstart = 0; 01538 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01539 } 01540 break; 01541 } 01542 } 01543 01544 return ret; 01545 }
static int agent_logoff_cmd | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1547 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01548 { 01549 int ret; 01550 char *agent; 01551 01552 if (argc < 3 || argc > 4) 01553 return RESULT_SHOWUSAGE; 01554 if (argc == 4 && strcasecmp(argv[3], "soft")) 01555 return RESULT_SHOWUSAGE; 01556 01557 agent = argv[2] + 6; 01558 ret = agent_logoff(agent, argc == 4); 01559 if (ret == 0) 01560 ast_cli(fd, "Logging out %s\n", agent); 01561 01562 return RESULT_SUCCESS; 01563 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1479 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().
01480 { 01481 char *tmp = NULL; 01482 char agent[AST_MAX_AGENT]; 01483 01484 if (!ast_strlen_zero(logcommand)) 01485 tmp = logcommand; 01486 else 01487 tmp = ast_strdupa(""); 01488 01489 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01490 01491 if (!ast_strlen_zero(uniqueid)) { 01492 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01493 "Agent: %s\r\n" 01494 "Reason: %s\r\n" 01495 "Loginchan: %s\r\n" 01496 "Logintime: %ld\r\n" 01497 "Uniqueid: %s\r\n", 01498 p->agent, tmp, loginchan, logintime, uniqueid); 01499 } else { 01500 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01501 "Agent: %s\r\n" 01502 "Reason: %s\r\n" 01503 "Loginchan: %s\r\n" 01504 "Logintime: %ld\r\n", 01505 p->agent, tmp, loginchan, logintime); 01506 } 01507 01508 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01509 set_agentbycallerid(p->logincallerid, NULL); 01510 p->loginchan[0] ='\0'; 01511 p->logincallerid[0] = '\0'; 01512 ast_device_state_changed("Agent/%s", p->agent); 01513 if (persistent_agents) 01514 dump_agents(); 01515 01516 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static] |
Create new agent channel.
Definition at line 914 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().
00915 { 00916 struct ast_channel *tmp; 00917 #if 0 00918 if (!p->chan) { 00919 ast_log(LOG_WARNING, "No channel? :(\n"); 00920 return NULL; 00921 } 00922 #endif 00923 if (p->pending) 00924 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); 00925 else 00926 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 00927 if (!tmp) { 00928 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 00929 return NULL; 00930 } 00931 00932 tmp->tech = &agent_tech; 00933 if (p->chan) { 00934 tmp->nativeformats = p->chan->nativeformats; 00935 tmp->writeformat = p->chan->writeformat; 00936 tmp->rawwriteformat = p->chan->writeformat; 00937 tmp->readformat = p->chan->readformat; 00938 tmp->rawreadformat = p->chan->readformat; 00939 ast_string_field_set(tmp, language, p->chan->language); 00940 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 00941 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 00942 /* XXX Is this really all we copy form the originating channel?? */ 00943 } else { 00944 tmp->nativeformats = AST_FORMAT_SLINEAR; 00945 tmp->writeformat = AST_FORMAT_SLINEAR; 00946 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 00947 tmp->readformat = AST_FORMAT_SLINEAR; 00948 tmp->rawreadformat = AST_FORMAT_SLINEAR; 00949 } 00950 /* Safe, agentlock already held */ 00951 tmp->tech_pvt = p; 00952 p->owner = tmp; 00953 /* XXX: this needs fixing */ 00954 #if 0 00955 ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1); 00956 #endif 00957 ast_update_use_count(); 00958 tmp->priority = 1; 00959 /* Wake up and wait for other applications (by definition the login app) 00960 * to release this channel). Takes ownership of the agent channel 00961 * to this thread only. 00962 * For signalling the other thread, ast_queue_frame is used until we 00963 * can safely use signals for this purpose. The pselect() needs to be 00964 * implemented in the kernel for this. 00965 */ 00966 p->app_sleep_cond = 0; 00967 if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) { 00968 if (p->chan) { 00969 ast_queue_frame(p->chan, &ast_null_frame); 00970 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 00971 ast_mutex_lock(&p->app_lock); 00972 ast_mutex_lock(&p->lock); 00973 } else { 00974 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 00975 p->owner = NULL; 00976 tmp->tech_pvt = NULL; 00977 p->app_sleep_cond = 1; 00978 ast_channel_free( tmp ); 00979 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 00980 ast_mutex_unlock(&p->app_lock); 00981 return NULL; 00982 } 00983 } else if (!ast_strlen_zero(p->loginchan)) { 00984 if (p->chan) 00985 ast_queue_frame(p->chan, &ast_null_frame); 00986 if (!p->chan) { 00987 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 00988 p->owner = NULL; 00989 tmp->tech_pvt = NULL; 00990 p->app_sleep_cond = 1; 00991 ast_channel_free( tmp ); 00992 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 00993 return NULL; 00994 } 00995 } 00996 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 00997 p->owning_app = pthread_self(); 00998 /* After the above step, there should not be any blockers. */ 00999 if (p->chan) { 01000 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) { 01001 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" ); 01002 CRASH; 01003 } 01004 } 01005 return tmp; 01006 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 435 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, AST_CONTROL_ANSWER, ast_copy_flags, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree(), ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_verbose(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, f, ast_channel::fdno, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_verbose, pbx_builtin_getvar_helper(), ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
00436 { 00437 struct agent_pvt *p = ast->tech_pvt; 00438 struct ast_frame *f = NULL; 00439 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00440 const char *status; 00441 ast_mutex_lock(&p->lock); 00442 CHECK_FORMATS(ast, p); 00443 if (p->chan) { 00444 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00445 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00446 f = ast_read(p->chan); 00447 } else 00448 f = &ast_null_frame; 00449 if (!f) { 00450 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00451 if (p->chan) { 00452 p->chan->_bridge = NULL; 00453 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00454 for us when the PBX instance that called login finishes */ 00455 if (!ast_strlen_zero(p->loginchan)) { 00456 if (p->chan) 00457 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00458 00459 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00460 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00461 long logintime = time(NULL) - p->loginstart; 00462 p->loginstart = 0; 00463 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00464 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00465 } 00466 ast_hangup(p->chan); 00467 if (p->wrapuptime && p->acknowledged) 00468 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00469 } 00470 p->chan = NULL; 00471 p->acknowledged = 0; 00472 } 00473 } else { 00474 /* if acknowledgement is not required, and the channel is up, we may have missed 00475 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00476 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) 00477 p->acknowledged = 1; 00478 switch (f->frametype) { 00479 case AST_FRAME_CONTROL: 00480 if (f->subclass == AST_CONTROL_ANSWER) { 00481 if (p->ackcall) { 00482 if (option_verbose > 2) 00483 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 00484 /* Don't pass answer along */ 00485 ast_frfree(f); 00486 f = &ast_null_frame; 00487 } else { 00488 p->acknowledged = 1; 00489 /* Use the builtin answer frame for the 00490 recording start check below. */ 00491 ast_frfree(f); 00492 f = &answer_frame; 00493 } 00494 } 00495 break; 00496 case AST_FRAME_DTMF_BEGIN: 00497 case AST_FRAME_DTMF_END: 00498 if (!p->acknowledged && (f->subclass == '#')) { 00499 if (option_verbose > 2) 00500 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 00501 p->acknowledged = 1; 00502 ast_frfree(f); 00503 f = &answer_frame; 00504 } else if (f->subclass == '*' && endcall) { 00505 /* terminates call */ 00506 ast_frfree(f); 00507 f = NULL; 00508 } 00509 break; 00510 case AST_FRAME_VOICE: 00511 case AST_FRAME_VIDEO: 00512 /* don't pass voice or video until the call is acknowledged */ 00513 if (!p->acknowledged) { 00514 ast_frfree(f); 00515 f = &ast_null_frame; 00516 } 00517 default: 00518 /* pass everything else on through */ 00519 break; 00520 } 00521 } 00522 00523 CLEANUP(ast,p); 00524 if (p->chan && !p->chan->_bridge) { 00525 if (strcasecmp(p->chan->tech->type, "Local")) { 00526 p->chan->_bridge = ast; 00527 if (p->chan) 00528 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00529 } 00530 } 00531 ast_mutex_unlock(&p->lock); 00532 if (recordagentcalls && f == &answer_frame) 00533 agent_start_monitoring(ast,0); 00534 return f; 00535 }
static struct ast_channel * agent_request | ( | const char * | type, | |
int | format, | |||
void * | data, | |||
int * | cause | |||
) | [static] |
Part of the Asterisk PBX interface.
Definition at line 1297 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.
01298 { 01299 struct agent_pvt *p; 01300 struct ast_channel *chan = NULL; 01301 char *s; 01302 ast_group_t groupmatch; 01303 int groupoff; 01304 int waitforagent=0; 01305 int hasagent = 0; 01306 struct timeval tv; 01307 01308 s = data; 01309 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01310 groupmatch = (1 << groupoff); 01311 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01312 groupmatch = (1 << groupoff); 01313 waitforagent = 1; 01314 } else 01315 groupmatch = 0; 01316 01317 /* Check actual logged in agents first */ 01318 AST_LIST_LOCK(&agents); 01319 AST_LIST_TRAVERSE(&agents, p, list) { 01320 ast_mutex_lock(&p->lock); 01321 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01322 ast_strlen_zero(p->loginchan)) { 01323 if (p->chan) 01324 hasagent++; 01325 if (!p->lastdisc.tv_sec) { 01326 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01327 if (!p->owner && p->chan) { 01328 /* Fixed agent */ 01329 chan = agent_new(p, AST_STATE_DOWN); 01330 } 01331 if (chan) { 01332 ast_mutex_unlock(&p->lock); 01333 break; 01334 } 01335 } 01336 } 01337 ast_mutex_unlock(&p->lock); 01338 } 01339 if (!p) { 01340 AST_LIST_TRAVERSE(&agents, p, list) { 01341 ast_mutex_lock(&p->lock); 01342 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01343 if (p->chan || !ast_strlen_zero(p->loginchan)) 01344 hasagent++; 01345 tv = ast_tvnow(); 01346 #if 0 01347 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec); 01348 #endif 01349 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) { 01350 p->lastdisc = ast_tv(0, 0); 01351 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01352 if (!p->owner && p->chan) { 01353 /* Could still get a fixed agent */ 01354 chan = agent_new(p, AST_STATE_DOWN); 01355 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01356 /* Adjustable agent */ 01357 p->chan = ast_request("Local", format, p->loginchan, cause); 01358 if (p->chan) 01359 chan = agent_new(p, AST_STATE_DOWN); 01360 } 01361 if (chan) { 01362 ast_mutex_unlock(&p->lock); 01363 break; 01364 } 01365 } 01366 } 01367 ast_mutex_unlock(&p->lock); 01368 } 01369 } 01370 01371 if (!chan && waitforagent) { 01372 /* No agent available -- but we're requesting to wait for one. 01373 Allocate a place holder */ 01374 if (hasagent) { 01375 if (option_debug) 01376 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); 01377 p = add_agent(data, 1); 01378 p->group = groupmatch; 01379 chan = agent_new(p, AST_STATE_DOWN); 01380 if (!chan) 01381 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01382 } else 01383 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); 01384 } 01385 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01386 AST_LIST_UNLOCK(&agents); 01387 return chan; 01388 }
static int agent_sendhtml | ( | struct ast_channel * | ast, | |
int | subclass, | |||
const char * | data, | |||
int | datalen | |||
) | [static] |
Definition at line 537 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.
00538 { 00539 struct agent_pvt *p = ast->tech_pvt; 00540 int res = -1; 00541 ast_mutex_lock(&p->lock); 00542 if (p->chan) 00543 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00544 ast_mutex_unlock(&p->lock); 00545 return res; 00546 }
static int agent_sendtext | ( | struct ast_channel * | ast, | |
const char * | text | |||
) | [static] |
Definition at line 548 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.
00549 { 00550 struct agent_pvt *p = ast->tech_pvt; 00551 int res = -1; 00552 ast_mutex_lock(&p->lock); 00553 if (p->chan) 00554 res = ast_sendtext(p->chan, text); 00555 ast_mutex_unlock(&p->lock); 00556 return res; 00557 }
static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
int | needlock | |||
) | [static] |
Definition at line 430 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00431 { 00432 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00433 }
static int agent_write | ( | struct ast_channel * | ast, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 559 of file chan_agent.c.
References AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, f, agent_pvt::lock, LOG_DEBUG, ast_channel::tech_pvt, and ast_channel::writeformat.
00560 { 00561 struct agent_pvt *p = ast->tech_pvt; 00562 int res = -1; 00563 CHECK_FORMATS(ast, p); 00564 ast_mutex_lock(&p->lock); 00565 if (!p->chan) 00566 res = 0; 00567 else { 00568 if ((f->frametype != AST_FRAME_VOICE) || 00569 (f->frametype != AST_FRAME_VIDEO) || 00570 (f->subclass == p->chan->writeformat)) { 00571 res = ast_write(p->chan, f); 00572 } else { 00573 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00574 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00575 ast->name, p->chan->name); 00576 res = 0; 00577 } 00578 } 00579 CLEANUP(ast, p); 00580 ast_mutex_unlock(&p->lock); 00581 return res; 00582 }
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 2334 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_verbose(), ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3.
Referenced by load_module().
02335 { 02336 int exitifnoagentid = 0; 02337 int nowarnings = 0; 02338 int changeoutgoing = 0; 02339 int res = 0; 02340 char agent[AST_MAX_AGENT]; 02341 02342 if (data) { 02343 if (strchr(data, 'd')) 02344 exitifnoagentid = 1; 02345 if (strchr(data, 'n')) 02346 nowarnings = 1; 02347 if (strchr(data, 'c')) 02348 changeoutgoing = 1; 02349 } 02350 if (chan->cid.cid_num) { 02351 const char *tmp; 02352 char agentvar[AST_MAX_BUF]; 02353 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02354 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02355 struct agent_pvt *p; 02356 ast_copy_string(agent, tmp, sizeof(agent)); 02357 AST_LIST_LOCK(&agents); 02358 AST_LIST_TRAVERSE(&agents, p, list) { 02359 if (!strcasecmp(p->agent, tmp)) { 02360 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02361 __agent_start_monitoring(chan, p, 1); 02362 break; 02363 } 02364 } 02365 AST_LIST_UNLOCK(&agents); 02366 02367 } else { 02368 res = -1; 02369 if (!nowarnings) 02370 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); 02371 } 02372 } else { 02373 res = -1; 02374 if (!nowarnings) 02375 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"); 02376 } 02377 /* check if there is n + 101 priority */ 02378 /*! \todo XXX Needs to check option priorityjump etc etc */ 02379 if (res) { 02380 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) { 02381 chan->priority+=100; 02382 if (option_verbose > 2) 02383 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); 02384 } else if (exitifnoagentid) 02385 return res; 02386 } 02387 return 0; 02388 }
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 1616 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.
01617 { 01618 struct agent_pvt *p; 01619 char username[AST_MAX_BUF]; 01620 char location[AST_MAX_BUF] = ""; 01621 char talkingto[AST_MAX_BUF] = ""; 01622 char moh[AST_MAX_BUF]; 01623 int count_agents = 0; /*!< Number of agents configured */ 01624 int online_agents = 0; /*!< Number of online agents */ 01625 int offline_agents = 0; /*!< Number of offline agents */ 01626 if (argc != 2) 01627 return RESULT_SHOWUSAGE; 01628 AST_LIST_LOCK(&agents); 01629 AST_LIST_TRAVERSE(&agents, p, list) { 01630 ast_mutex_lock(&p->lock); 01631 if (p->pending) { 01632 if (p->group) 01633 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group)); 01634 else 01635 ast_cli(fd, "-- Pending call to agent %s\n", p->agent); 01636 } else { 01637 if (!ast_strlen_zero(p->name)) 01638 snprintf(username, sizeof(username), "(%s) ", p->name); 01639 else 01640 username[0] = '\0'; 01641 if (p->chan) { 01642 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01643 if (p->owner && ast_bridged_channel(p->owner)) 01644 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01645 else 01646 strcpy(talkingto, " is idle"); 01647 online_agents++; 01648 } else if (!ast_strlen_zero(p->loginchan)) { 01649 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01650 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01651 else 01652 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01653 talkingto[0] = '\0'; 01654 online_agents++; 01655 if (p->acknowledged) 01656 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01657 } else { 01658 strcpy(location, "not logged in"); 01659 talkingto[0] = '\0'; 01660 offline_agents++; 01661 } 01662 if (!ast_strlen_zero(p->moh)) 01663 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01664 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 01665 username, location, talkingto, moh); 01666 count_agents++; 01667 } 01668 ast_mutex_unlock(&p->lock); 01669 } 01670 AST_LIST_UNLOCK(&agents); 01671 if ( !count_agents ) 01672 ast_cli(fd, "No Agents are configured in %s\n",config); 01673 else 01674 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01675 ast_cli(fd, "\n"); 01676 01677 return RESULT_SUCCESS; 01678 }
static int agents_show_online | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1681 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.
01682 { 01683 struct agent_pvt *p; 01684 char username[AST_MAX_BUF]; 01685 char location[AST_MAX_BUF] = ""; 01686 char talkingto[AST_MAX_BUF] = ""; 01687 char moh[AST_MAX_BUF]; 01688 int count_agents = 0; /* Number of agents configured */ 01689 int online_agents = 0; /* Number of online agents */ 01690 int agent_status = 0; /* 0 means offline, 1 means online */ 01691 if (argc != 3) 01692 return RESULT_SHOWUSAGE; 01693 AST_LIST_LOCK(&agents); 01694 AST_LIST_TRAVERSE(&agents, p, list) { 01695 agent_status = 0; /* reset it to offline */ 01696 ast_mutex_lock(&p->lock); 01697 if (!ast_strlen_zero(p->name)) 01698 snprintf(username, sizeof(username), "(%s) ", p->name); 01699 else 01700 username[0] = '\0'; 01701 if (p->chan) { 01702 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01703 if (p->owner && ast_bridged_channel(p->owner)) 01704 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01705 else 01706 strcpy(talkingto, " is idle"); 01707 agent_status = 1; 01708 online_agents++; 01709 } else if (!ast_strlen_zero(p->loginchan)) { 01710 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01711 talkingto[0] = '\0'; 01712 agent_status = 1; 01713 online_agents++; 01714 if (p->acknowledged) 01715 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01716 } 01717 if (!ast_strlen_zero(p->moh)) 01718 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01719 if (agent_status) 01720 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh); 01721 count_agents++; 01722 ast_mutex_unlock(&p->lock); 01723 } 01724 AST_LIST_UNLOCK(&agents); 01725 if (!count_agents) 01726 ast_cli(fd, "No Agents are configured in %s\n", config); 01727 else 01728 ast_cli(fd, "%d agents online\n", online_agents); 01729 ast_cli(fd, "\n"); 01730 return RESULT_SUCCESS; 01731 }
static int allow_multiple_login | ( | char * | chan, | |
char * | context | |||
) | [static] |
Definition at line 1277 of file chan_agent.c.
References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.
Referenced by __login_exec().
01278 { 01279 struct agent_pvt *p; 01280 char loginchan[80]; 01281 01282 if(multiplelogin) 01283 return 1; 01284 if(!chan) 01285 return 0; 01286 01287 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); 01288 01289 AST_LIST_TRAVERSE(&agents, p, list) { 01290 if(!strcasecmp(chan, p->loginchan)) 01291 return 0; 01292 } 01293 return -1; 01294 }
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 2215 of file chan_agent.c.
References ast_log(), depwarning, and LOG_WARNING.
Referenced by action_agent_callback_login(), and callback_exec().
02216 { 02217 static int depwarning = 0; 02218 02219 if (!depwarning) { 02220 depwarning = 1; 02221 02222 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n"); 02223 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n"); 02224 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n"); 02225 } 02226 }
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 2236 of file chan_agent.c.
References __login_exec(), callback_deprecated(), and ast_module_user::chan.
Referenced by load_module().
02237 { 02238 callback_deprecated(); 02239 02240 return __login_exec(chan, data, 1); 02241 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1163 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().
01164 { 01165 struct ast_channel *chan=NULL, *parent=NULL; 01166 struct agent_pvt *p; 01167 int res; 01168 01169 if (option_debug) 01170 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); 01171 if (needlock) 01172 AST_LIST_LOCK(&agents); 01173 AST_LIST_TRAVERSE(&agents, p, list) { 01174 if (p == newlyavailable) { 01175 continue; 01176 } 01177 ast_mutex_lock(&p->lock); 01178 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01179 if (option_debug) 01180 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01181 /* We found a pending call, time to merge */ 01182 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01183 parent = p->owner; 01184 p->abouttograb = 1; 01185 ast_mutex_unlock(&p->lock); 01186 break; 01187 } 01188 ast_mutex_unlock(&p->lock); 01189 } 01190 if (needlock) 01191 AST_LIST_UNLOCK(&agents); 01192 if (parent && chan) { 01193 if (newlyavailable->ackcall > 1) { 01194 /* Don't do beep here */ 01195 res = 0; 01196 } else { 01197 if (option_debug > 2) 01198 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01199 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01200 if (option_debug > 2) 01201 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01202 if (!res) { 01203 res = ast_waitstream(newlyavailable->chan, ""); 01204 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01205 } 01206 } 01207 if (!res) { 01208 /* Note -- parent may have disappeared */ 01209 if (p->abouttograb) { 01210 newlyavailable->acknowledged = 1; 01211 /* Safe -- agent lock already held */ 01212 ast_setstate(parent, AST_STATE_UP); 01213 ast_setstate(chan, AST_STATE_UP); 01214 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01215 /* Go ahead and mark the channel as a zombie so that masquerade will 01216 destroy it for us, and we need not call ast_hangup */ 01217 ast_mutex_lock(&parent->lock); 01218 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01219 ast_channel_masquerade(parent, chan); 01220 ast_mutex_unlock(&parent->lock); 01221 p->abouttograb = 0; 01222 } else { 01223 if (option_debug) 01224 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); 01225 agent_cleanup(newlyavailable); 01226 } 01227 } else { 01228 if (option_debug) 01229 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); 01230 agent_cleanup(newlyavailable); 01231 } 01232 } 01233 return 0; 01234 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1236 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().
01237 { 01238 struct agent_pvt *p; 01239 int res=0; 01240 01241 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); 01242 if (needlock) 01243 AST_LIST_LOCK(&agents); 01244 AST_LIST_TRAVERSE(&agents, p, list) { 01245 if (p == newlyavailable) { 01246 continue; 01247 } 01248 ast_mutex_lock(&p->lock); 01249 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01250 if (option_debug) 01251 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01252 ast_mutex_unlock(&p->lock); 01253 break; 01254 } 01255 ast_mutex_unlock(&p->lock); 01256 } 01257 if (needlock) 01258 AST_LIST_UNLOCK(&agents); 01259 if (p) { 01260 ast_mutex_unlock(&newlyavailable->lock); 01261 if (option_debug > 2) 01262 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01263 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01264 if (option_debug > 2) 01265 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01266 if (!res) { 01267 res = ast_waitstream(newlyavailable->chan, ""); 01268 if (option_debug) 01269 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01270 } 01271 ast_mutex_lock(&newlyavailable->lock); 01272 } 01273 return res; 01274 }
static char* complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1595 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_TRAVERSE, AST_MAX_AGENT, ast_strdup, len, and agent_pvt::name.
01596 { 01597 if (pos == 2) { 01598 struct agent_pvt *p; 01599 char name[AST_MAX_AGENT]; 01600 int which = 0, len = strlen(word); 01601 01602 AST_LIST_TRAVERSE(&agents, p, list) { 01603 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01604 if (!strncasecmp(word, name, len) && ++which > state) 01605 return ast_strdup(name); 01606 } 01607 } else if (pos == 3 && state == 0) 01608 return ast_strdup("soft"); 01609 01610 return NULL; 01611 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2393 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().
02394 { 02395 struct agent_pvt *cur_agent = NULL; 02396 char buf[256]; 02397 02398 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02399 if (cur_agent->chan) 02400 continue; 02401 02402 if (!ast_strlen_zero(cur_agent->loginchan)) { 02403 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02404 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02405 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02406 else if (option_debug) 02407 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02408 } else { 02409 /* Delete - no agent or there is an error */ 02410 ast_db_del(pa_family, cur_agent->agent); 02411 } 02412 } 02413 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static] |
Definition at line 2516 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02517 { 02518 struct agent_pvt *cur; 02519 02520 AST_LIST_TRAVERSE(&agents, cur, list) { 02521 if (!strcmp(cur->agent, agentid)) 02522 break; 02523 } 02524 02525 return cur; 02526 }
static int function_agent | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2528 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(), find_agent(), LOG_WARNING, and parse().
02529 { 02530 char *parse; 02531 AST_DECLARE_APP_ARGS(args, 02532 AST_APP_ARG(agentid); 02533 AST_APP_ARG(item); 02534 ); 02535 char *tmp; 02536 struct agent_pvt *agent; 02537 02538 buf[0] = '\0'; 02539 02540 if (ast_strlen_zero(data)) { 02541 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02542 return -1; 02543 } 02544 02545 parse = ast_strdupa(data); 02546 02547 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02548 if (!args.item) 02549 args.item = "status"; 02550 02551 if (!(agent = find_agent(args.agentid))) { 02552 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02553 return -1; 02554 } 02555 02556 if (!strcasecmp(args.item, "status")) { 02557 char *status = "LOGGEDOUT"; 02558 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02559 status = "LOGGEDIN"; 02560 ast_copy_string(buf, status, len); 02561 } else if (!strcasecmp(args.item, "password")) 02562 ast_copy_string(buf, agent->password, len); 02563 else if (!strcasecmp(args.item, "name")) 02564 ast_copy_string(buf, agent->name, len); 02565 else if (!strcasecmp(args.item, "mohclass")) 02566 ast_copy_string(buf, agent->moh, len); 02567 else if (!strcasecmp(args.item, "channel")) { 02568 if (agent->chan) { 02569 ast_copy_string(buf, agent->chan->name, len); 02570 tmp = strrchr(buf, '-'); 02571 if (tmp) 02572 *tmp = '\0'; 02573 } 02574 } else if (!strcasecmp(args.item, "exten")) 02575 ast_copy_string(buf, agent->loginchan, len); 02576 02577 return 0; 02578 }
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 2603 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().
02604 { 02605 /* Make sure we can register our agent channel type */ 02606 if (ast_channel_register(&agent_tech)) { 02607 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02608 return -1; 02609 } 02610 /* Read in the config */ 02611 if (!read_agent_config()) 02612 return AST_MODULE_LOAD_DECLINE; 02613 if (persistent_agents) 02614 reload_agents(); 02615 /* Dialplan applications */ 02616 ast_register_application(app, login_exec, synopsis, descrip); 02617 ast_register_application(app2, callback_exec, synopsis2, descrip2); 02618 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02619 02620 /* Manager commands */ 02621 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02622 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02623 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login); 02624 02625 /* CLI Commands */ 02626 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02627 02628 /* Dialplan Functions */ 02629 ast_custom_function_register(&agent_function); 02630 02631 return 0; 02632 }
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 2210 of file chan_agent.c.
References __login_exec(), and ast_module_user::chan.
Referenced by load_module().
02211 { 02212 return __login_exec(chan, data, 0); 02213 }
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 1014 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().
01015 { 01016 struct ast_config *cfg; 01017 struct ast_config *ucfg; 01018 struct ast_variable *v; 01019 struct agent_pvt *p; 01020 const char *general_val; 01021 const char *catname; 01022 const char *hasagent; 01023 int genhasagent; 01024 01025 group = 0; 01026 autologoff = 0; 01027 wrapuptime = 0; 01028 ackcall = 0; 01029 endcall = 1; 01030 cfg = ast_config_load(config); 01031 if (!cfg) { 01032 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01033 return 0; 01034 } 01035 AST_LIST_LOCK(&agents); 01036 AST_LIST_TRAVERSE(&agents, p, list) { 01037 p->dead = 1; 01038 } 01039 strcpy(moh, "default"); 01040 /* set the default recording values */ 01041 recordagentcalls = 0; 01042 strcpy(recordformat, "wav"); 01043 strcpy(recordformatext, "wav"); 01044 urlprefix[0] = '\0'; 01045 savecallsin[0] = '\0'; 01046 01047 /* Read in [general] section for persistence */ 01048 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01049 persistent_agents = ast_true(general_val); 01050 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01051 01052 /* Read in the [agents] section */ 01053 v = ast_variable_browse(cfg, "agents"); 01054 while(v) { 01055 /* Create the interface list */ 01056 if (!strcasecmp(v->name, "agent")) { 01057 add_agent(v->value, 0); 01058 } else if (!strcasecmp(v->name, "group")) { 01059 group = ast_get_group(v->value); 01060 } else if (!strcasecmp(v->name, "autologoff")) { 01061 autologoff = atoi(v->value); 01062 if (autologoff < 0) 01063 autologoff = 0; 01064 } else if (!strcasecmp(v->name, "ackcall")) { 01065 if (!strcasecmp(v->value, "always")) 01066 ackcall = 2; 01067 else if (ast_true(v->value)) 01068 ackcall = 1; 01069 else 01070 ackcall = 0; 01071 } else if (!strcasecmp(v->name, "endcall")) { 01072 endcall = ast_true(v->value); 01073 } else if (!strcasecmp(v->name, "wrapuptime")) { 01074 wrapuptime = atoi(v->value); 01075 if (wrapuptime < 0) 01076 wrapuptime = 0; 01077 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01078 maxlogintries = atoi(v->value); 01079 if (maxlogintries < 0) 01080 maxlogintries = 0; 01081 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01082 strcpy(agentgoodbye,v->value); 01083 } else if (!strcasecmp(v->name, "musiconhold")) { 01084 ast_copy_string(moh, v->value, sizeof(moh)); 01085 } else if (!strcasecmp(v->name, "updatecdr")) { 01086 if (ast_true(v->value)) 01087 updatecdr = 1; 01088 else 01089 updatecdr = 0; 01090 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01091 if (ast_true(v->value)) 01092 autologoffunavail = 1; 01093 else 01094 autologoffunavail = 0; 01095 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01096 recordagentcalls = ast_true(v->value); 01097 } else if (!strcasecmp(v->name, "recordformat")) { 01098 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01099 if (!strcasecmp(v->value, "wav49")) 01100 strcpy(recordformatext, "WAV"); 01101 else 01102 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01103 } else if (!strcasecmp(v->name, "urlprefix")) { 01104 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01105 if (urlprefix[strlen(urlprefix) - 1] != '/') 01106 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01107 } else if (!strcasecmp(v->name, "savecallsin")) { 01108 if (v->value[0] == '/') 01109 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01110 else 01111 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01112 if (savecallsin[strlen(savecallsin) - 1] != '/') 01113 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01114 } else if (!strcasecmp(v->name, "custom_beep")) { 01115 ast_copy_string(beep, v->value, sizeof(beep)); 01116 } 01117 v = v->next; 01118 } 01119 if ((ucfg = ast_config_load("users.conf"))) { 01120 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01121 catname = ast_category_browse(ucfg, NULL); 01122 while(catname) { 01123 if (strcasecmp(catname, "general")) { 01124 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01125 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01126 char tmp[256]; 01127 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01128 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01129 if (!fullname) 01130 fullname = ""; 01131 if (!secret) 01132 secret = ""; 01133 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01134 add_agent(tmp, 0); 01135 } 01136 } 01137 catname = ast_category_browse(ucfg, catname); 01138 } 01139 ast_config_destroy(ucfg); 01140 } 01141 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01142 if (p->dead) { 01143 AST_LIST_REMOVE_CURRENT(&agents, list); 01144 /* Destroy if appropriate */ 01145 if (!p->owner) { 01146 if (!p->chan) { 01147 ast_mutex_destroy(&p->lock); 01148 ast_mutex_destroy(&p->app_lock); 01149 free(p); 01150 } else { 01151 /* Cause them to hang up */ 01152 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01153 } 01154 } 01155 } 01156 } 01157 AST_LIST_TRAVERSE_SAFE_END 01158 AST_LIST_UNLOCK(&agents); 01159 ast_config_destroy(cfg); 01160 return 1; 01161 }
static int reload | ( | void | ) | [static] |
Definition at line 2634 of file chan_agent.c.
References read_agent_config(), and reload_agents().
Referenced by reload(), and rpt_do_reload().
02635 { 02636 read_agent_config(); 02637 if (persistent_agents) 02638 reload_agents(); 02639 return 0; 02640 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2418 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().
02419 { 02420 char *agent_num; 02421 struct ast_db_entry *db_tree; 02422 struct ast_db_entry *entry; 02423 struct agent_pvt *cur_agent; 02424 char agent_data[256]; 02425 char *parse; 02426 char *agent_chan; 02427 char *agent_callerid; 02428 02429 db_tree = ast_db_gettree(pa_family, NULL); 02430 02431 AST_LIST_LOCK(&agents); 02432 for (entry = db_tree; entry; entry = entry->next) { 02433 agent_num = entry->key + strlen(pa_family) + 2; 02434 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02435 ast_mutex_lock(&cur_agent->lock); 02436 if (strcmp(agent_num, cur_agent->agent) == 0) 02437 break; 02438 ast_mutex_unlock(&cur_agent->lock); 02439 } 02440 if (!cur_agent) { 02441 ast_db_del(pa_family, agent_num); 02442 continue; 02443 } else 02444 ast_mutex_unlock(&cur_agent->lock); 02445 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02446 if (option_debug) 02447 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02448 parse = agent_data; 02449 agent_chan = strsep(&parse, ";"); 02450 agent_callerid = strsep(&parse, ";"); 02451 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02452 if (agent_callerid) { 02453 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02454 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02455 } else 02456 cur_agent->logincallerid[0] = '\0'; 02457 if (cur_agent->loginstart == 0) 02458 time(&cur_agent->loginstart); 02459 ast_device_state_changed("Agent/%s", cur_agent->agent); 02460 } 02461 } 02462 AST_LIST_UNLOCK(&agents); 02463 if (db_tree) { 02464 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02465 ast_db_freetree(db_tree); 02466 } 02467 }
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 711 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().
00712 { 00713 char buf[AST_MAX_BUF]; 00714 00715 /* if there is no Caller ID, nothing to do */ 00716 if (ast_strlen_zero(callerid)) 00717 return; 00718 00719 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00720 pbx_builtin_setvar_helper(NULL, buf, agent); 00721 }
static int unload_module | ( | void | ) | [static] |
Definition at line 2642 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().
02643 { 02644 struct agent_pvt *p; 02645 /* First, take us out of the channel loop */ 02646 ast_channel_unregister(&agent_tech); 02647 /* Unregister dialplan functions */ 02648 ast_custom_function_unregister(&agent_function); 02649 /* Unregister CLI commands */ 02650 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02651 /* Unregister dialplan applications */ 02652 ast_unregister_application(app); 02653 ast_unregister_application(app2); 02654 ast_unregister_application(app3); 02655 /* Unregister manager command */ 02656 ast_manager_unregister("Agents"); 02657 ast_manager_unregister("AgentLogoff"); 02658 ast_manager_unregister("AgentCallbackLogin"); 02659 /* Unregister channel */ 02660 AST_LIST_LOCK(&agents); 02661 /* Hangup all interfaces if they have an owner */ 02662 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02663 if (p->owner) 02664 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02665 free(p); 02666 } 02667 AST_LIST_UNLOCK(&agents); 02668 AST_LIST_HEAD_DESTROY(&agents); 02669 return 0; 02670 }
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 1743 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 256 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(), add_extensions(), answer_exec_enable(), ast_pbx_run_app(), async_wait(), check_app_args(), check_pval_item(), conf_run(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_context_add_extension(), handle_context_add_extension_deprecated(), handle_exec(), load_module(), page_exec(), pbx_builtin_execiftime(), pbx_exec(), pbx_extension_helper(), realtime_exec(), try_calling(), tryexec_exec(), and unload_module().
const char app2[] = "AgentCallbackLogin" [static] |
Definition at line 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 1748 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 1753 of file chan_agent.c.
const char config[] = "agents.conf" [static] |
Definition at line 77 of file chan_agent.c.
Referenced by app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_channel_bridge(), ast_config_new(), ast_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_retrieve(), builtin_atxfer(), category_get(), cdr_pgsql_connect(), database_first_connect(), do_reload(), load_module(), load_odbc_config(), misdn_cfg_init(), my_load_module(), park_exec(), parse_config(), pbx_load_module(), read_config_maps(), reload(), reload_config(), set_config_flags(), and unload_module().
const char descrip[] [static] |
const char descrip2[] [static] |
const char descrip3[] [static] |
Definition at line 104 of file chan_agent.c.
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_register(), 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 1739 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 1735 of file chan_agent.c.
Definition at line 85 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.