--- chan_agent.c 2004-02-18 18:15:50.000000000 -0800 +++ shady_agent.c 2004-02-18 18:15:09.000000000 -0800 @@ -43,6 +43,8 @@ #include #include +#include "postgresql/libpq-fe.h" + static char *desc = "Agent Proxy Channel"; static char *type = "Agent"; static char *tdesc = "Call Agent Proxy Channel"; @@ -50,11 +52,9 @@ static char *app = "AgentLogin"; static char *app2 = "AgentCallbackLogin"; -static char *app3 = "AgentMonitorOutgoing"; static char *synopsis = "Call agent login"; static char *synopsis2 = "Call agent callback login"; -static char *synopsis3 = "Record agent's outgoing call"; static char *descrip = " AgentLogin([AgentNo][|options]):\n" @@ -71,17 +71,14 @@ "The agent's callback extension is called (optionally with the specified\n" "context. \n"; -static char *descrip3 = -" AgentMonitorOutgoing([options]):\n" -"Tries to figure out the id of the agent who is placing outgoing call based on comparision of the callerid of the current interface and the global variable placed by the AgentCallbackLogin application. That's why it should be used only with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent instead of Monitor application. That have to be configured in the agents.conf file. Normally the app returns 0 unless the options are passed. Also if the callerid or the agentid are not specified it'll look for n+101 priority. The options are:\n" -" 'd' - make the app return -1 if there is an error condition and there is no extension n+101\n" -" 'c' - change the source channel in the CDR record for this call to agent/agent_id so that we know which agent generates the call\n" -" 'n' - don't generate the warnings when there is no callerid or the agentid is not known. It's handy if you want to have one context for agent and non-agent calls.\n"; - static char moh[80] = "default"; #define AST_MAX_AGENT 80 /* Agent ID or Password max length */ -#define AST_MAX_BUF 256 + +static PGconn *shady; +char pg_conn[AST_MAX_AGENT]; +char pg_rtbl[AST_MAX_AGENT]; +char pg_avw[AST_MAX_AGENT]; static int capability = -1; @@ -96,15 +93,6 @@ /* Protect the interface list (of sip_pvt's) */ static ast_mutex_t agentlock = AST_MUTEX_INITIALIZER; -static int recordagentcalls = 0; -static char recordformat[AST_MAX_BUF]; -static char recordformatext[AST_MAX_BUF]; -static int createlink = 0; -static char urlprefix[AST_MAX_BUF]; -static char savecallsin[AST_MAX_BUF]; - -#define GETAGENTBYCALLERID "AGENTBYCALLERID" - static struct agent_pvt { ast_mutex_t lock; /* Channel private lock */ int dead; /* Poised for destruction? */ @@ -183,7 +171,7 @@ static struct agent_pvt *add_agent(char *agent, int pending) { - char tmp[AST_MAX_BUF]; + char tmp[256]; char *password=NULL, *name=NULL; struct agent_pvt *p, *prev; @@ -263,39 +251,6 @@ return -1; } -static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock) -{ - char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; - char filename[AST_MAX_BUF]; - int res = -1; - if (!p) - return -1; - if (!ast->monitor) { - snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); - /* substitute . for - */ - if ((pointer = strchr(filename, '.'))) - *pointer = '-'; - snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename); - ast_monitor_start(ast, recordformat, tmp, needlock); - ast_monitor_setjoinfiles(ast, 1); - snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext); -#if 0 - ast_verbose("name is %s, link is %s\n",tmp, tmp2); -#endif - if (!ast->cdr) - ast->cdr = ast_cdr_alloc(); - ast_cdr_setuserfield(ast, tmp2); - res = 0; - } else - ast_log(LOG_ERROR, "Recording already started on that call.\n"); - return res; -} - -static int agent_start_monitoring(struct ast_channel *ast, int needlock) -{ - return __agent_start_monitoring(ast, ast->pvt->pvt, needlock); -} - static struct ast_frame *agent_read(struct ast_channel *ast) { struct agent_pvt *p = ast->pvt->pvt; @@ -354,8 +309,6 @@ } CLEANUP(ast,p); ast_mutex_unlock(&p->lock); - if (recordagentcalls && f == &answer_frame) - agent_start_monitoring(ast,0); return f; } @@ -422,6 +375,7 @@ static int agent_call(struct ast_channel *ast, char *dest, int timeout) { + char act[256] = ""; struct agent_pvt *p = ast->pvt->pvt; int res = -1; ast_mutex_lock(&p->lock); @@ -479,13 +433,17 @@ } if( !res ) { + + // we need to copy the account code from the queue'd channel + // after calling the agent so it can be referred to by shady dial + strncpy(act, (char *)p->owner->accountcode, sizeof(act) - 1); + ast_cdr_setaccount(p->chan, strlen(act) ? act : NULL); + /* Call is immediately up, or might need ack */ if (p->ackcall > 1) ast_setstate(ast, AST_STATE_RINGING); else { ast_setstate(ast, AST_STATE_UP); - if (recordagentcalls) - agent_start_monitoring(ast,0); p->acknowledged = 1; } res = 0; @@ -497,6 +455,14 @@ static int agent_hangup(struct ast_channel *ast) { + + int res = 0; + char qry[384]; + PGresult *viva; + char rescode[AST_MAX_AGENT] = "0"; + char blankcode[AST_MAX_AGENT] = "0"; + char salecode[AST_MAX_AGENT] = "5"; + struct agent_pvt *p = ast->pvt->pvt; int howlong = 0; ast_mutex_lock(&p->lock); @@ -525,6 +491,27 @@ ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); ast_mutex_unlock(&p->chan->lock); } else { + + res = ast_app_getdata(p->chan, "slimagent-result", rescode, sizeof(rescode) - 1, 10000); + if (res<0 || strcmp(rescode,blankcode)==0) { + sprintf(qry, "INSERT INTO %s (agent_id,campaign_id,phone,channel,result) VALUES (%s,1,'%s','%s','0');\n", pg_rtbl, p->agent, p->chan->accountcode, p->chan->name); + } else { + sprintf(qry, "INSERT INTO %s (agent_id,campaign_id,phone,channel,result) VALUES (%s,1,'%s','%s','%s');\n", pg_rtbl, p->agent, p->chan->accountcode, p->chan->name, rescode); + } + viva = PQexec(shady, qry); + PQclear(viva); + + if (p->chan->accountcode && strcmp(rescode,salecode)==0) { + res = ast_streamfile(p->chan, "slimagent-thankyou", p->chan->language); + if (!res) + ast_waitstream(p->chan, ""); + res = ast_say_digit_str(p->chan, p->chan->accountcode, "", p->chan->language); + res = ast_streamfile(p->chan, "slimagent-repeat", p->chan->language); + if (!res) + ast_waitstream(p->chan, ""); + res = ast_say_digit_str(p->chan, p->chan->accountcode, "", p->chan->language); + } + ast_mutex_lock(&p->chan->lock); ast_moh_start(p->chan, p->moh); ast_mutex_unlock(&p->chan->lock); @@ -738,8 +725,40 @@ } +static int slim_pg_init() +{ + PGresult *viva; + int res=0; + int nres; + int tups; + char qry[384]; + char *agent; + + /* First we add the agents */ + sprintf(qry, "SELECT agent FROM %s;\n", pg_avw); + viva = PQexec(shady, qry); + if(!viva) { + ast_log(LOG_WARNING, "Slim agent error querying agents with '%s'. PostgreSQL error: %s\n", qry, PQerrorMessage(shady)); + res = -1; + } else { + nres = PQntuples(viva); + for(tups=0; tupsnext; } strcpy(moh, "default"); - /* set the default recording values */ - recordagentcalls = 0; - createlink = 0; - strcpy(recordformat, "wav"); - strcpy(recordformatext, "wav"); - strcpy(urlprefix, ""); - strcpy(savecallsin, ""); + + conn = ast_variable_retrieve(cfg, "global", "connection"); + avw = ast_variable_retrieve(cfg, "global", "agentview"); + rtbl = ast_variable_retrieve(cfg, "global", "resulttable"); + + strcpy(pg_conn, conn); + strcpy(pg_rtbl, rtbl); + strcpy(pg_avw, avw); + + shady = PQconnectdb(conn); + + slim_pg_init(); v = ast_variable_browse(cfg, "agents"); while(v) { @@ -791,27 +815,6 @@ wrapuptime = 0; } else if (!strcasecmp(v->name, "musiconhold")) { strncpy(moh, v->value, sizeof(moh) - 1); - } else if (!strcasecmp(v->name, "recordagentcalls")) { - recordagentcalls = ast_true(v->value); - } else if (!strcasecmp(v->name, "createlink")) { - createlink = ast_true(v->value); - } else if (!strcasecmp(v->name, "recordformat")) { - strncpy(recordformat, v->value, sizeof(recordformat) - 1); - if (!strcasecmp(v->value, "wav49")) - strcpy(recordformatext, "WAV"); - else - strncpy(recordformatext, v->value, sizeof(recordformat) - 1); - } else if (!strcasecmp(v->name, "urlprefix")) { - strncpy(urlprefix, v->value, sizeof(urlprefix) - 2); - if (urlprefix[strlen(urlprefix) - 1] != '/') - strcat(urlprefix, "/"); - } else if (!strcasecmp(v->name, "savecallsin")) { - if (v->value[0] == '/') - strncpy(savecallsin, v->value, sizeof(savecallsin) - 2); - else - snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); - if (savecallsin[strlen(savecallsin) - 1] != '/') - strcat(savecallsin, "/"); } v = v->next; } @@ -1050,10 +1053,10 @@ static int agents_show(int fd, int argc, char **argv) { struct agent_pvt *p; - char username[AST_MAX_BUF]; - char location[AST_MAX_BUF]; - char talkingto[AST_MAX_BUF]; - char moh[AST_MAX_BUF]; + char username[256]; + char location[256]; + char talkingto[256]; + char moh[256]; if (argc != 2) return RESULT_SHOWUSAGE; @@ -1099,6 +1102,38 @@ return RESULT_SUCCESS; } +static int agents_show_short( struct mansession *s, struct message *m ) +{ + int fd; + int talking=0; + int waiting=0; + struct agent_pvt *p; + if (s) { + fd = s->fd; + } else { + return 0; + } + + ast_mutex_lock(&agentlock); + p = agents; + while(p) { + ast_mutex_lock(&p->lock); + if (p->chan) { + if (p->owner && p->owner->bridge) { + talking++; + } else { + waiting++; + } + } + ast_mutex_unlock(&p->lock); + p = p->next; + } + ast_mutex_unlock(&agentlock); + ast_cli(fd, "Talking: %d\r\n", talking); + ast_cli(fd, "Waiting: %d\r\n\n", waiting); + return RESULT_SUCCESS; +} + static char show_agents_usage[] = "Usage: show agents\n" " Provides summary information on agents.\n"; @@ -1107,6 +1142,7 @@ { "show", "agents", NULL }, agents_show, "Show status of agents", show_agents_usage, NULL }; + STANDARD_LOCAL_USER; LOCAL_USER_DECL; @@ -1117,10 +1153,8 @@ struct agent_pvt *p; struct localuser *u; struct timeval tv; - time_t start; char user[AST_MAX_AGENT]; char pass[AST_MAX_AGENT]; - char agent[AST_MAX_AGENT] = ""; char xpass[AST_MAX_AGENT] = ""; char *errmsg; char info[512]; @@ -1129,7 +1163,7 @@ char *context = NULL; char *exten = NULL; int play_announcement; - char *filename = "agent-loginok"; + char *filename = "slimagent-loginok"; LOCAL_USER_ADD(u); @@ -1161,7 +1195,7 @@ if( opt_user && strlen(opt_user)) strncpy( user, opt_user, AST_MAX_AGENT ); else - res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); + res = ast_app_getdata(chan, "slimagent-welcome", user, sizeof(user) - 1, 0); } while (!res && (tries < 3)) { /* Check for password */ @@ -1175,11 +1209,11 @@ ast_mutex_unlock(&agentlock); if (!res) { if (strlen(xpass)) - res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); + res = ast_app_getdata(chan, "slimagent-pass", pass, sizeof(pass) - 1, 0); else strcpy(pass, ""); } - errmsg = "agent-incorrect"; + errmsg = "slimagent-incorrect"; #if 0 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); @@ -1194,7 +1228,7 @@ !strcmp(p->password, pass) && !p->pending) { if (!p->chan) { if (callbackmode) { - char tmpchan[AST_MAX_BUF] = ""; + char tmpchan[256] = ""; int pos = 0; /* Retrieve login chan */ for (;;) { @@ -1232,15 +1266,6 @@ if (!strlen(p->loginchan)) filename = "agent-loggedoff"; p->acknowledged = 0; - /* store/clear the global variable that stores agentid based on the callerid */ - if (chan->callerid) { - char agentvar[AST_MAX_BUF]; - snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid); - if (!strlen(p->loginchan)) - pbx_builtin_setvar_helper(NULL, agentvar, NULL); - else - pbx_builtin_setvar_helper(NULL, agentvar, p->agent); - } } } else { strcpy(p->loginchan, ""); @@ -1250,14 +1275,10 @@ if( options ) if( strchr( options, 's' ) ) play_announcement = 0; - ast_mutex_unlock(&p->lock); - ast_mutex_unlock(&agentlock); if( !res && play_announcement ) res = ast_streamfile(chan, filename, chan->language); if (!res) ast_waitstream(chan, ""); - ast_mutex_lock(&agentlock); - ast_mutex_lock(&p->lock); if (!res) { res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); if (res) @@ -1273,7 +1294,6 @@ res = -1; if (callbackmode && !res) { /* Just say goodbye and be done with it */ - ast_mutex_unlock(&agentlock); if (!res) res = ast_safe_sleep(chan, 500); res = ast_streamfile(chan, "vm-goodbye", chan->language); @@ -1282,6 +1302,7 @@ if (!res) res = ast_safe_sleep(chan, 1000); ast_mutex_unlock(&p->lock); + ast_mutex_unlock(&agentlock); } else if (!res) { #ifdef HONOR_MUSIC_CLASS /* check if the moh class was changed with setmusiconhold */ @@ -1293,9 +1314,6 @@ "Agent: %s\r\n" "Channel: %s\r\n", p->agent, chan->name); - time(&start); - snprintf(agent, sizeof(agent), "Agent/%s", p->agent); - ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent, ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); @@ -1365,7 +1383,6 @@ ast_mutex_unlock(&p->lock); if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent); - ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, (long)(time(NULL) - start)); manager_event(EVENT_FLAG_AGENT, "Agentlogoff", "Agent: %s\r\n", p->agent); @@ -1410,62 +1427,6 @@ return __login_exec(chan, data, 1); } -static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data) -{ - int exitifnoagentid = 0; - int nowarnings = 0; - int updatecdr = 0; - int res = 0; - char agent[AST_MAX_AGENT], *tmp; - if (data) { - if (strchr(data, 'd')) - exitifnoagentid = 1; - if (strchr(data, 'n')) - nowarnings = 1; - if (strchr(data, 'c')) - updatecdr = 1; - } - if (chan->callerid) { - char agentvar[AST_MAX_BUF]; - snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->callerid); - if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { - struct agent_pvt *p = agents; - strncpy(agent, tmp, sizeof(agent) - 1); - ast_mutex_lock(&agentlock); - while (p) { - if (!strcasecmp(p->agent, tmp)) { - __agent_start_monitoring(chan, p, 1); - if (updatecdr && chan->cdr) { - snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); - } - break; - } - p = p->next; - } - ast_mutex_unlock(&agentlock); - - } else { - res = -1; - if (!nowarnings) - 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); - } - } else { - res = -1; - if (!nowarnings) - 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"); - } - /* check if there is n + 101 priority */ - if (res) { - if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) { - chan->priority+=100; - ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority); - } - else if (exitifnoagentid) - return res; - } - return 0; -} - int load_module() { /* Make sure we can register our sip channel type */ @@ -1475,8 +1436,10 @@ } ast_register_application(app, login_exec, synopsis, descrip); ast_register_application(app2, callback_exec, synopsis2, descrip2); - ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3); ast_cli_register(&cli_show_agents); + + ast_manager_register( "ShowAgentsShort", 0, agents_show_short, "ShowAgentsShort" ); + /* Read in the config */ read_agent_config(); return 0; @@ -1484,7 +1447,9 @@ int reload() { - read_agent_config(); + //read_agent_config(); + unload_module(); + load_module(); return 0; } @@ -1493,9 +1458,11 @@ struct agent_pvt *p; /* First, take us out of the channel loop */ ast_cli_unregister(&cli_show_agents); + + PQfinish(shady); + ast_unregister_application(app); ast_unregister_application(app2); - ast_unregister_application(app3); ast_channel_unregister(type); if (!ast_mutex_lock(&agentlock)) { /* Hangup all interfaces if they have an owner */