![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chan_agent.c File Reference
Definition in file chan_agent.c.
#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
Include dependency graph for chan_agent.c:

Go to the source code of this file.
Data Structures | |
| struct | agent_pvt |
| Structure representing an agent. More... | |
Defines | |
| #define | AST_MAX_AGENT 80 |
| #define | AST_MAX_BUF 256 |
| #define | AST_MAX_FILENAME_LEN 256 |
| #define | CHECK_FORMATS(ast, p) |
| #define | CLEANUP(ast, p) |
| Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
| #define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
| #define | PA_MAX_LEN 2048 |
Functions | |
| static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
| static int | __login_exec (struct ast_channel *chan, void *data, int callbackmode) |
| Log in agent application. | |
| static int | action_agent_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 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, const char *cmd, char *data, char *buf, size_t len) |
| static int | load_module (void) |
| Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file. | |
| static int | login_exec (struct ast_channel *chan, void *data) |
| static force_inline int | powerof (unsigned int d) |
| static int | read_agent_config (void) |
| static int | reload (void) |
| static void | reload_agents (void) |
| Reload the persistent agents from astdb. | |
| static void | set_agentbycallerid (const char *callerid, const char *agent) |
| store/clear the global variable that stores agentid based on the callerid | |
| static int | unload_module (void) |
Variables | |
| static int | ackcall |
| ast_custom_function | agent_function |
| static const char | agent_logoff_usage [] |
| static const 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 | app3 [] = "AgentMonitorOutgoing" |
| static int | autologoff |
| static int | autologoffunavail = 0 |
| static char | beep [AST_MAX_BUF] = "beep" |
| static struct ast_cli_entry | cli_agents [] |
| static const char | config [] = "agents.conf" |
| static const char | descrip [] |
| 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 const char | show_agents_online_usage [] |
| static const char | show_agents_usage [] |
| static const char | synopsis [] = "Call agent 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 |
|
|
Agent ID or Password max length Definition at line 133 of file chan_agent.c. Referenced by __login_exec(), agent_logoff_maintenance(), agentmonitoroutgoing_exec(), and complete_agent_logoff_cmd(). |
|
|
Definition at line 134 of file chan_agent.c. Referenced by __agent_start_monitoring(), __login_exec(), agentmonitoroutgoing_exec(), agents_show(), agents_show_online(), and set_agentbycallerid(). |
|
|
Definition at line 135 of file chan_agent.c. Referenced by __login_exec(). |
|
|
Definition at line 194 of file chan_agent.c. Referenced by agent_read(), and agent_write(). |
|
|
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 217 of file chan_agent.c. Referenced by agent_call(), agent_read(), and agent_write(). |
|
|
Definition at line 162 of file chan_agent.c. Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid(). |
|
|
The maximum length of each persistent member agent database entry Definition at line 138 of file chan_agent.c. |
|
||||||||||||||||
|
Definition at line 393 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(). 00394 { 00395 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00396 char filename[AST_MAX_BUF]; 00397 int res = -1; 00398 if (!p) 00399 return -1; 00400 if (!ast->monitor) { 00401 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00402 /* substitute . for - */ 00403 if ((pointer = strchr(filename, '.'))) 00404 *pointer = '-'; 00405 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename); 00406 ast_monitor_start(ast, recordformat, tmp, needlock); 00407 ast_monitor_setjoinfiles(ast, 1); 00408 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext); 00409 #if 0 00410 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00411 #endif 00412 if (!ast->cdr) 00413 ast->cdr = ast_cdr_alloc(); 00414 ast_cdr_setuserfield(ast, tmp2); 00415 res = 0; 00416 } else 00417 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00418 return res; 00419 }
|
|
||||||||||||||||
|
Log in agent application.
Definition at line 1749 of file chan_agent.c. References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_module_user::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, context, agent_pvt::dead, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event, agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime. Referenced by login_exec(). 01750 { 01751 int res=0; 01752 int tries = 0; 01753 int max_login_tries = maxlogintries; 01754 struct agent_pvt *p; 01755 struct ast_module_user *u; 01756 int login_state = 0; 01757 char user[AST_MAX_AGENT] = ""; 01758 char pass[AST_MAX_AGENT]; 01759 char agent[AST_MAX_AGENT] = ""; 01760 char xpass[AST_MAX_AGENT] = ""; 01761 char *errmsg; 01762 char *parse; 01763 AST_DECLARE_APP_ARGS(args, 01764 AST_APP_ARG(agent_id); 01765 AST_APP_ARG(options); 01766 AST_APP_ARG(extension); 01767 ); 01768 const char *tmpoptions = NULL; 01769 char *context = NULL; 01770 int play_announcement = 1; 01771 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01772 int update_cdr = updatecdr; 01773 char *filename = "agent-loginok"; 01774 char tmpchan[AST_MAX_BUF] = ""; 01775 01776 u = ast_module_user_add(chan); 01777 01778 parse = ast_strdupa(data); 01779 01780 AST_STANDARD_APP_ARGS(args, parse); 01781 01782 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01783 01784 /* Set Channel Specific Login Overrides */ 01785 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01786 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01787 if (max_login_tries < 0) 01788 max_login_tries = 0; 01789 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01790 if (option_verbose > 2) 01791 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); 01792 } 01793 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01794 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01795 update_cdr = 1; 01796 else 01797 update_cdr = 0; 01798 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01799 if (option_verbose > 2) 01800 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01801 } 01802 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01803 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01804 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01805 if (option_verbose > 2) 01806 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01807 } 01808 /* End Channel Specific Login Overrides */ 01809 01810 if (callbackmode && args.extension) { 01811 parse = args.extension; 01812 args.extension = strsep(&parse, "@"); 01813 context = parse; 01814 } 01815 01816 if (!ast_strlen_zero(args.options)) { 01817 if (strchr(args.options, 's')) { 01818 play_announcement = 0; 01819 } 01820 } 01821 01822 if (chan->_state != AST_STATE_UP) 01823 res = ast_answer(chan); 01824 if (!res) { 01825 if (!ast_strlen_zero(args.agent_id)) 01826 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01827 else 01828 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01829 } 01830 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01831 tries++; 01832 /* Check for password */ 01833 AST_LIST_LOCK(&agents); 01834 AST_LIST_TRAVERSE(&agents, p, list) { 01835 if (!strcmp(p->agent, user) && !p->pending) 01836 ast_copy_string(xpass, p->password, sizeof(xpass)); 01837 } 01838 AST_LIST_UNLOCK(&agents); 01839 if (!res) { 01840 if (!ast_strlen_zero(xpass)) 01841 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01842 else 01843 pass[0] = '\0'; 01844 } 01845 errmsg = "agent-incorrect"; 01846 01847 #if 0 01848 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01849 #endif 01850 01851 /* Check again for accuracy */ 01852 AST_LIST_LOCK(&agents); 01853 AST_LIST_TRAVERSE(&agents, p, list) { 01854 ast_mutex_lock(&p->lock); 01855 if (!strcmp(p->agent, user) && 01856 !strcmp(p->password, pass) && !p->pending) { 01857 login_state = 1; /* Successful Login */ 01858 01859 /* Ensure we can't be gotten until we're done */ 01860 gettimeofday(&p->lastdisc, NULL); 01861 p->lastdisc.tv_sec++; 01862 01863 /* Set Channel Specific Agent Overrides */ 01864 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01865 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 01866 p->ackcall = 2; 01867 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 01868 p->ackcall = 1; 01869 else 01870 p->ackcall = 0; 01871 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01872 if (option_verbose > 2) 01873 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent); 01874 } 01875 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01876 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01877 if (p->autologoff < 0) 01878 p->autologoff = 0; 01879 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 01880 if (option_verbose > 2) 01881 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent); 01882 } 01883 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 01884 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 01885 if (p->wrapuptime < 0) 01886 p->wrapuptime = 0; 01887 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 01888 if (option_verbose > 2) 01889 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent); 01890 } 01891 /* End Channel Specific Agent Overrides */ 01892 if (!p->chan) { 01893 char last_loginchan[80] = ""; 01894 long logintime; 01895 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01896 01897 if (callbackmode) { 01898 int pos = 0; 01899 /* Retrieve login chan */ 01900 for (;;) { 01901 if (!ast_strlen_zero(args.extension)) { 01902 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan)); 01903 res = 0; 01904 } else 01905 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0); 01906 if (ast_strlen_zero(tmpchan) ) 01907 break; 01908 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) { 01909 if(!allow_multiple_login(tmpchan,context) ) { 01910 args.extension = NULL; 01911 pos = 0; 01912 } else 01913 break; 01914 } 01915 if (args.extension) { 01916 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent); 01917 args.extension = NULL; 01918 pos = 0; 01919 } else { 01920 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent); 01921 res = ast_streamfile(chan, "invalid", chan->language); 01922 if (!res) 01923 res = ast_waitstream(chan, AST_DIGIT_ANY); 01924 if (res > 0) { 01925 tmpchan[0] = res; 01926 tmpchan[1] = '\0'; 01927 pos = 1; 01928 } else { 01929 tmpchan[0] = '\0'; 01930 pos = 0; 01931 } 01932 } 01933 } 01934 args.extension = tmpchan; 01935 if (!res) { 01936 set_agentbycallerid(p->logincallerid, NULL); 01937 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan)) 01938 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context); 01939 else { 01940 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan)); 01941 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan)); 01942 } 01943 p->acknowledged = 0; 01944 if (ast_strlen_zero(p->loginchan)) { 01945 login_state = 2; 01946 filename = "agent-loggedoff"; 01947 } else { 01948 if (chan->cid.cid_num) { 01949 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid)); 01950 set_agentbycallerid(p->logincallerid, p->agent); 01951 } else 01952 p->logincallerid[0] = '\0'; 01953 } 01954 01955 if(update_cdr && chan->cdr) 01956 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 01957 01958 } 01959 } else { 01960 p->loginchan[0] = '\0'; 01961 p->logincallerid[0] = '\0'; 01962 p->acknowledged = 0; 01963 } 01964 ast_mutex_unlock(&p->lock); 01965 AST_LIST_UNLOCK(&agents); 01966 if( !res && play_announcement==1 ) 01967 res = ast_streamfile(chan, filename, chan->language); 01968 if (!res) 01969 ast_waitstream(chan, ""); 01970 AST_LIST_LOCK(&agents); 01971 ast_mutex_lock(&p->lock); 01972 if (!res) { 01973 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 01974 if (res) 01975 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 01976 } 01977 if (!res) { 01978 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 01979 if (res) 01980 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 01981 } 01982 /* Check once more just in case */ 01983 if (p->chan) 01984 res = -1; 01985 if (callbackmode && !res) { 01986 /* Just say goodbye and be done with it */ 01987 if (!ast_strlen_zero(p->loginchan)) { 01988 if (p->loginstart == 0) 01989 time(&p->loginstart); 01990 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin", 01991 "Agent: %s\r\n" 01992 "Loginchan: %s\r\n" 01993 "Uniqueid: %s\r\n", 01994 p->agent, p->loginchan, chan->uniqueid); 01995 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan); 01996 if (option_verbose > 1) 01997 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan); 01998 ast_device_state_changed("Agent/%s", p->agent); 01999 if (persistent_agents) 02000 dump_agents(); 02001 } else { 02002 logintime = time(NULL) - p->loginstart; 02003 p->loginstart = 0; 02004 02005 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL); 02006 if (option_verbose > 1) 02007 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent); 02008 } 02009 AST_LIST_UNLOCK(&agents); 02010 if (!res) 02011 res = ast_safe_sleep(chan, 500); 02012 ast_mutex_unlock(&p->lock); 02013 } else if (!res) { 02014 ast_indicate_data(chan, AST_CONTROL_HOLD, 02015 S_OR(p->moh, NULL), 02016 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02017 if (p->loginstart == 0) 02018 time(&p->loginstart); 02019 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02020 "Agent: %s\r\n" 02021 "Channel: %s\r\n" 02022 "Uniqueid: %s\r\n", 02023 p->agent, chan->name, chan->uniqueid); 02024 if (update_cdr && chan->cdr) 02025 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02026 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02027 if (option_verbose > 1) 02028 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent, 02029 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02030 /* Login this channel and wait for it to go away */ 02031 p->chan = chan; 02032 if (p->ackcall > 1) 02033 check_beep(p, 0); 02034 else 02035 check_availability(p, 0); 02036 ast_mutex_unlock(&p->lock); 02037 AST_LIST_UNLOCK(&agents); 02038 ast_device_state_changed("Agent/%s", p->agent); 02039 while (res >= 0) { 02040 ast_mutex_lock(&p->lock); 02041 if (p->chan != chan) 02042 res = -1; 02043 ast_mutex_unlock(&p->lock); 02044 /* Yield here so other interested threads can kick in. */ 02045 sched_yield(); 02046 if (res) 02047 break; 02048 02049 AST_LIST_LOCK(&agents); 02050 ast_mutex_lock(&p->lock); 02051 if (p->lastdisc.tv_sec) { 02052 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) { 02053 if (option_debug) 02054 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent); 02055 p->lastdisc = ast_tv(0, 0); 02056 if (p->ackcall > 1) 02057 check_beep(p, 0); 02058 else 02059 check_availability(p, 0); 02060 } 02061 } 02062 ast_mutex_unlock(&p->lock); 02063 AST_LIST_UNLOCK(&agents); 02064 /* Synchronize channel ownership between call to agent and itself. */ 02065 ast_mutex_lock( &p->app_lock ); 02066 ast_mutex_lock(&p->lock); 02067 p->owning_app = pthread_self(); 02068 ast_mutex_unlock(&p->lock); 02069 if (p->ackcall > 1) 02070 res = agent_ack_sleep(p); 02071 else 02072 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02073 ast_mutex_unlock( &p->app_lock ); 02074 if ((p->ackcall > 1) && (res == 1)) { 02075 AST_LIST_LOCK(&agents); 02076 ast_mutex_lock(&p->lock); 02077 check_availability(p, 0); 02078 ast_mutex_unlock(&p->lock); 02079 AST_LIST_UNLOCK(&agents); 02080 res = 0; 02081 } 02082 sched_yield(); 02083 } 02084 ast_mutex_lock(&p->lock); 02085 if (res && p->owner) 02086 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02087 /* Log us off if appropriate */ 02088 if (p->chan == chan) 02089 p->chan = NULL; 02090 p->acknowledged = 0; 02091 logintime = time(NULL) - p->loginstart; 02092 p->loginstart = 0; 02093 ast_mutex_unlock(&p->lock); 02094 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02095 "Agent: %s\r\n" 02096 "Logintime: %ld\r\n" 02097 "Uniqueid: %s\r\n", 02098 p->agent, logintime, chan->uniqueid); 02099 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02100 if (option_verbose > 1) 02101 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent); 02102 /* If there is no owner, go ahead and kill it now */ 02103 ast_device_state_changed("Agent/%s", p->agent); 02104 if (p->dead && !p->owner) { 02105 ast_mutex_destroy(&p->lock); 02106 ast_mutex_destroy(&p->app_lock); 02107 free(p); 02108 } 02109 } 02110 else { 02111 ast_mutex_unlock(&p->lock); 02112 p = NULL; 02113 } 02114 res = -1; 02115 } else { 02116 ast_mutex_unlock(&p->lock); 02117 errmsg = "agent-alreadyon"; 02118 p = NULL; 02119 } 02120 break; 02121 } 02122 ast_mutex_unlock(&p->lock); 02123 } 02124 if (!p) 02125 AST_LIST_UNLOCK(&agents); 02126 02127 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02128 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02129 } 02130 02131 if (!res) 02132 res = ast_safe_sleep(chan, 500); 02133 02134 /* AgentLogin() exit */ 02135 if (!callbackmode) { 02136 ast_module_user_remove(u); 02137 return -1; 02138 } else { /* AgentCallbackLogin() exit*/ 02139 /* Set variables */ 02140 if (login_state > 0) { 02141 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user); 02142 if (login_state==1) { 02143 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on"); 02144 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension); 02145 } else 02146 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off"); 02147 } else { 02148 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail"); 02149 } 02150 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) { 02151 ast_module_user_remove(u); 02152 return 0; 02153 } 02154 /* Do we need to play agent-goodbye now that we will be hanging up? */ 02155 if (play_announcement) { 02156 if (!res) 02157 res = ast_safe_sleep(chan, 1000); 02158 res = ast_streamfile(chan, agent_goodbye, chan->language); 02159 if (!res) 02160 res = ast_waitstream(chan, ""); 02161 if (!res) 02162 res = ast_safe_sleep(chan, 1000); 02163 } 02164 } 02165 02166 ast_module_user_remove(u); 02167 02168 /* We should never get here if next priority exists when in callbackmode */ 02169 return -1; 02170 }
|
|
||||||||||||
|
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.
Definition at line 1553 of file chan_agent.c. References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), astman_send_error(), and s. Referenced by load_module(). 01554 { 01555 const char *agent = astman_get_header(m, "Agent"); 01556 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01557 int soft; 01558 int ret; /* return value of agent_logoff */ 01559 01560 if (ast_strlen_zero(agent)) { 01561 astman_send_error(s, m, "No agent specified"); 01562 return 0; 01563 } 01564 01565 soft = ast_true(soft_s) ? 1 : 0; 01566 ret = agent_logoff(agent, soft); 01567 if (ret == 0) 01568 astman_send_ack(s, m, "Agent logged out"); 01569 else 01570 astman_send_error(s, m, "No such agent"); 01571 01572 return 0; 01573 }
|
|
||||||||||||
|
Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.
Definition at line 1392 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, and S_OR. Referenced by load_module(). 01393 { 01394 const char *id = astman_get_header(m,"ActionID"); 01395 char idText[256] = ""; 01396 char chanbuf[256]; 01397 struct agent_pvt *p; 01398 char *username = NULL; 01399 char *loginChan = NULL; 01400 char *talkingtoChan = NULL; 01401 char *status = NULL; 01402 01403 if (!ast_strlen_zero(id)) 01404 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01405 astman_send_ack(s, m, "Agents will follow"); 01406 AST_LIST_LOCK(&agents); 01407 AST_LIST_TRAVERSE(&agents, p, list) { 01408 ast_mutex_lock(&p->lock); 01409 01410 /* Status Values: 01411 AGENT_LOGGEDOFF - Agent isn't logged in 01412 AGENT_IDLE - Agent is logged in, and waiting for call 01413 AGENT_ONCALL - Agent is logged in, and on a call 01414 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01415 01416 username = S_OR(p->name, "None"); 01417 01418 /* Set a default status. It 'should' get changed. */ 01419 status = "AGENT_UNKNOWN"; 01420 01421 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01422 loginChan = p->loginchan; 01423 talkingtoChan = "n/a"; 01424 status = "AGENT_IDLE"; 01425 if (p->acknowledged) { 01426 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01427 loginChan = chanbuf; 01428 } 01429 } else if (p->chan) { 01430 loginChan = ast_strdupa(p->chan->name); 01431 if (p->owner && p->owner->_bridge) { 01432 talkingtoChan = p->chan->cid.cid_num; 01433 status = "AGENT_ONCALL"; 01434 } else { 01435 talkingtoChan = "n/a"; 01436 status = "AGENT_IDLE"; 01437 } 01438 } else { 01439 loginChan = "n/a"; 01440 talkingtoChan = "n/a"; 01441 status = "AGENT_LOGGEDOFF"; 01442 } 01443 01444 astman_append(s, "Event: Agents\r\n" 01445 "Agent: %s\r\n" 01446 "Name: %s\r\n" 01447 "Status: %s\r\n" 01448 "LoggedInChan: %s\r\n" 01449 "LoggedInTime: %d\r\n" 01450 "TalkingTo: %s\r\n" 01451 "%s" 01452 "\r\n", 01453 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText); 01454 ast_mutex_unlock(&p->lock); 01455 } 01456 AST_LIST_UNLOCK(&agents); 01457 astman_append(s, "Event: AgentsComplete\r\n" 01458 "%s" 01459 "\r\n",idText); 01460 return 0; 01461 }
|
|
||||||||||||
|
Adds an agent to the global list of agents.
Definition at line 277 of file chan_agent.c. References agent_pvt::ackcall, agent_pvt::agent, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::lastdisc, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime. Referenced by agent_request(), and read_agent_config(). 00278 { 00279 char *parse; 00280 AST_DECLARE_APP_ARGS(args, 00281 AST_APP_ARG(agt); 00282 AST_APP_ARG(password); 00283 AST_APP_ARG(name); 00284 ); 00285 char *password = NULL; 00286 char *name = NULL; 00287 char *agt = NULL; 00288 struct agent_pvt *p; 00289 00290 parse = ast_strdupa(agent); 00291 00292 /* Extract username (agt), password and name from agent (args). */ 00293 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 00294 00295 if(args.argc == 0) { 00296 ast_log(LOG_WARNING, "A blank agent line!\n"); 00297 return NULL; 00298 } 00299 00300 if(ast_strlen_zero(args.agt) ) { 00301 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00302 return NULL; 00303 } else 00304 agt = args.agt; 00305 00306 if(!ast_strlen_zero(args.password)) { 00307 password = args.password; 00308 while (*password && *password < 33) password++; 00309 } 00310 if(!ast_strlen_zero(args.name)) { 00311 name = args.name; 00312 while (*name && *name < 33) name++; 00313 } 00314 00315 /* Are we searching for the agent here ? To see if it exists already ? */ 00316 AST_LIST_TRAVERSE(&agents, p, list) { 00317 if (!pending && !strcmp(p->agent, agt)) 00318 break; 00319 } 00320 if (!p) { 00321 // Build the agent. 00322 if (!(p = ast_calloc(1, sizeof(*p)))) 00323 return NULL; 00324 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00325 ast_mutex_init(&p->lock); 00326 ast_mutex_init(&p->app_lock); 00327 p->owning_app = (pthread_t) -1; 00328 p->app_sleep_cond = 1; 00329 p->group = group; 00330 p->pending = pending; 00331 AST_LIST_INSERT_TAIL(&agents, p, list); 00332 } 00333 00334 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00335 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00336 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00337 p->ackcall = ackcall; 00338 p->autologoff = autologoff; 00339 00340 /* If someone reduces the wrapuptime and reloads, we want it 00341 * to change the wrapuptime immediately on all calls */ 00342 if (p->wrapuptime > wrapuptime) { 00343 struct timeval now = ast_tvnow(); 00344 /* XXX check what is this exactly */ 00345 00346 /* We won't be pedantic and check the tv_usec val */ 00347 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00348 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00349 p->lastdisc.tv_usec = now.tv_usec; 00350 } 00351 } 00352 p->wrapuptime = wrapuptime; 00353 00354 if (pending) 00355 p->dead = 1; 00356 else 00357 p->dead = 0; 00358 return p; 00359 }
|
|
|
Definition at line 840 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, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass. Referenced by __login_exec(). 00841 { 00842 struct agent_pvt *p; 00843 int res=0; 00844 int to = 1000; 00845 struct ast_frame *f; 00846 00847 /* Wait a second and look for something */ 00848 00849 p = (struct agent_pvt *) data; 00850 if (!p->chan) 00851 return -1; 00852 00853 for(;;) { 00854 to = ast_waitfor(p->chan, to); 00855 if (to < 0) 00856 return -1; 00857 if (!to) 00858 return 0; 00859 f = ast_read(p->chan); 00860 if (!f) 00861 return -1; 00862 if (f->frametype == AST_FRAME_DTMF) 00863 res = f->subclass; 00864 else 00865 res = 0; 00866 ast_frfree(f); 00867 ast_mutex_lock(&p->lock); 00868 if (!p->app_sleep_cond) { 00869 ast_mutex_unlock(&p->lock); 00870 return 0; 00871 } else if (res == '#') { 00872 ast_mutex_unlock(&p->lock); 00873 return 1; 00874 } 00875 ast_mutex_unlock(&p->lock); 00876 res = 0; 00877 } 00878 return res; 00879 }
|
|
|
Definition at line 387 of file chan_agent.c. References ast_log(), and LOG_WARNING. 00388 { 00389 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00390 return -1; 00391 }
|
|
||||||||||||
|
Definition at line 881 of file chan_agent.c. References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, option_debug, and ast_channel::tech_pvt. 00882 { 00883 struct agent_pvt *p = bridge->tech_pvt; 00884 struct ast_channel *ret = NULL; 00885 00886 if (p) { 00887 if (chan == p->chan) 00888 ret = bridge->_bridge; 00889 else if (chan == bridge->_bridge) 00890 ret = p->chan; 00891 } 00892 00893 if (option_debug) 00894 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 00895 return ret; 00896 }
|
|
||||||||||||||||
|
Definition at line 623 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. 00624 { 00625 struct agent_pvt *p = ast->tech_pvt; 00626 int res = -1; 00627 int newstate=0; 00628 ast_mutex_lock(&p->lock); 00629 p->acknowledged = 0; 00630 if (!p->chan) { 00631 if (p->pending) { 00632 if (option_debug) 00633 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00634 newstate = AST_STATE_DIALING; 00635 res = 0; 00636 } else { 00637 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00638 res = -1; 00639 } 00640 ast_mutex_unlock(&p->lock); 00641 if (newstate) 00642 ast_setstate(ast, newstate); 00643 return res; 00644 } else if (!ast_strlen_zero(p->loginchan)) { 00645 time(&p->start); 00646 /* Call on this agent */ 00647 if (option_verbose > 2) 00648 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00649 ast_set_callerid(p->chan, 00650 ast->cid.cid_num, ast->cid.cid_name, NULL); 00651 ast_channel_inherit_variables(ast, p->chan); 00652 res = ast_call(p->chan, p->loginchan, 0); 00653 CLEANUP(ast,p); 00654 ast_mutex_unlock(&p->lock); 00655 return res; 00656 } 00657 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00658 if (option_debug > 2) 00659 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language); 00660 res = ast_streamfile(p->chan, beep, p->chan->language); 00661 if (option_debug > 2) 00662 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 00663 if (!res) { 00664 res = ast_waitstream(p->chan, ""); 00665 if (option_debug > 2) 00666 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 00667 } 00668 if (!res) { 00669 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00670 if (option_debug > 2) 00671 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res); 00672 if (res) 00673 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00674 } else { 00675 /* Agent hung-up */ 00676 p->chan = NULL; 00677 } 00678 00679 if (!res) { 00680 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00681 if (option_debug > 2) 00682 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res); 00683 if (res) 00684 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00685 } 00686 if(!res) { 00687 /* Call is immediately up, or might need ack */ 00688 if (p->ackcall > 1) 00689 newstate = AST_STATE_RINGING; 00690 else { 00691 newstate = AST_STATE_UP; 00692 if (recordagentcalls) 00693 agent_start_monitoring(ast, 0); 00694 p->acknowledged = 1; 00695 } 00696 res = 0; 00697 } 00698 CLEANUP(ast, p); 00699 ast_mutex_unlock(&p->lock); 00700 if (newstate) 00701 ast_setstate(ast, newstate); 00702 return res; 00703 }
|
|
|
Deletes an agent after doing some clean up. Further documentation: How safe is this function ? What state should the agent be to be cleaned.
Definition at line 367 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(). 00368 { 00369 struct ast_channel *chan = p->owner; 00370 p->owner = NULL; 00371 chan->tech_pvt = NULL; 00372 p->app_sleep_cond = 1; 00373 /* Release ownership of the agent to other threads (presumably running the login app). */ 00374 ast_mutex_unlock(&p->app_lock); 00375 if (chan) 00376 ast_channel_free(chan); 00377 if (p->dead) { 00378 ast_mutex_destroy(&p->lock); 00379 ast_mutex_destroy(&p->app_lock); 00380 free(p); 00381 } 00382 return 0; 00383 }
|
|
|
Definition at line 819 of file chan_agent.c. References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, option_debug, and agent_pvt::wrapuptime. Referenced by __login_exec(). 00820 { 00821 struct agent_pvt *p; 00822 int res; 00823 00824 p = (struct agent_pvt *)data; 00825 00826 ast_mutex_lock(&p->lock); 00827 res = p->app_sleep_cond; 00828 if (p->lastdisc.tv_sec) { 00829 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 00830 res = 1; 00831 } 00832 ast_mutex_unlock(&p->lock); 00833 00834 if (option_debug > 4 && !res) 00835 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res ); 00836 00837 return res; 00838 }
|
|
|
Part of PBX channel interface.
Definition at line 2329 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. 02330 { 02331 struct agent_pvt *p; 02332 char *s; 02333 ast_group_t groupmatch; 02334 int groupoff; 02335 int waitforagent=0; 02336 int res = AST_DEVICE_INVALID; 02337 02338 s = data; 02339 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) 02340 groupmatch = (1 << groupoff); 02341 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 02342 groupmatch = (1 << groupoff); 02343 waitforagent = 1; 02344 } else 02345 groupmatch = 0; 02346 02347 /* Check actual logged in agents first */ 02348 AST_LIST_LOCK(&agents); 02349 AST_LIST_TRAVERSE(&agents, p, list) { 02350 ast_mutex_lock(&p->lock); 02351 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02352 if (p->owner) { 02353 if (res != AST_DEVICE_INUSE) 02354 res = AST_DEVICE_BUSY; 02355 } else { 02356 if (res == AST_DEVICE_BUSY) 02357 res = AST_DEVICE_INUSE; 02358 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02359 if (res == AST_DEVICE_INVALID) 02360 res = AST_DEVICE_UNKNOWN; 02361 } else if (res == AST_DEVICE_INVALID) 02362 res = AST_DEVICE_UNAVAILABLE; 02363 } 02364 if (!strcmp(data, p->agent)) { 02365 ast_mutex_unlock(&p->lock); 02366 break; 02367 } 02368 } 02369 ast_mutex_unlock(&p->lock); 02370 } 02371 AST_LIST_UNLOCK(&agents); 02372 return res; 02373 }
|
|
||||||||||||
|
Definition at line 603 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. 00604 { 00605 struct agent_pvt *p = ast->tech_pvt; 00606 int res = -1; 00607 ast_mutex_lock(&p->lock); 00608 ast_senddigit_begin(p->chan, digit); 00609 ast_mutex_unlock(&p->lock); 00610 return res; 00611 }
|
|
||||||||||||||||
|
Definition at line 613 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. 00614 { 00615 struct agent_pvt *p = ast->tech_pvt; 00616 int res = -1; 00617 ast_mutex_lock(&p->lock); 00618 ast_senddigit_end(p->chan, digit, duration); 00619 ast_mutex_unlock(&p->lock); 00620 return res; 00621 }
|
|
||||||||||||
|
Definition at line 576 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. 00577 { 00578 struct agent_pvt *p = newchan->tech_pvt; 00579 ast_mutex_lock(&p->lock); 00580 if (p->owner != oldchan) { 00581 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00582 ast_mutex_unlock(&p->lock); 00583 return -1; 00584 } 00585 p->owner = newchan; 00586 ast_mutex_unlock(&p->lock); 00587 return 0; 00588 }
|
|
|
Definition at line 718 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, free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, 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. 00719 { 00720 struct agent_pvt *p = ast->tech_pvt; 00721 int howlong = 0; 00722 const char *status; 00723 ast_mutex_lock(&p->lock); 00724 p->owner = NULL; 00725 ast->tech_pvt = NULL; 00726 p->app_sleep_cond = 1; 00727 p->acknowledged = 0; 00728 00729 /* if they really are hung up then set start to 0 so the test 00730 * later if we're called on an already downed channel 00731 * doesn't cause an agent to be logged out like when 00732 * agent_request() is followed immediately by agent_hangup() 00733 * as in apps/app_chanisavail.c:chanavail_exec() 00734 */ 00735 00736 if (option_debug) 00737 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00738 if (p->start && (ast->_state != AST_STATE_UP)) { 00739 howlong = time(NULL) - p->start; 00740 p->start = 0; 00741 } else if (ast->_state == AST_STATE_RESERVED) 00742 howlong = 0; 00743 else 00744 p->start = 0; 00745 if (p->chan) { 00746 p->chan->_bridge = NULL; 00747 /* If they're dead, go ahead and hang up on the agent now */ 00748 if (!ast_strlen_zero(p->loginchan)) { 00749 /* Store last disconnect time */ 00750 if (p->wrapuptime) 00751 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00752 else 00753 p->lastdisc = ast_tv(0,0); 00754 if (p->chan) { 00755 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00756 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00757 long logintime = time(NULL) - p->loginstart; 00758 p->loginstart = 0; 00759 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00760 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00761 } 00762 /* Recognize the hangup and pass it along immediately */ 00763 ast_hangup(p->chan); 00764 p->chan = NULL; 00765 } 00766 if (option_debug) 00767 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00768 if (howlong && p->autologoff && (howlong > p->autologoff)) { 00769 long logintime = time(NULL) - p->loginstart; 00770 p->loginstart = 0; 00771 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00772 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00773 } 00774 } else if (p->dead) { 00775 ast_channel_lock(p->chan); 00776 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00777 ast_channel_unlock(p->chan); 00778 } else if (p->loginstart) { 00779 ast_channel_lock(p->chan); 00780 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00781 S_OR(p->moh, NULL), 00782 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00783 ast_channel_unlock(p->chan); 00784 } 00785 } 00786 ast_mutex_unlock(&p->lock); 00787 /* Only register a device state change if the agent is still logged in */ 00788 if (p->loginstart) 00789 ast_device_state_changed("Agent/%s", p->agent); 00790 00791 if (p->pending) { 00792 AST_LIST_LOCK(&agents); 00793 AST_LIST_REMOVE(&agents, p, list); 00794 AST_LIST_UNLOCK(&agents); 00795 } 00796 if (p->abouttograb) { 00797 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00798 kill it later */ 00799 p->abouttograb = 0; 00800 } else if (p->dead) { 00801 ast_mutex_destroy(&p->lock); 00802 ast_mutex_destroy(&p->app_lock); 00803 free(p); 00804 } else { 00805 if (p->chan) { 00806 /* Not dead -- check availability now */ 00807 ast_mutex_lock(&p->lock); 00808 /* Store last disconnect time */ 00809 p->lastdisc = ast_tvnow(); 00810 ast_mutex_unlock(&p->lock); 00811 } 00812 /* Release ownership of the agent to other threads (presumably running the login app). */ 00813 if (ast_strlen_zero(p->loginchan)) 00814 ast_mutex_unlock(&p->app_lock); 00815 } 00816 return 0; 00817 }
|
|
||||||||||||||||||||
|
Definition at line 590 of file chan_agent.c. References ast_indicate_data(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt. 00591 { 00592 struct agent_pvt *p = ast->tech_pvt; 00593 int res = -1; 00594 ast_mutex_lock(&p->lock); 00595 if (p->chan) 00596 res = ast_indicate_data(p->chan, condition, data, datalen); 00597 else 00598 res = 0; 00599 ast_mutex_unlock(&p->lock); 00600 return res; 00601 }
|
|
||||||||||||
|
Definition at line 1502 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::loginchan, agent_pvt::loginstart, and agent_pvt::owner. Referenced by action_agent_logoff(), and agent_logoff_cmd(). 01503 { 01504 struct agent_pvt *p; 01505 long logintime; 01506 int ret = -1; /* Return -1 if no agent if found */ 01507 01508 AST_LIST_TRAVERSE(&agents, p, list) { 01509 if (!strcasecmp(p->agent, agent)) { 01510 if (!soft) { 01511 if (p->owner) 01512 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01513 if (p->chan) 01514 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01515 } 01516 ret = 0; /* found an agent => return 0 */ 01517 logintime = time(NULL) - p->loginstart; 01518 p->loginstart = 0; 01519 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01520 break; 01521 } 01522 } 01523 01524 return ret; 01525 }
|
|
||||||||||||||||
|
Definition at line 1527 of file chan_agent.c. References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS. 01528 { 01529 int ret; 01530 char *agent; 01531 01532 if (argc < 3 || argc > 4) 01533 return RESULT_SHOWUSAGE; 01534 if (argc == 4 && strcasecmp(argv[3], "soft")) 01535 return RESULT_SHOWUSAGE; 01536 01537 agent = argv[2] + 6; 01538 ret = agent_logoff(agent, argc == 4); 01539 if (ret == 0) 01540 ast_cli(fd, "Logging out %s\n", agent); 01541 01542 return RESULT_SUCCESS; 01543 }
|
|
||||||||||||||||||||||||
|
Definition at line 1463 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(). 01464 { 01465 char *tmp = NULL; 01466 char agent[AST_MAX_AGENT]; 01467 01468 if (!ast_strlen_zero(logcommand)) 01469 tmp = logcommand; 01470 else 01471 tmp = ast_strdupa(""); 01472 01473 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01474 01475 if (!ast_strlen_zero(uniqueid)) { 01476 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01477 "Agent: %s\r\n" 01478 "Reason: %s\r\n" 01479 "Loginchan: %s\r\n" 01480 "Logintime: %ld\r\n" 01481 "Uniqueid: %s\r\n", 01482 p->agent, tmp, loginchan, logintime, uniqueid); 01483 } else { 01484 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01485 "Agent: %s\r\n" 01486 "Reason: %s\r\n" 01487 "Loginchan: %s\r\n" 01488 "Logintime: %ld\r\n", 01489 p->agent, tmp, loginchan, logintime); 01490 } 01491 01492 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01493 set_agentbycallerid(p->logincallerid, NULL); 01494 p->loginchan[0] ='\0'; 01495 p->logincallerid[0] = '\0'; 01496 ast_device_state_changed("Agent/%s", p->agent); 01497 if (persistent_agents) 01498 dump_agents(); 01499 01500 }
|
|
||||||||||||
|
Create new agent channel.
Definition at line 899 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, 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(). 00900 { 00901 struct ast_channel *tmp; 00902 #if 0 00903 if (!p->chan) { 00904 ast_log(LOG_WARNING, "No channel? :(\n"); 00905 return NULL; 00906 } 00907 #endif 00908 if (p->pending) 00909 tmp = ast_channel_alloc(0, state, 0, 0, "Agent/P%s-%d", p->agent, ast_random() & 0xffff); 00910 else 00911 tmp = ast_channel_alloc(0, state, 0, 0, "Agent/%s", p->agent); 00912 if (!tmp) { 00913 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 00914 return NULL; 00915 } 00916 00917 tmp->tech = &agent_tech; 00918 if (p->chan) { 00919 tmp->nativeformats = p->chan->nativeformats; 00920 tmp->writeformat = p->chan->writeformat; 00921 tmp->rawwriteformat = p->chan->writeformat; 00922 tmp->readformat = p->chan->readformat; 00923 tmp->rawreadformat = p->chan->readformat; 00924 ast_string_field_set(tmp, language, p->chan->language); 00925 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 00926 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 00927 /* XXX Is this really all we copy form the originating channel?? */ 00928 } else { 00929 tmp->nativeformats = AST_FORMAT_SLINEAR; 00930 tmp->writeformat = AST_FORMAT_SLINEAR; 00931 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 00932 tmp->readformat = AST_FORMAT_SLINEAR; 00933 tmp->rawreadformat = AST_FORMAT_SLINEAR; 00934 } 00935 /* Safe, agentlock already held */ 00936 tmp->tech_pvt = p; 00937 p->owner = tmp; 00938 tmp->priority = 1; 00939 /* Wake up and wait for other applications (by definition the login app) 00940 * to release this channel). Takes ownership of the agent channel 00941 * to this thread only. 00942 * For signalling the other thread, ast_queue_frame is used until we 00943 * can safely use signals for this purpose. The pselect() needs to be 00944 * implemented in the kernel for this. 00945 */ 00946 p->app_sleep_cond = 0; 00947 if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) { 00948 if (p->chan) { 00949 ast_queue_frame(p->chan, &ast_null_frame); 00950 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 00951 ast_mutex_lock(&p->app_lock); 00952 ast_mutex_lock(&p->lock); 00953 } else { 00954 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 00955 p->owner = NULL; 00956 tmp->tech_pvt = NULL; 00957 p->app_sleep_cond = 1; 00958 ast_channel_free( tmp ); 00959 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 00960 ast_mutex_unlock(&p->app_lock); 00961 return NULL; 00962 } 00963 } else if (!ast_strlen_zero(p->loginchan)) { 00964 if (p->chan) 00965 ast_queue_frame(p->chan, &ast_null_frame); 00966 if (!p->chan) { 00967 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 00968 p->owner = NULL; 00969 tmp->tech_pvt = NULL; 00970 p->app_sleep_cond = 1; 00971 ast_channel_free( tmp ); 00972 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 00973 return NULL; 00974 } 00975 } 00976 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 00977 p->owning_app = pthread_self(); 00978 /* After the above step, there should not be any blockers. */ 00979 if (p->chan) { 00980 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) { 00981 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" ); 00982 CRASH; 00983 } 00984 } 00985 return tmp; 00986 }
|
|
|
Definition at line 426 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, 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_debug, 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. 00427 { 00428 struct agent_pvt *p = ast->tech_pvt; 00429 struct ast_frame *f = NULL; 00430 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00431 const char *status; 00432 ast_mutex_lock(&p->lock); 00433 CHECK_FORMATS(ast, p); 00434 if (p->chan) { 00435 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00436 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00437 f = ast_read(p->chan); 00438 } else 00439 f = &ast_null_frame; 00440 if (!f) { 00441 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00442 if (p->chan) { 00443 p->chan->_bridge = NULL; 00444 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00445 for us when the PBX instance that called login finishes */ 00446 if (!ast_strlen_zero(p->loginchan)) { 00447 if (p->chan && option_debug) 00448 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00449 00450 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00451 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00452 long logintime = time(NULL) - p->loginstart; 00453 p->loginstart = 0; 00454 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00455 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00456 } 00457 ast_hangup(p->chan); 00458 if (p->wrapuptime && p->acknowledged) 00459 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00460 } 00461 p->chan = NULL; 00462 p->acknowledged = 0; 00463 } 00464 } else { 00465 /* if acknowledgement is not required, and the channel is up, we may have missed 00466 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00467 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) 00468 p->acknowledged = 1; 00469 switch (f->frametype) { 00470 case AST_FRAME_CONTROL: 00471 if (f->subclass == AST_CONTROL_ANSWER) { 00472 if (p->ackcall) { 00473 if (option_verbose > 2) 00474 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 00475 /* Don't pass answer along */ 00476 ast_frfree(f); 00477 f = &ast_null_frame; 00478 } else { 00479 p->acknowledged = 1; 00480 /* Use the builtin answer frame for the 00481 recording start check below. */ 00482 ast_frfree(f); 00483 f = &answer_frame; 00484 } 00485 } 00486 break; 00487 case AST_FRAME_DTMF_BEGIN: 00488 case AST_FRAME_DTMF_END: 00489 if (!p->acknowledged && (f->subclass == '#')) { 00490 if (option_verbose > 2) 00491 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 00492 p->acknowledged = 1; 00493 ast_frfree(f); 00494 f = &answer_frame; 00495 } else if (f->subclass == '*' && endcall) { 00496 /* terminates call */ 00497 ast_frfree(f); 00498 f = NULL; 00499 } 00500 break; 00501 case AST_FRAME_VOICE: 00502 case AST_FRAME_VIDEO: 00503 /* don't pass voice or video until the call is acknowledged */ 00504 if (!p->acknowledged) { 00505 ast_frfree(f); 00506 f = &ast_null_frame; 00507 } 00508 default: 00509 /* pass everything else on through */ 00510 break; 00511 } 00512 } 00513 00514 CLEANUP(ast,p); 00515 if (p->chan && !p->chan->_bridge) { 00516 if (strcasecmp(p->chan->tech->type, "Local")) { 00517 p->chan->_bridge = ast; 00518 if (p->chan && option_debug) 00519 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00520 } 00521 } 00522 ast_mutex_unlock(&p->lock); 00523 if (recordagentcalls && f == &answer_frame) 00524 agent_start_monitoring(ast,0); 00525 return f; 00526 }
|
|
||||||||||||||||||||
|
Part of the Asterisk PBX interface.
Definition at line 1279 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. 01280 { 01281 struct agent_pvt *p; 01282 struct ast_channel *chan = NULL; 01283 char *s; 01284 ast_group_t groupmatch; 01285 int groupoff; 01286 int waitforagent=0; 01287 int hasagent = 0; 01288 struct timeval tv; 01289 01290 s = data; 01291 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01292 groupmatch = (1 << groupoff); 01293 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) { 01294 groupmatch = (1 << groupoff); 01295 waitforagent = 1; 01296 } else 01297 groupmatch = 0; 01298 01299 /* Check actual logged in agents first */ 01300 AST_LIST_LOCK(&agents); 01301 AST_LIST_TRAVERSE(&agents, p, list) { 01302 ast_mutex_lock(&p->lock); 01303 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01304 ast_strlen_zero(p->loginchan)) { 01305 if (p->chan) 01306 hasagent++; 01307 if (!p->lastdisc.tv_sec) { 01308 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01309 if (!p->owner && p->chan) { 01310 /* Fixed agent */ 01311 chan = agent_new(p, AST_STATE_DOWN); 01312 } 01313 if (chan) { 01314 ast_mutex_unlock(&p->lock); 01315 break; 01316 } 01317 } 01318 } 01319 ast_mutex_unlock(&p->lock); 01320 } 01321 if (!p) { 01322 AST_LIST_TRAVERSE(&agents, p, list) { 01323 ast_mutex_lock(&p->lock); 01324 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01325 if (p->chan || !ast_strlen_zero(p->loginchan)) 01326 hasagent++; 01327 tv = ast_tvnow(); 01328 #if 0 01329 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec); 01330 #endif 01331 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) { 01332 p->lastdisc = ast_tv(0, 0); 01333 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01334 if (!p->owner && p->chan) { 01335 /* Could still get a fixed agent */ 01336 chan = agent_new(p, AST_STATE_DOWN); 01337 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01338 /* Adjustable agent */ 01339 p->chan = ast_request("Local", format, p->loginchan, cause); 01340 if (p->chan) 01341 chan = agent_new(p, AST_STATE_DOWN); 01342 } 01343 if (chan) { 01344 ast_mutex_unlock(&p->lock); 01345 break; 01346 } 01347 } 01348 } 01349 ast_mutex_unlock(&p->lock); 01350 } 01351 } 01352 01353 if (!chan && waitforagent) { 01354 /* No agent available -- but we're requesting to wait for one. 01355 Allocate a place holder */ 01356 if (hasagent) { 01357 if (option_debug) 01358 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s); 01359 p = add_agent(data, 1); 01360 p->group = groupmatch; 01361 chan = agent_new(p, AST_STATE_DOWN); 01362 if (!chan) 01363 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01364 } else { 01365 if (option_debug) 01366 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s); 01367 } 01368 } 01369 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01370 AST_LIST_UNLOCK(&agents); 01371 return chan; 01372 }
|
|
||||||||||||||||||||
|
Definition at line 528 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. 00529 { 00530 struct agent_pvt *p = ast->tech_pvt; 00531 int res = -1; 00532 ast_mutex_lock(&p->lock); 00533 if (p->chan) 00534 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00535 ast_mutex_unlock(&p->lock); 00536 return res; 00537 }
|
|
||||||||||||
|
Definition at line 539 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. 00540 { 00541 struct agent_pvt *p = ast->tech_pvt; 00542 int res = -1; 00543 ast_mutex_lock(&p->lock); 00544 if (p->chan) 00545 res = ast_sendtext(p->chan, text); 00546 ast_mutex_unlock(&p->lock); 00547 return res; 00548 }
|
|
||||||||||||
|
Definition at line 421 of file chan_agent.c. References __agent_start_monitoring(), and ast_channel::tech_pvt. Referenced by agent_call(), and agent_read(). 00422 { 00423 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00424 }
|
|
||||||||||||
|
Definition at line 550 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, option_debug, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat. 00551 { 00552 struct agent_pvt *p = ast->tech_pvt; 00553 int res = -1; 00554 CHECK_FORMATS(ast, p); 00555 ast_mutex_lock(&p->lock); 00556 if (!p->chan) 00557 res = 0; 00558 else { 00559 if ((f->frametype != AST_FRAME_VOICE) || 00560 (f->frametype != AST_FRAME_VIDEO) || 00561 (f->subclass == p->chan->writeformat)) { 00562 res = ast_write(p->chan, f); 00563 } else { 00564 if (option_debug) 00565 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00566 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00567 ast->name, p->chan->name); 00568 res = 0; 00569 } 00570 } 00571 CLEANUP(ast, p); 00572 ast_mutex_unlock(&p->lock); 00573 return res; 00574 }
|
|
||||||||||||
|
Called by the AgentMonitorOutgoing application (from the dial plan).
Definition at line 2193 of file chan_agent.c. References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_verbose(), ast_channel::cdr, agent_pvt::chan, ast_module_user::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3. Referenced by load_module(). 02194 { 02195 int exitifnoagentid = 0; 02196 int nowarnings = 0; 02197 int changeoutgoing = 0; 02198 int res = 0; 02199 char agent[AST_MAX_AGENT]; 02200 02201 if (data) { 02202 if (strchr(data, 'd')) 02203 exitifnoagentid = 1; 02204 if (strchr(data, 'n')) 02205 nowarnings = 1; 02206 if (strchr(data, 'c')) 02207 changeoutgoing = 1; 02208 } 02209 if (chan->cid.cid_num) { 02210 const char *tmp; 02211 char agentvar[AST_MAX_BUF]; 02212 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02213 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02214 struct agent_pvt *p; 02215 ast_copy_string(agent, tmp, sizeof(agent)); 02216 AST_LIST_LOCK(&agents); 02217 AST_LIST_TRAVERSE(&agents, p, list) { 02218 if (!strcasecmp(p->agent, tmp)) { 02219 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02220 __agent_start_monitoring(chan, p, 1); 02221 break; 02222 } 02223 } 02224 AST_LIST_UNLOCK(&agents); 02225 02226 } else { 02227 res = -1; 02228 if (!nowarnings) 02229 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); 02230 } 02231 } else { 02232 res = -1; 02233 if (!nowarnings) 02234 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"); 02235 } 02236 /* check if there is n + 101 priority */ 02237 /*! \todo XXX Needs to check option priorityjump etc etc */ 02238 if (res) { 02239 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) { 02240 chan->priority+=100; 02241 if (option_verbose > 2) 02242 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); 02243 } else if (exitifnoagentid) 02244 return res; 02245 } 02246 return 0; 02247 }
|
|
||||||||||||||||
|
Show agents in cli. < Number of agents configured < Number of online agents < Number of offline agents Definition at line 1596 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, and RESULT_SUCCESS. 01597 { 01598 struct agent_pvt *p; 01599 char username[AST_MAX_BUF]; 01600 char location[AST_MAX_BUF] = ""; 01601 char talkingto[AST_MAX_BUF] = ""; 01602 char moh[AST_MAX_BUF]; 01603 int count_agents = 0; /*!< Number of agents configured */ 01604 int online_agents = 0; /*!< Number of online agents */ 01605 int offline_agents = 0; /*!< Number of offline agents */ 01606 if (argc != 2) 01607 return RESULT_SHOWUSAGE; 01608 AST_LIST_LOCK(&agents); 01609 AST_LIST_TRAVERSE(&agents, p, list) { 01610 ast_mutex_lock(&p->lock); 01611 if (p->pending) { 01612 if (p->group) 01613 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group)); 01614 else 01615 ast_cli(fd, "-- Pending call to agent %s\n", p->agent); 01616 } else { 01617 if (!ast_strlen_zero(p->name)) 01618 snprintf(username, sizeof(username), "(%s) ", p->name); 01619 else 01620 username[0] = '\0'; 01621 if (p->chan) { 01622 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01623 if (p->owner && ast_bridged_channel(p->owner)) 01624 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01625 else 01626 strcpy(talkingto, " is idle"); 01627 online_agents++; 01628 } else if (!ast_strlen_zero(p->loginchan)) { 01629 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01630 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01631 else 01632 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01633 talkingto[0] = '\0'; 01634 online_agents++; 01635 if (p->acknowledged) 01636 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01637 } else { 01638 strcpy(location, "not logged in"); 01639 talkingto[0] = '\0'; 01640 offline_agents++; 01641 } 01642 if (!ast_strlen_zero(p->moh)) 01643 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01644 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 01645 username, location, talkingto, moh); 01646 count_agents++; 01647 } 01648 ast_mutex_unlock(&p->lock); 01649 } 01650 AST_LIST_UNLOCK(&agents); 01651 if ( !count_agents ) 01652 ast_cli(fd, "No Agents are configured in %s\n",config); 01653 else 01654 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01655 ast_cli(fd, "\n"); 01656 01657 return RESULT_SUCCESS; 01658 }
|
|
||||||||||||||||
|
Definition at line 1661 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, and RESULT_SUCCESS. 01662 { 01663 struct agent_pvt *p; 01664 char username[AST_MAX_BUF]; 01665 char location[AST_MAX_BUF] = ""; 01666 char talkingto[AST_MAX_BUF] = ""; 01667 char moh[AST_MAX_BUF]; 01668 int count_agents = 0; /* Number of agents configured */ 01669 int online_agents = 0; /* Number of online agents */ 01670 int agent_status = 0; /* 0 means offline, 1 means online */ 01671 if (argc != 3) 01672 return RESULT_SHOWUSAGE; 01673 AST_LIST_LOCK(&agents); 01674 AST_LIST_TRAVERSE(&agents, p, list) { 01675 agent_status = 0; /* reset it to offline */ 01676 ast_mutex_lock(&p->lock); 01677 if (!ast_strlen_zero(p->name)) 01678 snprintf(username, sizeof(username), "(%s) ", p->name); 01679 else 01680 username[0] = '\0'; 01681 if (p->chan) { 01682 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01683 if (p->owner && ast_bridged_channel(p->owner)) 01684 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01685 else 01686 strcpy(talkingto, " is idle"); 01687 agent_status = 1; 01688 online_agents++; 01689 } else if (!ast_strlen_zero(p->loginchan)) { 01690 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01691 talkingto[0] = '\0'; 01692 agent_status = 1; 01693 online_agents++; 01694 if (p->acknowledged) 01695 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01696 } 01697 if (!ast_strlen_zero(p->moh)) 01698 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh); 01699 if (agent_status) 01700 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh); 01701 count_agents++; 01702 ast_mutex_unlock(&p->lock); 01703 } 01704 AST_LIST_UNLOCK(&agents); 01705 if (!count_agents) 01706 ast_cli(fd, "No Agents are configured in %s\n", config); 01707 else 01708 ast_cli(fd, "%d agents online\n", online_agents); 01709 ast_cli(fd, "\n"); 01710 return RESULT_SUCCESS; 01711 }
|
|
||||||||||||
|
Definition at line 1259 of file chan_agent.c. References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR. Referenced by __login_exec(). 01260 { 01261 struct agent_pvt *p; 01262 char loginchan[80]; 01263 01264 if(multiplelogin) 01265 return 1; 01266 if(!chan) 01267 return 0; 01268 01269 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default")); 01270 01271 AST_LIST_TRAVERSE(&agents, p, list) { 01272 if(!strcasecmp(chan, p->loginchan)) 01273 return 0; 01274 } 01275 return -1; 01276 }
|
|
||||||||||||
|
Holds the list of agents (loaded form agents.conf). |
|
||||||||||||||||||||||||||||
|
|
|
||||||||||||
|
Definition at line 1143 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(). 01144 { 01145 struct ast_channel *chan=NULL, *parent=NULL; 01146 struct agent_pvt *p; 01147 int res; 01148 01149 if (option_debug) 01150 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent); 01151 if (needlock) 01152 AST_LIST_LOCK(&agents); 01153 AST_LIST_TRAVERSE(&agents, p, list) { 01154 if (p == newlyavailable) { 01155 continue; 01156 } 01157 ast_mutex_lock(&p->lock); 01158 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01159 if (option_debug) 01160 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01161 /* We found a pending call, time to merge */ 01162 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01163 parent = p->owner; 01164 p->abouttograb = 1; 01165 ast_mutex_unlock(&p->lock); 01166 break; 01167 } 01168 ast_mutex_unlock(&p->lock); 01169 } 01170 if (needlock) 01171 AST_LIST_UNLOCK(&agents); 01172 if (parent && chan) { 01173 if (newlyavailable->ackcall > 1) { 01174 /* Don't do beep here */ 01175 res = 0; 01176 } else { 01177 if (option_debug > 2) 01178 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01179 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01180 if (option_debug > 2) 01181 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 01182 if (!res) { 01183 res = ast_waitstream(newlyavailable->chan, ""); 01184 if (option_debug) 01185 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01186 } 01187 } 01188 if (!res) { 01189 /* Note -- parent may have disappeared */ 01190 if (p->abouttograb) { 01191 newlyavailable->acknowledged = 1; 01192 /* Safe -- agent lock already held */ 01193 ast_setstate(parent, AST_STATE_UP); 01194 ast_setstate(chan, AST_STATE_UP); 01195 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01196 /* Go ahead and mark the channel as a zombie so that masquerade will 01197 destroy it for us, and we need not call ast_hangup */ 01198 ast_mutex_lock(&parent->lock); 01199 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01200 ast_channel_masquerade(parent, chan); 01201 ast_mutex_unlock(&parent->lock); 01202 p->abouttograb = 0; 01203 } else { 01204 if (option_debug) 01205 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n"); 01206 agent_cleanup(newlyavailable); 01207 } 01208 } else { 01209 if (option_debug) 01210 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n"); 01211 agent_cleanup(newlyavailable); 01212 } 01213 } 01214 return 0; 01215 }
|
|
||||||||||||
|
Definition at line 1217 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(). 01218 { 01219 struct agent_pvt *p; 01220 int res=0; 01221 01222 if (option_debug) 01223 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent); 01224 if (needlock) 01225 AST_LIST_LOCK(&agents); 01226 AST_LIST_TRAVERSE(&agents, p, list) { 01227 if (p == newlyavailable) { 01228 continue; 01229 } 01230 ast_mutex_lock(&p->lock); 01231 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01232 if (option_debug) 01233 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01234 ast_mutex_unlock(&p->lock); 01235 break; 01236 } 01237 ast_mutex_unlock(&p->lock); 01238 } 01239 if (needlock) 01240 AST_LIST_UNLOCK(&agents); 01241 if (p) { 01242 ast_mutex_unlock(&newlyavailable->lock); 01243 if (option_debug > 2) 01244 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01245 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01246 if (option_debug > 2) 01247 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 01248 if (!res) { 01249 res = ast_waitstream(newlyavailable->chan, ""); 01250 if (option_debug) 01251 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 01252 } 01253 ast_mutex_lock(&newlyavailable->lock); 01254 } 01255 return res; 01256 }
|
|
||||||||||||||||||||
|
Definition at line 1575 of file chan_agent.c. References agent_pvt::agent, AST_LIST_TRAVERSE, AST_MAX_AGENT, ast_strdup, len, and name. 01576 { 01577 if (pos == 2) { 01578 struct agent_pvt *p; 01579 char name[AST_MAX_AGENT]; 01580 int which = 0, len = strlen(word); 01581 01582 AST_LIST_TRAVERSE(&agents, p, list) { 01583 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01584 if (!strncasecmp(word, name, len) && ++which > state) 01585 return ast_strdup(name); 01586 } 01587 } else if (pos == 3 && state == 0) 01588 return ast_strdup("soft"); 01589 01590 return NULL; 01591 }
|
|
|
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2252 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(), and agent_logoff_maintenance(). 02253 { 02254 struct agent_pvt *cur_agent = NULL; 02255 char buf[256]; 02256 02257 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02258 if (cur_agent->chan) 02259 continue; 02260 02261 if (!ast_strlen_zero(cur_agent->loginchan)) { 02262 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02263 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02264 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02265 else if (option_debug) 02266 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02267 } else { 02268 /* Delete - no agent or there is an error */ 02269 ast_db_del(pa_family, cur_agent->agent); 02270 } 02271 } 02272 }
|
|
|
Definition at line 2375 of file chan_agent.c. References agent_pvt::agent, and AST_LIST_TRAVERSE. Referenced by function_agent(). 02376 { 02377 struct agent_pvt *cur; 02378 02379 AST_LIST_TRAVERSE(&agents, cur, list) { 02380 if (!strcmp(cur->agent, agentid)) 02381 break; 02382 } 02383 02384 return cur; 02385 }
|
|
||||||||||||||||||||||||
|
Definition at line 2387 of file chan_agent.c. References agent_pvt::agent, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_agent(), LOG_WARNING, and parse(). 02388 { 02389 char *parse; 02390 AST_DECLARE_APP_ARGS(args, 02391 AST_APP_ARG(agentid); 02392 AST_APP_ARG(item); 02393 ); 02394 char *tmp; 02395 struct agent_pvt *agent; 02396 02397 buf[0] = '\0'; 02398 02399 if (ast_strlen_zero(data)) { 02400 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02401 return -1; 02402 } 02403 02404 parse = ast_strdupa(data); 02405 02406 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02407 if (!args.item) 02408 args.item = "status"; 02409 02410 if (!(agent = find_agent(args.agentid))) { 02411 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02412 return -1; 02413 } 02414 02415 if (!strcasecmp(args.item, "status")) { 02416 char *status = "LOGGEDOUT"; 02417 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02418 status = "LOGGEDIN"; 02419 ast_copy_string(buf, status, len); 02420 } else if (!strcasecmp(args.item, "password")) 02421 ast_copy_string(buf, agent->password, len); 02422 else if (!strcasecmp(args.item, "name")) 02423 ast_copy_string(buf, agent->name, len); 02424 else if (!strcasecmp(args.item, "mohclass")) 02425 ast_copy_string(buf, agent->moh, len); 02426 else if (!strcasecmp(args.item, "channel")) { 02427 if (agent->chan) { 02428 ast_copy_string(buf, agent->chan->name, len); 02429 tmp = strrchr(buf, '-'); 02430 if (tmp) 02431 *tmp = '\0'; 02432 } 02433 } else if (!strcasecmp(args.item, "exten")) 02434 ast_copy_string(buf, agent->loginchan, len); 02435 02436 return 0; 02437 }
|
|
|
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 2462 of file chan_agent.c. References 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(), cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents(). 02463 { 02464 /* Make sure we can register our agent channel type */ 02465 if (ast_channel_register(&agent_tech)) { 02466 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02467 return -1; 02468 } 02469 /* Read in the config */ 02470 if (!read_agent_config()) 02471 return AST_MODULE_LOAD_DECLINE; 02472 if (persistent_agents) 02473 reload_agents(); 02474 /* Dialplan applications */ 02475 ast_register_application(app, login_exec, synopsis, descrip); 02476 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); 02477 02478 /* Manager commands */ 02479 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02480 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02481 02482 /* CLI Commands */ 02483 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry)); 02484 02485 /* Dialplan Functions */ 02486 ast_custom_function_register(&agent_function); 02487 02488 return 0; 02489 }
|
|
||||||||||||
|
Called by the AgentLogin application (from the dial plan).
Definition at line 2180 of file chan_agent.c. References __login_exec(), and ast_module_user::chan. Referenced by load_module(). 02181 { 02182 return __login_exec(chan, data, 0); 02183 }
|
|
|
Definition at line 1374 of file chan_agent.c.
|
|
|
Read configuration data. The file named agents.conf.
Definition at line 994 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(). 00995 { 00996 struct ast_config *cfg; 00997 struct ast_config *ucfg; 00998 struct ast_variable *v; 00999 struct agent_pvt *p; 01000 const char *general_val; 01001 const char *catname; 01002 const char *hasagent; 01003 int genhasagent; 01004 01005 group = 0; 01006 autologoff = 0; 01007 wrapuptime = 0; 01008 ackcall = 0; 01009 endcall = 1; 01010 cfg = ast_config_load(config); 01011 if (!cfg) { 01012 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01013 return 0; 01014 } 01015 AST_LIST_LOCK(&agents); 01016 AST_LIST_TRAVERSE(&agents, p, list) { 01017 p->dead = 1; 01018 } 01019 strcpy(moh, "default"); 01020 /* set the default recording values */ 01021 recordagentcalls = 0; 01022 strcpy(recordformat, "wav"); 01023 strcpy(recordformatext, "wav"); 01024 urlprefix[0] = '\0'; 01025 savecallsin[0] = '\0'; 01026 01027 /* Read in [general] section for persistence */ 01028 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01029 persistent_agents = ast_true(general_val); 01030 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01031 01032 /* Read in the [agents] section */ 01033 v = ast_variable_browse(cfg, "agents"); 01034 while(v) { 01035 /* Create the interface list */ 01036 if (!strcasecmp(v->name, "agent")) { 01037 add_agent(v->value, 0); 01038 } else if (!strcasecmp(v->name, "group")) { 01039 group = ast_get_group(v->value); 01040 } else if (!strcasecmp(v->name, "autologoff")) { 01041 autologoff = atoi(v->value); 01042 if (autologoff < 0) 01043 autologoff = 0; 01044 } else if (!strcasecmp(v->name, "ackcall")) { 01045 if (!strcasecmp(v->value, "always")) 01046 ackcall = 2; 01047 else if (ast_true(v->value)) 01048 ackcall = 1; 01049 else 01050 ackcall = 0; 01051 } else if (!strcasecmp(v->name, "endcall")) { 01052 endcall = ast_true(v->value); 01053 } else if (!strcasecmp(v->name, "wrapuptime")) { 01054 wrapuptime = atoi(v->value); 01055 if (wrapuptime < 0) 01056 wrapuptime = 0; 01057 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01058 maxlogintries = atoi(v->value); 01059 if (maxlogintries < 0) 01060 maxlogintries = 0; 01061 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01062 strcpy(agentgoodbye,v->value); 01063 } else if (!strcasecmp(v->name, "musiconhold")) { 01064 ast_copy_string(moh, v->value, sizeof(moh)); 01065 } else if (!strcasecmp(v->name, "updatecdr")) { 01066 if (ast_true(v->value)) 01067 updatecdr = 1; 01068 else 01069 updatecdr = 0; 01070 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01071 if (ast_true(v->value)) 01072 autologoffunavail = 1; 01073 else 01074 autologoffunavail = 0; 01075 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01076 recordagentcalls = ast_true(v->value); 01077 } else if (!strcasecmp(v->name, "recordformat")) { 01078 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01079 if (!strcasecmp(v->value, "wav49")) 01080 strcpy(recordformatext, "WAV"); 01081 else 01082 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01083 } else if (!strcasecmp(v->name, "urlprefix")) { 01084 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01085 if (urlprefix[strlen(urlprefix) - 1] != '/') 01086 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01087 } else if (!strcasecmp(v->name, "savecallsin")) { 01088 if (v->value[0] == '/') 01089 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01090 else 01091 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01092 if (savecallsin[strlen(savecallsin) - 1] != '/') 01093 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01094 } else if (!strcasecmp(v->name, "custom_beep")) { 01095 ast_copy_string(beep, v->value, sizeof(beep)); 01096 } 01097 v = v->next; 01098 } 01099 if ((ucfg = ast_config_load("users.conf"))) { 01100 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01101 catname = ast_category_browse(ucfg, NULL); 01102 while(catname) { 01103 if (strcasecmp(catname, "general")) { 01104 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01105 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01106 char tmp[256]; 01107 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01108 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01109 if (!fullname) 01110 fullname = ""; 01111 if (!secret) 01112 secret = ""; 01113 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01114 add_agent(tmp, 0); 01115 } 01116 } 01117 catname = ast_category_browse(ucfg, catname); 01118 } 01119 ast_config_destroy(ucfg); 01120 } 01121 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01122 if (p->dead) { 01123 AST_LIST_REMOVE_CURRENT(&agents, list); 01124 /* Destroy if appropriate */ 01125 if (!p->owner) { 01126 if (!p->chan) { 01127 ast_mutex_destroy(&p->lock); 01128 ast_mutex_destroy(&p->app_lock); 01129 free(p); 01130 } else { 01131 /* Cause them to hang up */ 01132 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01133 } 01134 } 01135 } 01136 } 01137 AST_LIST_TRAVERSE_SAFE_END 01138 AST_LIST_UNLOCK(&agents); 01139 ast_config_destroy(cfg); 01140 return 1; 01141 }
|
|
|
Definition at line 2491 of file chan_agent.c. References read_agent_config(), and reload_agents(). 02492 { 02493 read_agent_config(); 02494 if (persistent_agents) 02495 reload_agents(); 02496 return 0; 02497 }
|
|
|
Reload the persistent agents from astdb.
Definition at line 2277 of file chan_agent.c. References agent_pvt::agent, ast_db_del(), ast_db_get(), ast_db_gettree(), ast_device_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::lock, LOG_DEBUG, 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(). 02278 { 02279 char *agent_num; 02280 struct ast_db_entry *db_tree; 02281 struct ast_db_entry *entry; 02282 struct agent_pvt *cur_agent; 02283 char agent_data[256]; 02284 char *parse; 02285 char *agent_chan; 02286 char *agent_callerid; 02287 02288 db_tree = ast_db_gettree(pa_family, NULL); 02289 02290 AST_LIST_LOCK(&agents); 02291 for (entry = db_tree; entry; entry = entry->next) { 02292 agent_num = entry->key + strlen(pa_family) + 2; 02293 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02294 ast_mutex_lock(&cur_agent->lock); 02295 if (strcmp(agent_num, cur_agent->agent) == 0) 02296 break; 02297 ast_mutex_unlock(&cur_agent->lock); 02298 } 02299 if (!cur_agent) { 02300 ast_db_del(pa_family, agent_num); 02301 continue; 02302 } else 02303 ast_mutex_unlock(&cur_agent->lock); 02304 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02305 if (option_debug) 02306 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02307 parse = agent_data; 02308 agent_chan = strsep(&parse, ";"); 02309 agent_callerid = strsep(&parse, ";"); 02310 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02311 if (agent_callerid) { 02312 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02313 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02314 } else 02315 cur_agent->logincallerid[0] = '\0'; 02316 if (cur_agent->loginstart == 0) 02317 time(&cur_agent->loginstart); 02318 ast_device_state_changed("Agent/%s", cur_agent->agent); 02319 } 02320 } 02321 AST_LIST_UNLOCK(&agents); 02322 if (db_tree) { 02323 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02324 ast_db_freetree(db_tree); 02325 } 02326 }
|
|
||||||||||||
|
store/clear the global variable that stores agentid based on the callerid
Definition at line 706 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(). 00707 { 00708 char buf[AST_MAX_BUF]; 00709 00710 /* if there is no Caller ID, nothing to do */ 00711 if (ast_strlen_zero(callerid)) 00712 return; 00713 00714 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00715 pbx_builtin_setvar_helper(NULL, buf, agent); 00716 }
|
|
|
|
Definition at line 146 of file chan_agent.c. |
|
|
Definition at line 2439 of file chan_agent.c. Referenced by load_module(), and unload_module(). |
|
|
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 1723 of file chan_agent.c. |
|
|
Channel interface description for PBX integration.
Definition at line 247 of file chan_agent.c. Referenced by agent_new(), load_module(), and unload_module(). |
|
|
Definition at line 152 of file chan_agent.c. |
|
|
Definition at line 79 of file chan_agent.c. Referenced by action_originate(), add_extensions(), answer_exec_enable(), ast_pbx_run_app(), async_wait(), check_app_args(), check_pval_item(), feature_exec_app(), handle_context_add_extension(), handle_exec(), load_module(), pbx_builtin_execiftime(), pbx_exec(), pbx_extension_helper(), realtime_exec(), unload_module(), and unreference_cached_app(). |
|
|
Definition at line 80 of file chan_agent.c. |
|
|
Definition at line 144 of file chan_agent.c. |
|
|
Definition at line 149 of file chan_agent.c. |
|
|
Definition at line 160 of file chan_agent.c. |
|
|
Definition at line 1728 of file chan_agent.c. Referenced by load_module(), and unload_module(). |
|
|
|
Definition at line 85 of file chan_agent.c. Referenced by aji_handle_presence(), and load_module(). |
|
|
Definition at line 94 of file chan_agent.c. |
|
|
Definition at line 147 of file chan_agent.c. |
|
|
Definition at line 143 of file chan_agent.c. Referenced by ast_app_group_set_channel(), ast_get_group(), ast_makesocket(), and misdn_request(). |
|
|
Definition at line 122 of file chan_agent.c. |
|
|
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 116 of file chan_agent.c. |
|
|
Initial value: "Description: Will list info about all possible agents.\n" "Variables: NONE\n" Definition at line 112 of file chan_agent.c. |
|
|
Definition at line 151 of file chan_agent.c. |
|
|
Definition at line 131 of file chan_agent.c. Referenced by ast_moh_destroy(), get_mohbyname(), init_classes(), moh_generate(), moh_register(), moh_release(), mohalloc(), and monmp3thread(). |
|
|
Definition at line 148 of file chan_agent.c. |
|
|
Persistent Agents astdb family Definition at line 137 of file chan_agent.c. |
|
|
queues.conf [general] option Definition at line 140 of file chan_agent.c. |
|