![]() |
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) |