#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
Go to the source code of this file.
Data Structures | |
struct | agent_pvt |
Structure representing an agent. More... | |
Defines | |
#define | AST_MAX_AGENT 80 |
#define | AST_MAX_BUF 256 |
#define | AST_MAX_FILENAME_LEN 256 |
#define | CHECK_FORMATS(ast, p) |
#define | CLEANUP(ast, p) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
#define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
#define | PA_MAX_LEN 2048 |
Functions | |
static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
static int | __login_exec (struct ast_channel *chan, void *data, int callbackmode) |
Log in agent application. | |
static int | action_agent_callback_login (struct mansession *s, const struct message *m) |
static int | action_agent_logoff (struct mansession *s, const struct message *m) |
static int | action_agents (struct mansession *s, const struct message *m) |
static struct agent_pvt * | add_agent (char *agent, int pending) |
static int | agent_ack_sleep (void *data) |
static int | agent_answer (struct ast_channel *ast) |
static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
static int | agent_cleanup (struct agent_pvt *p) |
static int | agent_cont_sleep (void *data) |
static int | agent_devicestate (void *data) |
Part of PBX channel interface. | |
static int | agent_digit_begin (struct ast_channel *ast, char digit) |
static int | agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
static 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 |
struct ast_custom_function | agent_function |
static char | agent_logoff_usage [] |
static struct ast_channel_tech | agent_tech |
Channel interface description for PBX integration. | |
static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye" |
static const char | app [] = "AgentLogin" |
static const char | app2 [] = "AgentCallbackLogin" |
static const char | app3 [] = "AgentMonitorOutgoing" |
static int | autologoff |
static int | autologoffunavail = 0 |
static char | beep [AST_MAX_BUF] = "beep" |
static struct ast_cli_entry | cli_agents [] |
static struct ast_cli_entry | cli_show_agents_deprecated |
static struct ast_cli_entry | cli_show_agents_online_deprecated |
static const char | config [] = "agents.conf" |
static const char | descrip [] |
static const char | descrip2 [] |
static const char | descrip3 [] |
static int | endcall |
static ast_group_t | group |
static const char | mandescr_agent_callback_login [] |
static const char | mandescr_agent_logoff [] |
static const char | mandescr_agents [] |
static int | maxlogintries = 3 |
static char | moh [80] = "default" |
static int | multiplelogin = 1 |
static const char | pa_family [] = "Agents" |
static int | persistent_agents = 0 |
static int | recordagentcalls = 0 |
static char | recordformat [AST_MAX_BUF] = "" |
static char | recordformatext [AST_MAX_BUF] = "" |
static char | savecallsin [AST_MAX_BUF] = "" |
static char | show_agents_online_usage [] |
static char | show_agents_usage [] |
static const char | synopsis [] = "Call agent login" |
static const char | synopsis2 [] = "Call agent callback login" |
static const char | synopsis3 [] = "Record agent's outgoing call" |
static const char | tdesc [] = "Call Agent Proxy Channel" |
static int | updatecdr = 0 |
static char | urlprefix [AST_MAX_BUF] = "" |
static int | wrapuptime |
This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.
Definition in file chan_agent.c.
#define AST_MAX_AGENT 80 |
Agent ID or Password max length
Definition at line 143 of file chan_agent.c.
Referenced by __login_exec(), agent_logoff_maintenance(), agentmonitoroutgoing_exec(), and complete_agent_logoff_cmd().
#define AST_MAX_BUF 256 |
Definition at line 144 of file chan_agent.c.
Referenced by __agent_start_monitoring(), __login_exec(), agentmonitoroutgoing_exec(), agents_show(), agents_show_online(), and set_agentbycallerid().
#define AST_MAX_FILENAME_LEN 256 |
#define CHECK_FORMATS | ( | ast, | |||
p | ) |
#define CLEANUP | ( | ast, | |||
p | ) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
Definition at line 226 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
#define GETAGENTBYCALLERID "AGENTBYCALLERID" |
Definition at line 172 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().
#define PA_MAX_LEN 2048 |
The maximum length of each persistent member agent database entry
Definition at line 148 of file chan_agent.c.
static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
struct agent_pvt * | p, | |||
int | needlock | |||
) | [static] |
Definition at line 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, filename); 00415 ast_monitor_start(ast, recordformat, tmp, needlock); 00416 ast_monitor_setjoinfiles(ast, 1); 00417 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", 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 1782 of file chan_agent.c.
References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, ast_channel::exten, free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), agent_pvt::pending, ast_channel::priority, ast_channel::readformat, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, agent_pvt::wrapuptime, and ast_channel::writeformat.
Referenced by callback_exec(), and login_exec().
01783 { 01784 int res=0; 01785 int tries = 0; 01786 int max_login_tries = maxlogintries; 01787 struct agent_pvt *p; 01788 struct ast_module_user *u; 01789 int login_state = 0; 01790 char user[AST_MAX_AGENT] = ""; 01791 char pass[AST_MAX_AGENT]; 01792 char agent[AST_MAX_AGENT] = ""; 01793 char xpass[AST_MAX_AGENT] = ""; 01794 char *errmsg; 01795 char *parse; 01796 AST_DECLARE_APP_ARGS(args, 01797 AST_APP_ARG(agent_id); 01798 AST_APP_ARG(options); 01799 AST_APP_ARG(extension); 01800 ); 01801 const char *tmpoptions = NULL; 01802 char *context = NULL; 01803 int play_announcement = 1; 01804 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01805 int update_cdr = updatecdr; 01806 char *filename = "agent-loginok"; 01807 char tmpchan[AST_MAX_BUF] = ""; 01808 01809 u = ast_module_user_add(chan); 01810 01811 parse = ast_strdupa(data); 01812 01813 AST_STANDARD_APP_ARGS(args, parse); 01814 01815 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01816 01817 /* Set Channel Specific Login Overrides */ 01818 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01819 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01820 if (max_login_tries < 0) 01821 max_login_tries = 0; 01822 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01823 if (option_verbose > 2) 01824 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); 01825 } 01826 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01827 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01828 update_cdr = 1; 01829 else 01830 update_cdr = 0; 01831 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01832 if (option_verbose > 2) 01833 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01834 } 01835 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01836 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01837 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01838 if (option_verbose > 2) 01839 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01840 } 01841 /* End Channel Specific Login Overrides */ 01842 01843 if (callbackmode && args.extension) { 01844 parse = args.extension; 01845 args.extension = strsep(&parse, "@"); 01846 context = parse; 01847 } 01848 01849 if (!ast_strlen_zero(args.options)) { 01850 if (strchr(args.options, 's')) { 01851 play_announcement = 0; 01852 } 01853 } 01854 01855 if (chan->_state != AST_STATE_UP) 01856 res = ast_answer(chan); 01857 if (!res) { 01858 if (!ast_strlen_zero(args.agent_id)) 01859 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01860 else 01861 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01862 } 01863 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01864 tries++; 01865 /* Check for password */ 01866 AST_LIST_LOCK(&agents); 01867 AST_LIST_TRAVERSE(&agents, p, list) { 01868 if (!strcmp(p->agent, user) && !p->pending) 01869 ast_copy_string(xpass, p->password, sizeof(xpass)); 01870 } 01871 AST_LIST_UNLOCK(&agents); 01872 if (!res) { 01873 if (!ast_strlen_zero(xpass)) 01874 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01875 else 01876 pass[0] = '\0'; 01877 } 01878 errmsg = "agent-incorrect"; 01879 01880 #if 0 01881 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01882 #endif 01883 01884 /* Check again for accuracy */ 01885 AST_LIST_LOCK(&agents); 01886 AST_LIST_TRAVERSE(&agents, p, list) { 01887 ast_mutex_lock(&p->lock); 01888 if (!strcmp(p->agent, user) && 01889 !strcmp(p->password, pass) && !p->pending) { 01890 login_state = 1; /* Successful Login */ 01891 01892 /* Ensure we can't be gotten until we're done */ 01893 gettimeofday(&p->lastdisc, NULL); 01894 p->lastdisc.tv_sec++; 01895 01896 /* Set Channel Specific Agent Overrides */ 01897 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01898 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 01899 p->ackcall = 2; 01900 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 01901 p->ackcall = 1; 01902 else 01903 p->ackcall = 0; 01904 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01905 if (option_verbose > 2) 01906 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 01907 } 01908 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01909 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01910 if (p->autologoff < 0) 01911 p->autologoff = 0; 01912 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 01913 if (option_verbose > 2) 01914 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 01915 } 01916 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 01917 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 01918 if (p->wrapuptime < 0) 01919 p->wrapuptime = 0; 01920 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 01921 if (option_verbose > 2) 01922 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 01923 } 01924 /* End Channel Specific Agent Overrides */ 01925 if (!p->chan) { 01926 char last_loginchan[80] = ""; 01927 long logintime; 01928 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01929 01930 if (callbackmode) { 01931 int pos = 0; 01932 /* Retrieve login chan */ 01933 for (;;) { 01934 if (!ast_strlen_zero(args.extension)) { 01935 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 01936 res = 0; 01937 } else 01938 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 01939 if (ast_strlen_zero(tmpchan) ) 01940 break; 01941 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 01942 if(!allow_multiple_login(tmpchan,context) ) { 01943 args.extension = NULL; 01944 pos = 0; 01945 } else 01946 break; 01947 } 01948 if (args.extension) { 01949 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 01950 args.extension = NULL; 01951 pos = 0; 01952 } else { 01953 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 01954 res = ast_streamfile(chan, "invalid", chan->language); 01955 if (!res) 01956 res = ast_waitstream(chan, AST_DIGIT_ANY); 01957 if (res > 0) { 01958 tmpchan[0] = res; 01959 tmpchan[1] = '\0'; 01960 pos = 1; 01961 } else { 01962 tmpchan[0] = '\0'; 01963 pos = 0; 01964 } 01965 } 01966 } 01967 args.extension = tmpchan; 01968 if (!res) { 01969 set_agentbycallerid(p->logincallerid, NULL); 01970 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 01971 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 01972 else { 01973 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 01974 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 01975 } 01976 p->acknowledged = 0; 01977 if (ast_strlen_zero(p->loginchan)) { 01978 login_state = 2; 01979 filename = "agent-loggedoff"; 01980 } else { 01981 if (chan->cid.cid_num) { 01982 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 01983 set_agentbycallerid(p->logincallerid, p->agent); 01984 } else 01985 p->logincallerid[0] = '\0'; 01986 } 01987 01988 if(update_cdr && chan->cdr) 01989 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 01990 01991 } 01992 } else { 01993 p->loginchan[0] = '\0'; 01994 p->logincallerid[0] = '\0'; 01995 p->acknowledged = 0; 01996 } 01997 ast_mutex_unlock(&p->lock); 01998 AST_LIST_UNLOCK(&agents); 01999 if( !res && play_announcement==1 ) 02000 res = ast_streamfile(chan, filename, chan->language); 02001 if (!res) 02002 ast_waitstream(chan, ""); 02003 AST_LIST_LOCK(&agents); 02004 ast_mutex_lock(&p->lock); 02005 if (!res) { 02006 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02007 if (res) 02008 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02009 } 02010 if (!res) { 02011 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02012 if (res) 02013 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02014 } 02015 /* Check once more just in case */ 02016 if (p->chan) 02017 res = -1; 02018 if (callbackmode && !res) { 02019 /* Just say goodbye and be done with it */ 02020 if (!ast_strlen_zero(p->loginchan)) { 02021 if (p->loginstart == 0) 02022 time(&p->loginstart); 02023 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02024 "Agent: %s\r\n" 02025 "Loginchan: %s\r\n" 02026 "Uniqueid: %s\r\n", 02027 p->agent, p->loginchan, chan->uniqueid); 02028 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02029 if (option_verbose > 1) 02030 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02031 ast_device_state_changed("Agent/%s", p->agent); 02032 if (persistent_agents) 02033 dump_agents(); 02034 } else { 02035 logintime = time(NULL) - p->loginstart; 02036 p->loginstart = 0; 02037 02038 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02039 if (option_verbose > 1) 02040 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02041 } 02042 AST_LIST_UNLOCK(&agents); 02043 if (!res) 02044 res = ast_safe_sleep(chan, 500); 02045 ast_mutex_unlock(&p->lock); 02046 } else if (!res) { 02047 ast_indicate_data(chan, AST_CONTROL_HOLD, 02048 S_OR(p->moh, NULL), 02049 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02050 if (p->loginstart == 0) 02051 time(&p->loginstart); 02052 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02053 "Agent: %s\r\n" 02054 "Channel: %s\r\n" 02055 "Uniqueid: %s\r\n", 02056 p->agent, chan->name, chan->uniqueid); 02057 if (update_cdr && chan->cdr) 02058 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02059 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02060 if (option_verbose > 1) 02061 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02062 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02063 /* Login this channel and wait for it to go away */ 02064 p->chan = chan; 02065 if (p->ackcall > 1) 02066 check_beep(p, 0); 02067 else 02068 check_availability(p, 0); 02069 ast_mutex_unlock(&p->lock); 02070 AST_LIST_UNLOCK(&agents); 02071 ast_device_state_changed("Agent/%s", p->agent); 02072 while (res >= 0) { 02073 ast_mutex_lock(&p->lock); 02074 if (p->deferlogoff && p->chan) { 02075 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02076 p->deferlogoff = 0; 02077 } 02078 if (p->chan != chan) 02079 res = -1; 02080 ast_mutex_unlock(&p->lock); 02081 /* Yield here so other interested threads can kick in. */ 02082 sched_yield(); 02083 if (res) 02084 break; 02085 02086 AST_LIST_LOCK(&agents); 02087 ast_mutex_lock(&p->lock); 02088 if (p->lastdisc.tv_sec) { 02089 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02090 if (option_debug) 02091 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02092 p->lastdisc = ast_tv(0, 0); 02093 if (p->ackcall > 1) 02094 check_beep(p, 0); 02095 else 02096 check_availability(p, 0); 02097 } 02098 } 02099 ast_mutex_unlock(&p->lock); 02100 AST_LIST_UNLOCK(&agents); 02101 /* Synchronize channel ownership between call to agent and itself. */ 02102 ast_mutex_lock( &p->app_lock ); 02103 ast_mutex_lock(&p->lock); 02104 p->owning_app = pthread_self(); 02105 ast_mutex_unlock(&p->lock); 02106 if (p->ackcall > 1) 02107 res = agent_ack_sleep(p); 02108 else 02109 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02110 ast_mutex_unlock( &p->app_lock ); 02111 if ((p->ackcall > 1) && (res == 1)) { 02112 AST_LIST_LOCK(&agents); 02113 ast_mutex_lock(&p->lock); 02114 check_availability(p, 0); 02115 ast_mutex_unlock(&p->lock); 02116 AST_LIST_UNLOCK(&agents); 02117 res = 0; 02118 } 02119 sched_yield(); 02120 } 02121 ast_mutex_lock(&p->lock); 02122 if (res && p->owner) 02123 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02124 /* Log us off if appropriate */ 02125 if (p->chan == chan) 02126 p->chan = NULL; 02127 p->acknowledged = 0; 02128 logintime = time(NULL) - p->loginstart; 02129 p->loginstart = 0; 02130 ast_mutex_unlock(&p->lock); 02131 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02132 "Agent: %s\r\n" 02133 "Logintime: %ld\r\n" 02134 "Uniqueid: %s\r\n", 02135 p->agent, logintime, chan->uniqueid); 02136 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02137 if (option_verbose > 1) 02138 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02139 /* If there is no owner, go ahead and kill it now */ 02140 ast_device_state_changed("Agent/%s", p->agent); 02141 if (p->dead && !p->owner) { 02142 ast_mutex_destroy(&p->lock); 02143 ast_mutex_destroy(&p->app_lock); 02144 free(p); 02145 } 02146 } 02147 else { 02148 ast_mutex_unlock(&p->lock); 02149 p = NULL; 02150 } 02151 res = -1; 02152 } else { 02153 ast_mutex_unlock(&p->lock); 02154 errmsg = "agent-alreadyon"; 02155 p = NULL; 02156 } 02157 break; 02158 } 02159 ast_mutex_unlock(&p->lock); 02160 } 02161 if (!p) 02162 AST_LIST_UNLOCK(&agents); 02163 02164 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02165 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02166 } 02167 02168 if (!res) 02169 res = ast_safe_sleep(chan, 500); 02170 02171 /* AgentLogin() exit */ 02172 if (!callbackmode) { 02173 ast_module_user_remove(u); 02174 return -1; 02175 } else { /* AgentCallbackLogin() exit*/ 02176 /* Set variables */ 02177 if (login_state > 0) { 02178 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user); 02179 if (login_state==1) { 02180 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on"); 02181 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension); 02182 } else 02183 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off"); 02184 } else { 02185 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail"); 02186 } 02187 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) { 02188 ast_module_user_remove(u); 02189 return 0; 02190 } 02191 /* Do we need to play agent-goodbye now that we will be hanging up? */ 02192 if (play_announcement) { 02193 if (!res) 02194 res = ast_safe_sleep(chan, 1000); 02195 res = ast_streamfile(chan, agent_goodbye, chan->language); 02196 if (!res) 02197 res = ast_waitstream(chan, ""); 02198 if (!res) 02199 res = ast_safe_sleep(chan, 1000); 02200 } 02201 } 02202 02203 ast_module_user_remove(u); 02204 02205 /* We should never get here if next priority exists when in callbackmode */ 02206 return -1; 02207 }
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 2258 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, ast_device_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_verbose(), astman_get_header(), astman_send_ack(), astman_send_error(), callback_deprecated(), agent_pvt::chan, context, dump_agents(), EVENT_FLAG_AGENT, exten, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), option_verbose, agent_pvt::pending, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.
Referenced by load_module().
02259 { 02260 const char *agent = astman_get_header(m, "Agent"); 02261 const char *exten = astman_get_header(m, "Exten"); 02262 const char *context = astman_get_header(m, "Context"); 02263 const char *wrapuptime_s = astman_get_header(m, "WrapupTime"); 02264 const char *ackcall_s = astman_get_header(m, "AckCall"); 02265 struct agent_pvt *p; 02266 int login_state = 0; 02267 02268 callback_deprecated(); 02269 02270 if (ast_strlen_zero(agent)) { 02271 astman_send_error(s, m, "No agent specified"); 02272 return 0; 02273 } 02274 02275 if (ast_strlen_zero(exten)) { 02276 astman_send_error(s, m, "No extension specified"); 02277 return 0; 02278 } 02279 02280 AST_LIST_LOCK(&agents); 02281 AST_LIST_TRAVERSE(&agents, p, list) { 02282 if (strcmp(p->agent, agent) || p->pending) 02283 continue; 02284 if (p->chan) { 02285 login_state = 2; /* already logged in (and on the phone)*/ 02286 break; 02287 } 02288 ast_mutex_lock(&p->lock); 02289 login_state = 1; /* Successful Login */ 02290 02291 if (ast_strlen_zero(context)) 02292 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan)); 02293 else 02294 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context); 02295 02296 if (!ast_strlen_zero(wrapuptime_s)) { 02297 p->wrapuptime = atoi(wrapuptime_s); 02298 if (p->wrapuptime < 0) 02299 p->wrapuptime = 0; 02300 } 02301 02302 if (ast_true(ackcall_s)) 02303 p->ackcall = 1; 02304 else 02305 p->ackcall = 0; 02306 02307 if (p->loginstart == 0) 02308 time(&p->loginstart); 02309 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 02310 "Agent: %s\r\n" 02311 "Loginchan: %s\r\n", 02312 p->agent, p->loginchan); 02313 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 02314 if (option_verbose > 1) 02315 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 02316 ast_device_state_changed("Agent/%s", p->agent); 02317 ast_mutex_unlock(&p->lock); 02318 if (persistent_agents) 02319 dump_agents(); 02320 } 02321 AST_LIST_UNLOCK(&agents); 02322 02323 if (login_state == 1) 02324 astman_send_ack(s, m, "Agent logged in"); 02325 else if (login_state == 0) 02326 astman_send_error(s, m, "No such agent"); 02327 else if (login_state == 2) 02328 astman_send_error(s, m, "Agent already logged in"); 02329 02330 return 0; 02331 }
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 1576 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
01577 { 01578 const char *agent = astman_get_header(m, "Agent"); 01579 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01580 int soft; 01581 int ret; /* return value of agent_logoff */ 01582 01583 if (ast_strlen_zero(agent)) { 01584 astman_send_error(s, m, "No agent specified"); 01585 return 0; 01586 } 01587 01588 soft = ast_true(soft_s) ? 1 : 0; 01589 ret = agent_logoff(agent, soft); 01590 if (ret == 0) 01591 astman_send_ack(s, m, "Agent logged out"); 01592 else 01593 astman_send_error(s, m, "No such agent"); 01594 01595 return 0; 01596 }
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 1411 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, agent_pvt::owner, S_OR, and username.
Referenced by load_module().
01412 { 01413 const char *id = astman_get_header(m,"ActionID"); 01414 char idText[256] = ""; 01415 char chanbuf[256]; 01416 struct agent_pvt *p; 01417 char *username = NULL; 01418 char *loginChan = NULL; 01419 char *talkingtoChan = NULL; 01420 char *status = NULL; 01421 01422 if (!ast_strlen_zero(id)) 01423 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01424 astman_send_ack(s, m, "Agents will follow"); 01425 AST_LIST_LOCK(&agents); 01426 AST_LIST_TRAVERSE(&agents, p, list) { 01427 ast_mutex_lock(&p->lock); 01428 01429 /* Status Values: 01430 AGENT_LOGGEDOFF - Agent isn't logged in 01431 AGENT_IDLE - Agent is logged in, and waiting for call 01432 AGENT_ONCALL - Agent is logged in, and on a call 01433 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01434 01435 username = S_OR(p->name, "None"); 01436 01437 /* Set a default status. It 'should' get changed. */ 01438 status = "AGENT_UNKNOWN"; 01439 01440 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01441 loginChan = p->loginchan; 01442 talkingtoChan = "n/a"; 01443 status = "AGENT_IDLE"; 01444 if (p->acknowledged) { 01445 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01446 loginChan = chanbuf; 01447 } 01448 } else if (p->chan) { 01449 loginChan = ast_strdupa(p->chan->name); 01450 if (p->owner && p->owner->_bridge) { 01451 talkingtoChan = p->chan->cid.cid_num; 01452 status = "AGENT_ONCALL"; 01453 } else { 01454 talkingtoChan = "n/a"; 01455 status = "AGENT_IDLE"; 01456 } 01457 } else { 01458 loginChan = "n/a"; 01459 talkingtoChan = "n/a"; 01460 status = "AGENT_LOGGEDOFF"; 01461 } 01462 01463 astman_append(s, "Event: Agents\r\n" 01464 "Agent: %s\r\n" 01465 "Name: %s\r\n" 01466 "Status: %s\r\n" 01467 "LoggedInChan: %s\r\n" 01468 "LoggedInTime: %d\r\n" 01469 "TalkingTo: %s\r\n" 01470 "%s" 01471 "\r\n", 01472 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); 01473 ast_mutex_unlock(&p->lock); 01474 } 01475 AST_LIST_UNLOCK(&agents); 01476 astman_append(s, "Event: AgentsComplete\r\n" 01477 "%s" 01478 "\r\n",idText); 01479 return 0; 01480 }
static struct agent_pvt* add_agent | ( | char * | agent, | |
int | pending | |||
) | [static, read] |
Adds an agent to the global list of agents.
agent | A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" | |
pending | If it is pending or not. |
Definition at line 286 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::agent, agent_pvt::app_lock, agent_pvt::app_sleep_cond, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::moh, agent_pvt::name, agent_pvt::owning_app, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
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, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.
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, read] |
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, and option_debug.
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) > 0) 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 2477 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.
02478 { 02479 struct agent_pvt *p; 02480 char *s; 02481 ast_group_t groupmatch; 02482 int groupoff; 02483 int waitforagent=0; 02484 int res = AST_DEVICE_INVALID; 02485 02486 s = data; 02487 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) 02488 groupmatch = (1 << groupoff); 02489 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 02490 groupmatch = (1 << groupoff); 02491 waitforagent = 1; 02492 } else 02493 groupmatch = 0; 02494 02495 /* Check actual logged in agents first */ 02496 AST_LIST_LOCK(&agents); 02497 AST_LIST_TRAVERSE(&agents, p, list) { 02498 ast_mutex_lock(&p->lock); 02499 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02500 if (p->owner) { 02501 if (res != AST_DEVICE_INUSE) 02502 res = AST_DEVICE_BUSY; 02503 } else { 02504 if (res == AST_DEVICE_BUSY) 02505 res = AST_DEVICE_INUSE; 02506 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02507 if (res == AST_DEVICE_INVALID) 02508 res = AST_DEVICE_UNKNOWN; 02509 } else if (res == AST_DEVICE_INVALID) 02510 res = AST_DEVICE_UNAVAILABLE; 02511 } 02512 if (!strcmp(data, p->agent)) { 02513 ast_mutex_unlock(&p->lock); 02514 break; 02515 } 02516 } 02517 ast_mutex_unlock(&p->lock); 02518 } 02519 AST_LIST_UNLOCK(&agents); 02520 return res; 02521 }
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_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 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 1521 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().
01522 { 01523 struct agent_pvt *p; 01524 long logintime; 01525 int ret = -1; /* Return -1 if no agent if found */ 01526 01527 AST_LIST_TRAVERSE(&agents, p, list) { 01528 if (!strcasecmp(p->agent, agent)) { 01529 ret = 0; 01530 if (p->owner || p->chan) { 01531 if (!soft) { 01532 if (p->owner) 01533 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01534 if (p->chan) 01535 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01536 } else 01537 p->deferlogoff = 1; 01538 } else { 01539 logintime = time(NULL) - p->loginstart; 01540 p->loginstart = 0; 01541 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01542 } 01543 break; 01544 } 01545 } 01546 01547 return ret; 01548 }
static int agent_logoff_cmd | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1550 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.
01551 { 01552 int ret; 01553 char *agent; 01554 01555 if (argc < 3 || argc > 4) 01556 return RESULT_SHOWUSAGE; 01557 if (argc == 4 && strcasecmp(argv[3], "soft")) 01558 return RESULT_SHOWUSAGE; 01559 01560 agent = argv[2] + 6; 01561 ret = agent_logoff(agent, argc == 4); 01562 if (ret == 0) 01563 ast_cli(fd, "Logging out %s\n", agent); 01564 01565 return RESULT_SUCCESS; 01566 }
static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
char * | loginchan, | |||
long | logintime, | |||
const char * | uniqueid, | |||
char * | logcommand | |||
) | [static] |
Definition at line 1482 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().
01483 { 01484 char *tmp = NULL; 01485 char agent[AST_MAX_AGENT]; 01486 01487 if (!ast_strlen_zero(logcommand)) 01488 tmp = logcommand; 01489 else 01490 tmp = ast_strdupa(""); 01491 01492 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01493 01494 if (!ast_strlen_zero(uniqueid)) { 01495 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01496 "Agent: %s\r\n" 01497 "Reason: %s\r\n" 01498 "Loginchan: %s\r\n" 01499 "Logintime: %ld\r\n" 01500 "Uniqueid: %s\r\n", 01501 p->agent, tmp, loginchan, logintime, uniqueid); 01502 } else { 01503 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01504 "Agent: %s\r\n" 01505 "Reason: %s\r\n" 01506 "Loginchan: %s\r\n" 01507 "Logintime: %ld\r\n", 01508 p->agent, tmp, loginchan, logintime); 01509 } 01510 01511 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01512 set_agentbycallerid(p->logincallerid, NULL); 01513 p->loginchan[0] ='\0'; 01514 p->logincallerid[0] = '\0'; 01515 ast_device_state_changed("Agent/%s", p->agent); 01516 if (persistent_agents) 01517 dump_agents(); 01518 01519 }
static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
int | state | |||
) | [static, read] |
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 if (p->chan) 00997 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 00998 p->owning_app = pthread_self(); 00999 /* After the above step, there should not be any blockers. */ 01000 if (p->chan) { 01001 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) { 01002 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" ); 01003 CRASH; 01004 } 01005 } 01006 return tmp; 01007 }
static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static, read] |
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, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_verbose, pbx_builtin_getvar_helper(), ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.
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, read] |
Part of the Asterisk PBX interface.
Definition at line 1298 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.
01299 { 01300 struct agent_pvt *p; 01301 struct ast_channel *chan = NULL; 01302 char *s; 01303 ast_group_t groupmatch; 01304 int groupoff; 01305 int waitforagent=0; 01306 int hasagent = 0; 01307 struct timeval tv; 01308 01309 s = data; 01310 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01311 groupmatch = (1 << groupoff); 01312 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01313 groupmatch = (1 << groupoff); 01314 waitforagent = 1; 01315 } else 01316 groupmatch = 0; 01317 01318 /* Check actual logged in agents first */ 01319 AST_LIST_LOCK(&agents); 01320 AST_LIST_TRAVERSE(&agents, p, list) { 01321 ast_mutex_lock(&p->lock); 01322 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01323 ast_strlen_zero(p->loginchan)) { 01324 if (p->chan) 01325 hasagent++; 01326 tv = ast_tvnow(); 01327 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01328 p->lastdisc = ast_tv(0, 0); 01329 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01330 if (!p->owner && p->chan) { 01331 /* Fixed agent */ 01332 chan = agent_new(p, AST_STATE_DOWN); 01333 } 01334 if (chan) { 01335 ast_mutex_unlock(&p->lock); 01336 break; 01337 } 01338 } 01339 } 01340 ast_mutex_unlock(&p->lock); 01341 } 01342 if (!p) { 01343 AST_LIST_TRAVERSE(&agents, p, list) { 01344 ast_mutex_lock(&p->lock); 01345 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01346 if (p->chan || !ast_strlen_zero(p->loginchan)) 01347 hasagent++; 01348 tv = ast_tvnow(); 01349 #if 0 01350 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec); 01351 #endif 01352 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) { 01353 p->lastdisc = ast_tv(0, 0); 01354 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01355 if (!p->owner && p->chan) { 01356 /* Could still get a fixed agent */ 01357 chan = agent_new(p, AST_STATE_DOWN); 01358 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01359 /* Adjustable agent */ 01360 p->chan = ast_request("Local", format, p->loginchan, cause); 01361 if (p->chan) 01362 chan = agent_new(p, AST_STATE_DOWN); 01363 } 01364 if (chan) { 01365 ast_mutex_unlock(&p->lock); 01366 break; 01367 } 01368 } 01369 } 01370 ast_mutex_unlock(&p->lock); 01371 } 01372 } 01373 01374 if (!chan && waitforagent) { 01375 /* No agent available -- but we're requesting to wait for one. 01376 Allocate a place holder */ 01377 if (hasagent) { 01378 if (option_debug) 01379 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); 01380 p = add_agent(data, 1); 01381 p->group = groupmatch; 01382 chan = agent_new(p, AST_STATE_DOWN); 01383 if (!chan) 01384 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01385 } else 01386 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); 01387 } 01388 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01389 AST_LIST_UNLOCK(&agents); 01390 return chan; 01391 }
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, ast_frame::frametype, agent_pvt::lock, LOG_DEBUG, ast_frame::subclass, 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 2341 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_verbose(), ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), ast_channel::priority, and VERBOSE_PREFIX_3.
Referenced by load_module().
02342 { 02343 int exitifnoagentid = 0; 02344 int nowarnings = 0; 02345 int changeoutgoing = 0; 02346 int res = 0; 02347 char agent[AST_MAX_AGENT]; 02348 02349 if (data) { 02350 if (strchr(data, 'd')) 02351 exitifnoagentid = 1; 02352 if (strchr(data, 'n')) 02353 nowarnings = 1; 02354 if (strchr(data, 'c')) 02355 changeoutgoing = 1; 02356 } 02357 if (chan->cid.cid_num) { 02358 const char *tmp; 02359 char agentvar[AST_MAX_BUF]; 02360 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02361 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02362 struct agent_pvt *p; 02363 ast_copy_string(agent, tmp, sizeof(agent)); 02364 AST_LIST_LOCK(&agents); 02365 AST_LIST_TRAVERSE(&agents, p, list) { 02366 if (!strcasecmp(p->agent, tmp)) { 02367 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02368 __agent_start_monitoring(chan, p, 1); 02369 break; 02370 } 02371 } 02372 AST_LIST_UNLOCK(&agents); 02373 02374 } else { 02375 res = -1; 02376 if (!nowarnings) 02377 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); 02378 } 02379 } else { 02380 res = -1; 02381 if (!nowarnings) 02382 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"); 02383 } 02384 /* check if there is n + 101 priority */ 02385 /*! \todo XXX Needs to check option priorityjump etc etc */ 02386 if (res) { 02387 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) { 02388 chan->priority+=100; 02389 if (option_verbose > 2) 02390 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); 02391 } else if (exitifnoagentid) 02392 return res; 02393 } 02394 return 0; 02395 }
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 1619 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.
01620 { 01621 struct agent_pvt *p; 01622 char username[AST_MAX_BUF]; 01623 char location[AST_MAX_BUF] = ""; 01624 char talkingto[AST_MAX_BUF] = ""; 01625 char moh[AST_MAX_BUF]; 01626 int count_agents = 0; /*!< Number of agents configured */ 01627 int online_agents = 0; /*!< Number of online agents */ 01628 int offline_agents = 0; /*!< Number of offline agents */ 01629 if (argc != 2) 01630 return RESULT_SHOWUSAGE; 01631 AST_LIST_LOCK(&agents); 01632 AST_LIST_TRAVERSE(&agents, p, list) { 01633 ast_mutex_lock(&p->lock); 01634 if (p->pending) { 01635 if (p->group) 01636 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group)); 01637 else 01638 ast_cli(fd, "-- Pending call to agent %s\n", p->agent); 01639 } else { 01640 if (!ast_strlen_zero(p->name)) 01641 snprintf(username, sizeof(username), "(%s) ", p->name); 01642 else 01643 username[0] = '\0'; 01644 if (p->chan) { 01645 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01646 if (p->owner && ast_bridged_channel(p->owner)) 01647 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01648 else 01649 strcpy(talkingto, " is idle"); 01650 online_agents++; 01651 } else if (!ast_strlen_zero(p->loginchan)) { 01652 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01653 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01654 else 01655 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01656 talkingto[0] = '\0'; 01657 online_agents++; 01658 if (p->acknowledged) 01659 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01660 } else { 01661 strcpy(location, "not logged in"); 01662 talkingto[0] = '\0'; 01663 offline_agents++; 01664 } 01665 if (!ast_strlen_zero(p->moh)) 01666 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01667 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 01668 username, location, talkingto, moh); 01669 count_agents++; 01670 } 01671 ast_mutex_unlock(&p->lock); 01672 } 01673 AST_LIST_UNLOCK(&agents); 01674 if ( !count_agents ) 01675 ast_cli(fd, "No Agents are configured in %s\n",config); 01676 else 01677 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01678 ast_cli(fd, "\n"); 01679 01680 return RESULT_SUCCESS; 01681 }
static int agents_show_online | ( | int | fd, | |
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 1684 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.
01685 { 01686 struct agent_pvt *p; 01687 char username[AST_MAX_BUF]; 01688 char location[AST_MAX_BUF] = ""; 01689 char talkingto[AST_MAX_BUF] = ""; 01690 char moh[AST_MAX_BUF]; 01691 int count_agents = 0; /* Number of agents configured */ 01692 int online_agents = 0; /* Number of online agents */ 01693 int agent_status = 0; /* 0 means offline, 1 means online */ 01694 if (argc != 3) 01695 return RESULT_SHOWUSAGE; 01696 AST_LIST_LOCK(&agents); 01697 AST_LIST_TRAVERSE(&agents, p, list) { 01698 agent_status = 0; /* reset it to offline */ 01699 ast_mutex_lock(&p->lock); 01700 if (!ast_strlen_zero(p->name)) 01701 snprintf(username, sizeof(username), "(%s) ", p->name); 01702 else 01703 username[0] = '\0'; 01704 if (p->chan) { 01705 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01706 if (p->owner && ast_bridged_channel(p->owner)) 01707 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01708 else 01709 strcpy(talkingto, " is idle"); 01710 agent_status = 1; 01711 online_agents++; 01712 } else if (!ast_strlen_zero(p->loginchan)) { 01713 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01714 talkingto[0] = '\0'; 01715 agent_status = 1; 01716 online_agents++; 01717 if (p->acknowledged) 01718 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01719 } 01720 if (!ast_strlen_zero(p->moh)) 01721 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01722 if (agent_status) 01723 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh); 01724 count_agents++; 01725 ast_mutex_unlock(&p->lock); 01726 } 01727 AST_LIST_UNLOCK(&agents); 01728 if (!count_agents) 01729 ast_cli(fd, "No Agents are configured in %s\n", config); 01730 else 01731 ast_cli(fd, "%d agents online\n", online_agents); 01732 ast_cli(fd, "\n"); 01733 return RESULT_SUCCESS; 01734 }
static int allow_multiple_login | ( | char * | chan, | |
char * | context | |||
) | [static] |
Definition at line 1278 of file chan_agent.c.
References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.
Referenced by __login_exec().
01279 { 01280 struct agent_pvt *p; 01281 char loginchan[80]; 01282 01283 if(multiplelogin) 01284 return 1; 01285 if(!chan) 01286 return 0; 01287 01288 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); 01289 01290 AST_LIST_TRAVERSE(&agents, p, list) { 01291 if(!strcasecmp(chan, p->loginchan)) 01292 return 0; 01293 } 01294 return -1; 01295 }
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 2222 of file chan_agent.c.
References ast_log(), depwarning, and LOG_WARNING.
Referenced by action_agent_callback_login(), and callback_exec().
02223 { 02224 static int depwarning = 0; 02225 02226 if (!depwarning) { 02227 depwarning = 1; 02228 02229 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n"); 02230 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n"); 02231 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n"); 02232 } 02233 }
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 2243 of file chan_agent.c.
References __login_exec(), and callback_deprecated().
Referenced by load_module().
02244 { 02245 callback_deprecated(); 02246 02247 return __login_exec(chan, data, 1); 02248 }
static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1164 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().
01165 { 01166 struct ast_channel *chan=NULL, *parent=NULL; 01167 struct agent_pvt *p; 01168 int res; 01169 01170 if (option_debug) 01171 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); 01172 if (needlock) 01173 AST_LIST_LOCK(&agents); 01174 AST_LIST_TRAVERSE(&agents, p, list) { 01175 if (p == newlyavailable) { 01176 continue; 01177 } 01178 ast_mutex_lock(&p->lock); 01179 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01180 if (option_debug) 01181 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01182 /* We found a pending call, time to merge */ 01183 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01184 parent = p->owner; 01185 p->abouttograb = 1; 01186 ast_mutex_unlock(&p->lock); 01187 break; 01188 } 01189 ast_mutex_unlock(&p->lock); 01190 } 01191 if (needlock) 01192 AST_LIST_UNLOCK(&agents); 01193 if (parent && chan) { 01194 if (newlyavailable->ackcall > 1) { 01195 /* Don't do beep here */ 01196 res = 0; 01197 } else { 01198 if (option_debug > 2) 01199 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01200 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01201 if (option_debug > 2) 01202 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01203 if (!res) { 01204 res = ast_waitstream(newlyavailable->chan, ""); 01205 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01206 } 01207 } 01208 if (!res) { 01209 /* Note -- parent may have disappeared */ 01210 if (p->abouttograb) { 01211 newlyavailable->acknowledged = 1; 01212 /* Safe -- agent lock already held */ 01213 ast_setstate(parent, AST_STATE_UP); 01214 ast_setstate(chan, AST_STATE_UP); 01215 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01216 /* Go ahead and mark the channel as a zombie so that masquerade will 01217 destroy it for us, and we need not call ast_hangup */ 01218 ast_mutex_lock(&parent->lock); 01219 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01220 ast_channel_masquerade(parent, chan); 01221 ast_mutex_unlock(&parent->lock); 01222 p->abouttograb = 0; 01223 } else { 01224 if (option_debug) 01225 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); 01226 agent_cleanup(newlyavailable); 01227 } 01228 } else { 01229 if (option_debug) 01230 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); 01231 agent_cleanup(newlyavailable); 01232 } 01233 } 01234 return 0; 01235 }
static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
int | needlock | |||
) | [static] |
Definition at line 1237 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().
01238 { 01239 struct agent_pvt *p; 01240 int res=0; 01241 01242 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); 01243 if (needlock) 01244 AST_LIST_LOCK(&agents); 01245 AST_LIST_TRAVERSE(&agents, p, list) { 01246 if (p == newlyavailable) { 01247 continue; 01248 } 01249 ast_mutex_lock(&p->lock); 01250 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01251 if (option_debug) 01252 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01253 ast_mutex_unlock(&p->lock); 01254 break; 01255 } 01256 ast_mutex_unlock(&p->lock); 01257 } 01258 if (needlock) 01259 AST_LIST_UNLOCK(&agents); 01260 if (p) { 01261 ast_mutex_unlock(&newlyavailable->lock); 01262 if (option_debug > 2) 01263 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01264 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01265 if (option_debug > 2) 01266 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res); 01267 if (!res) { 01268 res = ast_waitstream(newlyavailable->chan, ""); 01269 if (option_debug) 01270 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01271 } 01272 ast_mutex_lock(&newlyavailable->lock); 01273 } 01274 return res; 01275 }
static char* complete_agent_logoff_cmd | ( | const char * | line, | |
const char * | word, | |||
int | pos, | |||
int | state | |||
) | [static] |
Definition at line 1598 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_TRAVERSE, AST_MAX_AGENT, ast_strdup, len, and agent_pvt::name.
01599 { 01600 if (pos == 2) { 01601 struct agent_pvt *p; 01602 char name[AST_MAX_AGENT]; 01603 int which = 0, len = strlen(word); 01604 01605 AST_LIST_TRAVERSE(&agents, p, list) { 01606 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01607 if (!strncasecmp(word, name, len) && ++which > state) 01608 return ast_strdup(name); 01609 } 01610 } else if (pos == 3 && state == 0) 01611 return ast_strdup("soft"); 01612 01613 return NULL; 01614 }
static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2400 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().
02401 { 02402 struct agent_pvt *cur_agent = NULL; 02403 char buf[256]; 02404 02405 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02406 if (cur_agent->chan) 02407 continue; 02408 02409 if (!ast_strlen_zero(cur_agent->loginchan)) { 02410 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02411 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02412 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02413 else if (option_debug) 02414 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02415 } else { 02416 /* Delete - no agent or there is an error */ 02417 ast_db_del(pa_family, cur_agent->agent); 02418 } 02419 } 02420 }
static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static, read] |
Definition at line 2523 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02524 { 02525 struct agent_pvt *cur; 02526 02527 AST_LIST_TRAVERSE(&agents, cur, list) { 02528 if (!strcmp(cur->agent, agentid)) 02529 break; 02530 } 02531 02532 return cur; 02533 }
static int function_agent | ( | struct ast_channel * | chan, | |
char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 2535 of file chan_agent.c.
References agent_pvt::agent, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::chan, find_agent(), LOG_WARNING, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, parse(), and agent_pvt::password.
02536 { 02537 char *parse; 02538 AST_DECLARE_APP_ARGS(args, 02539 AST_APP_ARG(agentid); 02540 AST_APP_ARG(item); 02541 ); 02542 char *tmp; 02543 struct agent_pvt *agent; 02544 02545 buf[0] = '\0'; 02546 02547 if (ast_strlen_zero(data)) { 02548 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02549 return -1; 02550 } 02551 02552 parse = ast_strdupa(data); 02553 02554 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02555 if (!args.item) 02556 args.item = "status"; 02557 02558 if (!(agent = find_agent(args.agentid))) { 02559 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02560 return -1; 02561 } 02562 02563 if (!strcasecmp(args.item, "status")) { 02564 char *status = "LOGGEDOUT"; 02565 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02566 status = "LOGGEDIN"; 02567 ast_copy_string(buf, status, len); 02568 } else if (!strcasecmp(args.item, "password")) 02569 ast_copy_string(buf, agent->password, len); 02570 else if (!strcasecmp(args.item, "name")) 02571 ast_copy_string(buf, agent->name, len); 02572 else if (!strcasecmp(args.item, "mohclass")) 02573 ast_copy_string(buf, agent->moh, len); 02574 else if (!strcasecmp(args.item, "channel")) { 02575 if (agent->chan) { 02576 ast_copy_string(buf, agent->chan->name, len); 02577 tmp = strrchr(buf, '-'); 02578 if (tmp) 02579 *tmp = '\0'; 02580 } 02581 } else if (!strcasecmp(args.item, "exten")) 02582 ast_copy_string(buf, agent->loginchan, len); 02583 02584 return 0; 02585 }
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 2610 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().
02611 { 02612 /* Make sure we can register our agent channel type */ 02613 if (ast_channel_register(&agent_tech)) { 02614 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02615 return -1; 02616 } 02617 /* Read in the config */ 02618 if (!read_agent_config()) 02619 return AST_MODULE_LOAD_DECLINE; 02620 if (persistent_agents) 02621 reload_agents(); 02622 /* Dialplan applications */ 02623 ast_register_application(app, login_exec, synopsis, descrip); 02624 ast_register_application(app2, callback_exec, synopsis2, descrip2); 02625 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02626 02627 /* Manager commands */ 02628 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02629 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02630 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login); 02631 02632 /* CLI Commands */ 02633 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02634 02635 /* Dialplan Functions */ 02636 ast_custom_function_register(&agent_function); 02637 02638 return 0; 02639 }
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 2217 of file chan_agent.c.
References __login_exec().
Referenced by load_module().
02218 { 02219 return __login_exec(chan, data, 0); 02220 }
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 1015 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().
01016 { 01017 struct ast_config *cfg; 01018 struct ast_config *ucfg; 01019 struct ast_variable *v; 01020 struct agent_pvt *p; 01021 const char *general_val; 01022 const char *catname; 01023 const char *hasagent; 01024 int genhasagent; 01025 01026 group = 0; 01027 autologoff = 0; 01028 wrapuptime = 0; 01029 ackcall = 0; 01030 endcall = 1; 01031 cfg = ast_config_load(config); 01032 if (!cfg) { 01033 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01034 return 0; 01035 } 01036 AST_LIST_LOCK(&agents); 01037 AST_LIST_TRAVERSE(&agents, p, list) { 01038 p->dead = 1; 01039 } 01040 strcpy(moh, "default"); 01041 /* set the default recording values */ 01042 recordagentcalls = 0; 01043 strcpy(recordformat, "wav"); 01044 strcpy(recordformatext, "wav"); 01045 urlprefix[0] = '\0'; 01046 savecallsin[0] = '\0'; 01047 01048 /* Read in [general] section for persistence */ 01049 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01050 persistent_agents = ast_true(general_val); 01051 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01052 01053 /* Read in the [agents] section */ 01054 v = ast_variable_browse(cfg, "agents"); 01055 while(v) { 01056 /* Create the interface list */ 01057 if (!strcasecmp(v->name, "agent")) { 01058 add_agent(v->value, 0); 01059 } else if (!strcasecmp(v->name, "group")) { 01060 group = ast_get_group(v->value); 01061 } else if (!strcasecmp(v->name, "autologoff")) { 01062 autologoff = atoi(v->value); 01063 if (autologoff < 0) 01064 autologoff = 0; 01065 } else if (!strcasecmp(v->name, "ackcall")) { 01066 if (!strcasecmp(v->value, "always")) 01067 ackcall = 2; 01068 else if (ast_true(v->value)) 01069 ackcall = 1; 01070 else 01071 ackcall = 0; 01072 } else if (!strcasecmp(v->name, "endcall")) { 01073 endcall = ast_true(v->value); 01074 } else if (!strcasecmp(v->name, "wrapuptime")) { 01075 wrapuptime = atoi(v->value); 01076 if (wrapuptime < 0) 01077 wrapuptime = 0; 01078 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01079 maxlogintries = atoi(v->value); 01080 if (maxlogintries < 0) 01081 maxlogintries = 0; 01082 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01083 strcpy(agentgoodbye,v->value); 01084 } else if (!strcasecmp(v->name, "musiconhold")) { 01085 ast_copy_string(moh, v->value, sizeof(moh)); 01086 } else if (!strcasecmp(v->name, "updatecdr")) { 01087 if (ast_true(v->value)) 01088 updatecdr = 1; 01089 else 01090 updatecdr = 0; 01091 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01092 if (ast_true(v->value)) 01093 autologoffunavail = 1; 01094 else 01095 autologoffunavail = 0; 01096 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01097 recordagentcalls = ast_true(v->value); 01098 } else if (!strcasecmp(v->name, "recordformat")) { 01099 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01100 if (!strcasecmp(v->value, "wav49")) 01101 strcpy(recordformatext, "WAV"); 01102 else 01103 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01104 } else if (!strcasecmp(v->name, "urlprefix")) { 01105 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01106 if (urlprefix[strlen(urlprefix) - 1] != '/') 01107 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01108 } else if (!strcasecmp(v->name, "savecallsin")) { 01109 if (v->value[0] == '/') 01110 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01111 else 01112 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01113 if (savecallsin[strlen(savecallsin) - 1] != '/') 01114 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01115 } else if (!strcasecmp(v->name, "custom_beep")) { 01116 ast_copy_string(beep, v->value, sizeof(beep)); 01117 } 01118 v = v->next; 01119 } 01120 if ((ucfg = ast_config_load("users.conf"))) { 01121 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01122 catname = ast_category_browse(ucfg, NULL); 01123 while(catname) { 01124 if (strcasecmp(catname, "general")) { 01125 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01126 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01127 char tmp[256]; 01128 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01129 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01130 if (!fullname) 01131 fullname = ""; 01132 if (!secret) 01133 secret = ""; 01134 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01135 add_agent(tmp, 0); 01136 } 01137 } 01138 catname = ast_category_browse(ucfg, catname); 01139 } 01140 ast_config_destroy(ucfg); 01141 } 01142 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01143 if (p->dead) { 01144 AST_LIST_REMOVE_CURRENT(&agents, list); 01145 /* Destroy if appropriate */ 01146 if (!p->owner) { 01147 if (!p->chan) { 01148 ast_mutex_destroy(&p->lock); 01149 ast_mutex_destroy(&p->app_lock); 01150 free(p); 01151 } else { 01152 /* Cause them to hang up */ 01153 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01154 } 01155 } 01156 } 01157 } 01158 AST_LIST_TRAVERSE_SAFE_END 01159 AST_LIST_UNLOCK(&agents); 01160 ast_config_destroy(cfg); 01161 return 1; 01162 }
static int reload | ( | void | ) | [static] |
Definition at line 2641 of file chan_agent.c.
References read_agent_config(), and reload_agents().
Referenced by reload(), and rpt_do_reload().
02642 { 02643 read_agent_config(); 02644 if (persistent_agents) 02645 reload_agents(); 02646 return 0; 02647 }
static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2425 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().
02426 { 02427 char *agent_num; 02428 struct ast_db_entry *db_tree; 02429 struct ast_db_entry *entry; 02430 struct agent_pvt *cur_agent; 02431 char agent_data[256]; 02432 char *parse; 02433 char *agent_chan; 02434 char *agent_callerid; 02435 02436 db_tree = ast_db_gettree(pa_family, NULL); 02437 02438 AST_LIST_LOCK(&agents); 02439 for (entry = db_tree; entry; entry = entry->next) { 02440 agent_num = entry->key + strlen(pa_family) + 2; 02441 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02442 ast_mutex_lock(&cur_agent->lock); 02443 if (strcmp(agent_num, cur_agent->agent) == 0) 02444 break; 02445 ast_mutex_unlock(&cur_agent->lock); 02446 } 02447 if (!cur_agent) { 02448 ast_db_del(pa_family, agent_num); 02449 continue; 02450 } else 02451 ast_mutex_unlock(&cur_agent->lock); 02452 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02453 if (option_debug) 02454 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02455 parse = agent_data; 02456 agent_chan = strsep(&parse, ";"); 02457 agent_callerid = strsep(&parse, ";"); 02458 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02459 if (agent_callerid) { 02460 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02461 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02462 } else 02463 cur_agent->logincallerid[0] = '\0'; 02464 if (cur_agent->loginstart == 0) 02465 time(&cur_agent->loginstart); 02466 ast_device_state_changed("Agent/%s", cur_agent->agent); 02467 } 02468 } 02469 AST_LIST_UNLOCK(&agents); 02470 if (db_tree) { 02471 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02472 ast_db_freetree(db_tree); 02473 } 02474 }
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 2649 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().
02650 { 02651 struct agent_pvt *p; 02652 /* First, take us out of the channel loop */ 02653 ast_channel_unregister(&agent_tech); 02654 /* Unregister dialplan functions */ 02655 ast_custom_function_unregister(&agent_function); 02656 /* Unregister CLI commands */ 02657 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02658 /* Unregister dialplan applications */ 02659 ast_unregister_application(app); 02660 ast_unregister_application(app2); 02661 ast_unregister_application(app3); 02662 /* Unregister manager command */ 02663 ast_manager_unregister("Agents"); 02664 ast_manager_unregister("AgentLogoff"); 02665 ast_manager_unregister("AgentCallbackLogin"); 02666 /* Unregister channel */ 02667 AST_LIST_LOCK(&agents); 02668 /* Hangup all interfaces if they have an owner */ 02669 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02670 if (p->owner) 02671 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02672 free(p); 02673 } 02674 AST_LIST_UNLOCK(&agents); 02675 AST_LIST_HEAD_DESTROY(&agents); 02676 return 0; 02677 }
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 1746 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(), answer_exec_enable(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_context_add_extension(), handle_context_add_extension_deprecated(), load_config(), load_module(), page_exec(), pbx_extension_helper(), realtime_exec(), tryexec_exec(), and unload_module().
const char app2[] = "AgentCallbackLogin" [static] |
Definition at line 80 of file chan_agent.c.
Referenced by _macro_exec(), load_module(), and unload_module().
const char app3[] = "AgentMonitorOutgoing" [static] |
int autologoff [static] |
Definition at line 154 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 159 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 170 of file chan_agent.c.
struct ast_cli_entry cli_agents[] [static] |
struct ast_cli_entry cli_show_agents_deprecated [static] |
Initial value:
{ { "show", "agents", NULL }, agents_show, NULL, NULL, NULL }
Definition at line 1751 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 1756 of file chan_agent.c.
const char config[] = "agents.conf" [static] |
Definition at line 77 of file chan_agent.c.
Referenced by ast_config_new(), ast_readconfig(), do_reload(), load_module(), load_odbc_config(), misdn_cfg_init(), parse_config(), read_config_maps(), reload(), and reload_config().
const char descrip[] [static] |
const char descrip2[] [static] |
Definition at line 96 of file chan_agent.c.
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_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 1742 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 1738 of file chan_agent.c.
Definition at line 84 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.