00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 314908 $")
00040
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <errno.h>
00044 #include <unistd.h>
00045 #include <sys/socket.h>
00046 #include <stdlib.h>
00047 #include <fcntl.h>
00048 #include <netdb.h>
00049 #include <netinet/in.h>
00050 #include <arpa/inet.h>
00051 #include <sys/signal.h>
00052
00053 #include "asterisk/lock.h"
00054 #include "asterisk/channel.h"
00055 #include "asterisk/config.h"
00056 #include "asterisk/logger.h"
00057 #include "asterisk/module.h"
00058 #include "asterisk/pbx.h"
00059 #include "asterisk/options.h"
00060 #include "asterisk/lock.h"
00061 #include "asterisk/sched.h"
00062 #include "asterisk/io.h"
00063 #include "asterisk/rtp.h"
00064 #include "asterisk/acl.h"
00065 #include "asterisk/callerid.h"
00066 #include "asterisk/file.h"
00067 #include "asterisk/cli.h"
00068 #include "asterisk/app.h"
00069 #include "asterisk/musiconhold.h"
00070 #include "asterisk/manager.h"
00071 #include "asterisk/features.h"
00072 #include "asterisk/utils.h"
00073 #include "asterisk/causes.h"
00074 #include "asterisk/astdb.h"
00075 #include "asterisk/devicestate.h"
00076 #include "asterisk/monitor.h"
00077 #include "asterisk/stringfields.h"
00078
00079 static const char tdesc[] = "Call Agent Proxy Channel";
00080 static const char config[] = "agents.conf";
00081
00082 static const char app[] = "AgentLogin";
00083 static const char app2[] = "AgentCallbackLogin";
00084 static const char app3[] = "AgentMonitorOutgoing";
00085
00086 static const char synopsis[] = "Call agent login";
00087 static const char synopsis2[] = "Call agent callback login";
00088 static const char synopsis3[] = "Record agent's outgoing call";
00089
00090 static const char descrip[] =
00091 " AgentLogin([AgentNo][|options]):\n"
00092 "Asks the agent to login to the system. Always returns -1. While\n"
00093 "logged in, the agent can receive calls and will hear a 'beep'\n"
00094 "when a new call comes in. The agent can dump the call by pressing\n"
00095 "the star key.\n"
00096 "The option string may contain zero or more of the following characters:\n"
00097 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
00098
00099 static const char descrip2[] =
00100 " AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]):\n"
00101 "Asks the agent to login to the system with callback.\n"
00102 "The agent's callback extension is called (optionally with the specified\n"
00103 "context).\n"
00104 "The option string may contain zero or more of the following characters:\n"
00105 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
00106
00107 static const char descrip3[] =
00108 " AgentMonitorOutgoing([options]):\n"
00109 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
00110 "comparison of the callerid of the current interface and the global variable \n"
00111 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
00112 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
00113 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
00114 "\nReturn value:\n"
00115 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
00116 "the agentid are not specified it'll look for n+101 priority.\n"
00117 "\nOptions:\n"
00118 " 'd' - make the app return -1 if there is an error condition and there is\n"
00119 " no extension n+101\n"
00120 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
00121 " 'n' - don't generate the warnings when there is no callerid or the\n"
00122 " agentid is not known.\n"
00123 " It's handy if you want to have one context for agent and non-agent calls.\n";
00124
00125 static const char mandescr_agents[] =
00126 "Description: Will list info about all possible agents.\n"
00127 "Variables: NONE\n";
00128
00129 static const char mandescr_agent_logoff[] =
00130 "Description: Sets an agent as no longer logged in.\n"
00131 "Variables: (Names marked with * are required)\n"
00132 " *Agent: Agent ID of the agent to log off\n"
00133 " Soft: Set to 'true' to not hangup existing calls\n";
00134
00135 static const char mandescr_agent_callback_login[] =
00136 "Description: Sets an agent as logged in with callback.\n"
00137 "Variables: (Names marked with * are required)\n"
00138 " *Agent: Agent ID of the agent to login\n"
00139 " *Exten: Extension to use for callback\n"
00140 " Context: Context to use for callback\n"
00141 " AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
00142 " WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
00143
00144 static char moh[80] = "default";
00145
00146 #define AST_MAX_AGENT 80
00147 #define AST_MAX_BUF 256
00148 #define AST_MAX_FILENAME_LEN 256
00149
00150 static const char pa_family[] = "Agents";
00151 #define PA_MAX_LEN 2048
00152
00153 static int persistent_agents = 0;
00154 static void dump_agents(void);
00155
00156 static ast_group_t group;
00157 static int autologoff;
00158 static int wrapuptime;
00159 static int ackcall;
00160 static int endcall;
00161 static int multiplelogin = 1;
00162 static int autologoffunavail = 0;
00163
00164 static int maxlogintries = 3;
00165 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
00166
00167 static int recordagentcalls = 0;
00168 static char recordformat[AST_MAX_BUF] = "";
00169 static char recordformatext[AST_MAX_BUF] = "";
00170 static char urlprefix[AST_MAX_BUF] = "";
00171 static char savecallsin[AST_MAX_BUF] = "";
00172 static int updatecdr = 0;
00173 static char beep[AST_MAX_BUF] = "beep";
00174
00175 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
00176
00177
00178 struct agent_pvt {
00179 ast_mutex_t lock;
00180 int dead;
00181 int pending;
00182 int abouttograb;
00183 int autologoff;
00184 int ackcall;
00185 int deferlogoff;
00186 time_t loginstart;
00187 time_t start;
00188 struct timeval lastdisc;
00189 int wrapuptime;
00190 ast_group_t group;
00191 int acknowledged;
00192 char moh[80];
00193 char agent[AST_MAX_AGENT];
00194 char password[AST_MAX_AGENT];
00195 char name[AST_MAX_AGENT];
00196 int inherited_devicestate;
00197 int app_lock_flag;
00198 ast_cond_t app_complete_cond;
00199 ast_cond_t login_wait_cond;
00200 volatile int app_sleep_cond;
00201 struct ast_channel *owner;
00202
00203
00204
00205 char loginchan[80];
00206 char logincallerid[80];
00207 struct ast_channel *chan;
00208 AST_LIST_ENTRY(agent_pvt) list;
00209 };
00210
00211 static AST_LIST_HEAD_STATIC(agents, agent_pvt);
00212
00213 #define CHECK_FORMATS(ast, p) do { \
00214 if (p->chan) {\
00215 if (ast->nativeformats != p->chan->nativeformats) { \
00216 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
00217 \
00218 ast->nativeformats = p->chan->nativeformats; \
00219 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
00220 ast_set_read_format(ast, ast->readformat); \
00221 ast_set_write_format(ast, ast->writeformat); \
00222 } \
00223 if (p->chan->readformat != ast->rawreadformat && !p->chan->generator) \
00224 ast_set_read_format(p->chan, ast->rawreadformat); \
00225 if (p->chan->writeformat != ast->rawwriteformat && !p->chan->generator) \
00226 ast_set_write_format(p->chan, ast->rawwriteformat); \
00227 } \
00228 } while(0)
00229
00230
00231
00232
00233
00234 #define CLEANUP(ast, p) do { \
00235 int x; \
00236 if (p->chan) { \
00237 for (x=0;x<AST_MAX_FDS;x++) {\
00238 if (x != AST_TIMING_FD) \
00239 ast->fds[x] = p->chan->fds[x]; \
00240 } \
00241 ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
00242 } \
00243 } while(0)
00244
00245
00246 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
00247 static int agent_devicestate(void *data);
00248 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
00249 static int agent_digit_begin(struct ast_channel *ast, char digit);
00250 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00251 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
00252 static int agent_hangup(struct ast_channel *ast);
00253 static int agent_answer(struct ast_channel *ast);
00254 static struct ast_frame *agent_read(struct ast_channel *ast);
00255 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
00256 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00257 static int agent_sendtext(struct ast_channel *ast, const char *text);
00258 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00259 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00260 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00261 static void set_agentbycallerid(const char *callerid, const char *agent);
00262 static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
00263 static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
00264 static int agent_logoff(const char *agent, int soft);
00265
00266
00267 static const struct ast_channel_tech agent_tech = {
00268 .type = "Agent",
00269 .description = tdesc,
00270 .capabilities = -1,
00271 .requester = agent_request,
00272 .devicestate = agent_devicestate,
00273 .send_digit_begin = agent_digit_begin,
00274 .send_digit_end = agent_digit_end,
00275 .call = agent_call,
00276 .hangup = agent_hangup,
00277 .answer = agent_answer,
00278 .read = agent_read,
00279 .write = agent_write,
00280 .write_video = agent_write,
00281 .send_html = agent_sendhtml,
00282 .send_text = agent_sendtext,
00283 .exception = agent_read,
00284 .indicate = agent_indicate,
00285 .fixup = agent_fixup,
00286 .bridged_channel = agent_bridgedchannel,
00287 .get_base_channel = agent_get_base_channel,
00288 .set_base_channel = agent_set_base_channel,
00289 };
00290
00291 static int agent_devicestate_cb(const char *dev, int state, void *data)
00292 {
00293 int res, i;
00294 struct agent_pvt *p;
00295 char basename[AST_CHANNEL_NAME], *tmp;
00296
00297
00298 if (!strncasecmp(dev, "Agent/", 6)) {
00299 return 0;
00300 }
00301
00302
00303 for (i = 0; i < 10; i++) {
00304 if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
00305 break;
00306 }
00307 }
00308 if (res) {
00309 return -1;
00310 }
00311
00312 AST_LIST_TRAVERSE(&agents, p, list) {
00313 ast_mutex_lock(&p->lock);
00314 if (p->chan && !ast_strlen_zero(p->loginchan)) {
00315 ast_copy_string(basename, p->chan->name, sizeof(basename));
00316 if ((tmp = strrchr(basename, '-'))) {
00317 *tmp = '\0';
00318 }
00319 if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) {
00320 p->inherited_devicestate = state;
00321 ast_device_state_changed("Agent/%s", p->agent);
00322 }
00323 }
00324 ast_mutex_unlock(&p->lock);
00325 }
00326 AST_LIST_UNLOCK(&agents);
00327 return 0;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338 static struct agent_pvt *add_agent(char *agent, int pending)
00339 {
00340 char *parse;
00341 AST_DECLARE_APP_ARGS(args,
00342 AST_APP_ARG(agt);
00343 AST_APP_ARG(password);
00344 AST_APP_ARG(name);
00345 );
00346 char *password = NULL;
00347 char *name = NULL;
00348 char *agt = NULL;
00349 struct agent_pvt *p;
00350
00351 parse = ast_strdupa(agent);
00352
00353
00354 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
00355
00356 if(args.argc == 0) {
00357 ast_log(LOG_WARNING, "A blank agent line!\n");
00358 return NULL;
00359 }
00360
00361 if(ast_strlen_zero(args.agt) ) {
00362 ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00363 return NULL;
00364 } else
00365 agt = args.agt;
00366
00367 if(!ast_strlen_zero(args.password)) {
00368 password = args.password;
00369 while (*password && *password < 33) password++;
00370 }
00371 if(!ast_strlen_zero(args.name)) {
00372 name = args.name;
00373 while (*name && *name < 33) name++;
00374 }
00375
00376
00377 AST_LIST_TRAVERSE(&agents, p, list) {
00378 if (!pending && !strcmp(p->agent, agt))
00379 break;
00380 }
00381 if (!p) {
00382
00383 if (!(p = ast_calloc(1, sizeof(*p))))
00384 return NULL;
00385 ast_copy_string(p->agent, agt, sizeof(p->agent));
00386 ast_mutex_init(&p->lock);
00387 ast_cond_init(&p->app_complete_cond, NULL);
00388 ast_cond_init(&p->login_wait_cond, NULL);
00389 p->app_lock_flag = 0;
00390 p->app_sleep_cond = 1;
00391 memcpy(&p->group, group, sizeof(p->group));
00392 p->pending = pending;
00393 p->inherited_devicestate = -1;
00394 AST_LIST_INSERT_TAIL(&agents, p, list);
00395 }
00396
00397 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00398 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00399 ast_copy_string(p->moh, moh, sizeof(p->moh));
00400 p->ackcall = ackcall;
00401 p->autologoff = autologoff;
00402
00403
00404
00405 if (p->wrapuptime > wrapuptime) {
00406 struct timeval now = ast_tvnow();
00407
00408
00409
00410 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00411 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00412 p->lastdisc.tv_usec = now.tv_usec;
00413 }
00414 }
00415 p->wrapuptime = wrapuptime;
00416
00417 if (pending)
00418 p->dead = 1;
00419 else
00420 p->dead = 0;
00421 return p;
00422 }
00423
00424
00425
00426
00427
00428
00429
00430 static int agent_cleanup(struct agent_pvt *p)
00431 {
00432 struct ast_channel *chan = NULL;
00433 ast_mutex_lock(&p->lock);
00434 chan = p->owner;
00435 p->owner = NULL;
00436 chan->tech_pvt = NULL;
00437
00438 p->app_sleep_cond = 1;
00439 p->app_lock_flag = 0;
00440 ast_cond_signal(&p->app_complete_cond);
00441 if (chan)
00442 ast_channel_free(chan);
00443 if (p->dead) {
00444 ast_mutex_unlock(&p->lock);
00445 ast_mutex_destroy(&p->lock);
00446 ast_cond_destroy(&p->app_complete_cond);
00447 ast_cond_destroy(&p->login_wait_cond);
00448 free(p);
00449 } else {
00450 ast_mutex_unlock(&p->lock);
00451 }
00452 return 0;
00453 }
00454
00455 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
00456
00457 static int agent_answer(struct ast_channel *ast)
00458 {
00459 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
00460 return -1;
00461 }
00462
00463 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
00464 {
00465 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00466 char filename[AST_MAX_BUF];
00467 int res = -1;
00468 if (!p)
00469 return -1;
00470 if (!ast->monitor) {
00471 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00472
00473 if ((pointer = strchr(filename, '.')))
00474 *pointer = '-';
00475 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00476 ast_monitor_start(ast, recordformat, tmp, needlock);
00477 ast_monitor_setjoinfiles(ast, 1);
00478 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00479 #if 0
00480 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00481 #endif
00482 if (!ast->cdr)
00483 ast->cdr = ast_cdr_alloc();
00484 ast_cdr_setuserfield(ast, tmp2);
00485 res = 0;
00486 } else
00487 ast_log(LOG_ERROR, "Recording already started on that call.\n");
00488 return res;
00489 }
00490
00491 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
00492 {
00493 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00494 }
00495
00496 static struct ast_frame *agent_read(struct ast_channel *ast)
00497 {
00498 struct agent_pvt *p = ast->tech_pvt;
00499 struct ast_frame *f = NULL;
00500 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00501 const char *status;
00502 int cur_time = time(NULL);
00503 ast_mutex_lock(&p->lock);
00504 CHECK_FORMATS(ast, p);
00505 if (!p->start) {
00506 p->start = cur_time;
00507 }
00508 if (p->chan) {
00509 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00510 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00511 f = ast_read(p->chan);
00512 } else
00513 f = &ast_null_frame;
00514 if (!f) {
00515
00516 if (p->chan) {
00517 p->chan->_bridge = NULL;
00518
00519
00520 if (!ast_strlen_zero(p->loginchan)) {
00521 if (p->chan)
00522 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00523 if (p->owner->_state != AST_STATE_UP) {
00524 int howlong = cur_time - p->start;
00525 if (p->autologoff && howlong >= p->autologoff) {
00526 p->loginstart = 0;
00527 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00528 agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff");
00529 }
00530 }
00531 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00532 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00533 long logintime = cur_time - p->loginstart;
00534 p->loginstart = 0;
00535 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
00536 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00537 }
00538 ast_hangup(p->chan);
00539 if (p->wrapuptime && p->acknowledged)
00540 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00541 }
00542 p->chan = NULL;
00543 p->inherited_devicestate = -1;
00544 ast_device_state_changed("Agent/%s", p->agent);
00545 p->acknowledged = 0;
00546 }
00547 } else {
00548
00549
00550 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00551 p->acknowledged = 1;
00552 }
00553 if (!p->acknowledged) {
00554 int howlong = cur_time - p->start;
00555 if (p->autologoff && (howlong >= p->autologoff)) {
00556 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00557 agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff");
00558 if (p->owner || p->chan) {
00559 while (p->owner && ast_channel_trylock(p->owner)) {
00560 DEADLOCK_AVOIDANCE(&p->lock);
00561 }
00562 if (p->owner) {
00563 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
00564 ast_channel_unlock(p->owner);
00565 }
00566
00567 while (p->chan && ast_channel_trylock(p->chan)) {
00568 DEADLOCK_AVOIDANCE(&p->lock);
00569 }
00570 if (p->chan) {
00571 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00572 ast_channel_unlock(p->chan);
00573 }
00574 } else {
00575 long logintime;
00576 logintime = time(NULL) - p->loginstart;
00577 p->loginstart = 0;
00578 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
00579 }
00580 }
00581 }
00582 switch (f->frametype) {
00583 case AST_FRAME_CONTROL:
00584 if (f->subclass == AST_CONTROL_ANSWER) {
00585 if (p->ackcall) {
00586 if (option_verbose > 2)
00587 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
00588
00589 ast_frfree(f);
00590 f = &ast_null_frame;
00591 } else {
00592 p->acknowledged = 1;
00593
00594
00595 ast_frfree(f);
00596 f = &answer_frame;
00597 }
00598 }
00599 break;
00600 case AST_FRAME_DTMF_BEGIN:
00601
00602 if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){
00603 ast_frfree(f);
00604 f = &ast_null_frame;
00605 }
00606 break;
00607 case AST_FRAME_DTMF_END:
00608 if (!p->acknowledged && (f->subclass == '#')) {
00609 if (option_verbose > 2)
00610 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
00611 p->acknowledged = 1;
00612 ast_frfree(f);
00613 f = &answer_frame;
00614 } else if (f->subclass == '*' && endcall) {
00615
00616 ast_frfree(f);
00617 f = NULL;
00618 }
00619 break;
00620 case AST_FRAME_VOICE:
00621 case AST_FRAME_VIDEO:
00622
00623 if (!p->acknowledged) {
00624 ast_frfree(f);
00625 f = &ast_null_frame;
00626 }
00627 default:
00628
00629 break;
00630 }
00631 }
00632
00633 CLEANUP(ast,p);
00634 if (p->chan && !p->chan->_bridge) {
00635 if (strcasecmp(p->chan->tech->type, "Local")) {
00636 p->chan->_bridge = ast;
00637 if (p->chan)
00638 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00639 }
00640 }
00641 ast_mutex_unlock(&p->lock);
00642 if (recordagentcalls && f == &answer_frame)
00643 agent_start_monitoring(ast,0);
00644 return f;
00645 }
00646
00647 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00648 {
00649 struct agent_pvt *p = ast->tech_pvt;
00650 int res = -1;
00651 ast_mutex_lock(&p->lock);
00652 if (p->chan)
00653 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00654 ast_mutex_unlock(&p->lock);
00655 return res;
00656 }
00657
00658 static int agent_sendtext(struct ast_channel *ast, const char *text)
00659 {
00660 struct agent_pvt *p = ast->tech_pvt;
00661 int res = -1;
00662 ast_mutex_lock(&p->lock);
00663 if (p->chan)
00664 res = ast_sendtext(p->chan, text);
00665 ast_mutex_unlock(&p->lock);
00666 return res;
00667 }
00668
00669 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
00670 {
00671 struct agent_pvt *p = ast->tech_pvt;
00672 int res = -1;
00673 CHECK_FORMATS(ast, p);
00674 ast_mutex_lock(&p->lock);
00675 if (!p->chan)
00676 res = 0;
00677 else {
00678 if ((f->frametype != AST_FRAME_VOICE) ||
00679 (f->frametype != AST_FRAME_VIDEO) ||
00680 (f->subclass == p->chan->writeformat)) {
00681 res = ast_write(p->chan, f);
00682 } else {
00683 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n",
00684 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00685 ast->name, p->chan->name);
00686 res = 0;
00687 }
00688 }
00689 CLEANUP(ast, p);
00690 ast_mutex_unlock(&p->lock);
00691 return res;
00692 }
00693
00694 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00695 {
00696 struct agent_pvt *p = newchan->tech_pvt;
00697 ast_mutex_lock(&p->lock);
00698 if (p->owner != oldchan) {
00699 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00700 ast_mutex_unlock(&p->lock);
00701 return -1;
00702 }
00703 p->owner = newchan;
00704 ast_mutex_unlock(&p->lock);
00705 return 0;
00706 }
00707
00708 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00709 {
00710 struct agent_pvt *p = ast->tech_pvt;
00711 int res = -1;
00712 ast_mutex_lock(&p->lock);
00713 if (p->chan && !ast_check_hangup(p->chan)) {
00714 while (ast_channel_trylock(p->chan)) {
00715 int res;
00716 if ((res = ast_channel_unlock(ast))) {
00717 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res));
00718 ast_mutex_unlock(&p->lock);
00719 return -1;
00720 }
00721 usleep(1);
00722 ast_channel_lock(ast);
00723 }
00724 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00725 ast_channel_unlock(p->chan);
00726 } else
00727 res = 0;
00728 ast_mutex_unlock(&p->lock);
00729 return res;
00730 }
00731
00732 static int agent_digit_begin(struct ast_channel *ast, char digit)
00733 {
00734 struct agent_pvt *p = ast->tech_pvt;
00735 ast_mutex_lock(&p->lock);
00736 if (p->chan) {
00737 ast_senddigit_begin(p->chan, digit);
00738 }
00739 ast_mutex_unlock(&p->lock);
00740 return 0;
00741 }
00742
00743 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00744 {
00745 struct agent_pvt *p = ast->tech_pvt;
00746 ast_mutex_lock(&p->lock);
00747 if (p->chan) {
00748 ast_senddigit_end(p->chan, digit, duration);
00749 }
00750 ast_mutex_unlock(&p->lock);
00751 return 0;
00752 }
00753
00754 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
00755 {
00756 struct agent_pvt *p = ast->tech_pvt;
00757 int res = -1;
00758 int newstate=0;
00759 struct ast_channel *chan;
00760
00761 ast_mutex_lock(&p->lock);
00762 p->acknowledged = 0;
00763
00764 if (p->pending) {
00765 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00766 ast_mutex_unlock(&p->lock);
00767 ast_setstate(ast, AST_STATE_DIALING);
00768 return 0;
00769 }
00770
00771 if (!p->chan) {
00772 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
00773 ast_mutex_unlock(&p->lock);
00774 return res;
00775 }
00776
00777 if (!ast_strlen_zero(p->loginchan)) {
00778 time(&p->start);
00779
00780 if (option_verbose > 2)
00781 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00782 ast_set_callerid(p->chan,
00783 ast->cid.cid_num, ast->cid.cid_name, NULL);
00784 ast_channel_inherit_variables(ast, p->chan);
00785 res = ast_call(p->chan, p->loginchan, 0);
00786 CLEANUP(ast,p);
00787 ast_mutex_unlock(&p->lock);
00788 return res;
00789 }
00790 if (option_verbose > 2)
00791 ast_verbose(VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00792 if (option_debug > 2)
00793 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
00794
00795 chan = p->chan;
00796 ast_mutex_unlock(&p->lock);
00797
00798 res = ast_streamfile(chan, beep, chan->language);
00799 if (option_debug > 2)
00800 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
00801 if (!res) {
00802 res = ast_waitstream(chan, "");
00803 if (option_debug > 2)
00804 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
00805 }
00806
00807 ast_mutex_lock(&p->lock);
00808 if (!p->chan) {
00809
00810 res = -1;
00811 }
00812
00813 if (!res) {
00814 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00815 if (option_debug > 2)
00816 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
00817 if (res)
00818 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00819 } else {
00820
00821 p->chan = NULL;
00822 p->inherited_devicestate = -1;
00823 ast_device_state_changed("Agent/%s", p->agent);
00824 }
00825
00826 if (!res) {
00827 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00828 if (option_debug > 2)
00829 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
00830 if (res)
00831 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00832 }
00833 if(!res) {
00834
00835 if (p->ackcall > 1)
00836 newstate = AST_STATE_RINGING;
00837 else {
00838 newstate = AST_STATE_UP;
00839 if (recordagentcalls)
00840 agent_start_monitoring(ast, 0);
00841 p->acknowledged = 1;
00842 }
00843 res = 0;
00844 }
00845 CLEANUP(ast, p);
00846 ast_mutex_unlock(&p->lock);
00847 if (newstate)
00848 ast_setstate(ast, newstate);
00849 return res;
00850 }
00851
00852
00853 static void set_agentbycallerid(const char *callerid, const char *agent)
00854 {
00855 char buf[AST_MAX_BUF];
00856
00857
00858 if (ast_strlen_zero(callerid))
00859 return;
00860
00861 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00862 pbx_builtin_setvar_helper(NULL, buf, agent);
00863 }
00864
00865
00866 struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
00867 {
00868 struct agent_pvt *p = NULL;
00869 struct ast_channel *base = chan;
00870
00871
00872 if (!chan || !chan->tech_pvt) {
00873 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);
00874 return NULL;
00875 }
00876 p = chan->tech_pvt;
00877 if (p->chan)
00878 base = p->chan;
00879 return base;
00880 }
00881
00882 int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
00883 {
00884 struct agent_pvt *p = NULL;
00885
00886 if (!chan || !base) {
00887 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00888 return -1;
00889 }
00890 p = chan->tech_pvt;
00891 if (!p) {
00892 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00893 return -1;
00894 }
00895 p->chan = base;
00896 return 0;
00897 }
00898
00899 static int agent_hangup(struct ast_channel *ast)
00900 {
00901 struct agent_pvt *p = ast->tech_pvt;
00902 int howlong = 0;
00903 const char *status;
00904 ast_mutex_lock(&p->lock);
00905 p->owner = NULL;
00906 ast->tech_pvt = NULL;
00907 p->app_sleep_cond = 1;
00908 p->acknowledged = 0;
00909
00910
00911 if (ast_strlen_zero(p->loginchan)) {
00912 p->app_lock_flag = 0;
00913 ast_cond_signal(&p->app_complete_cond);
00914 }
00915
00916
00917
00918
00919
00920
00921
00922
00923 if (option_debug)
00924 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
00925 if (p->start && (ast->_state != AST_STATE_UP)) {
00926 howlong = time(NULL) - p->start;
00927 p->start = 0;
00928 } else if (ast->_state == AST_STATE_RESERVED)
00929 howlong = 0;
00930 else
00931 p->start = 0;
00932 if (p->chan) {
00933 p->chan->_bridge = NULL;
00934
00935 if (!ast_strlen_zero(p->loginchan)) {
00936
00937 if (p->wrapuptime)
00938 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00939 else
00940 p->lastdisc = ast_tv(0,0);
00941 if (p->chan) {
00942 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00943 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00944 long logintime = time(NULL) - p->loginstart;
00945 p->loginstart = 0;
00946 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00947 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00948 }
00949
00950 ast_hangup(p->chan);
00951 p->chan = NULL;
00952 p->inherited_devicestate = -1;
00953 ast_device_state_changed("Agent/%s", p->agent);
00954 }
00955 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00956 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
00957 long logintime = time(NULL) - p->loginstart;
00958 p->loginstart = 0;
00959 if (!p->deferlogoff)
00960 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00961 p->deferlogoff = 0;
00962 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00963 if (persistent_agents)
00964 dump_agents();
00965 }
00966 } else if (p->dead) {
00967 ast_channel_lock(p->chan);
00968 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00969 ast_channel_unlock(p->chan);
00970 } else if (p->loginstart) {
00971 ast_channel_lock(p->chan);
00972 ast_indicate_data(p->chan, AST_CONTROL_HOLD,
00973 S_OR(p->moh, NULL),
00974 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00975 ast_channel_unlock(p->chan);
00976 }
00977 }
00978 ast_mutex_unlock(&p->lock);
00979
00980
00981 if (!p->loginstart) {
00982 p->loginchan[0] = '\0';
00983 p->logincallerid[0] = '\0';
00984 if (persistent_agents)
00985 dump_agents();
00986 } else {
00987 ast_device_state_changed("Agent/%s", p->agent);
00988 }
00989
00990 if (p->pending) {
00991 AST_LIST_LOCK(&agents);
00992 AST_LIST_REMOVE(&agents, p, list);
00993 AST_LIST_UNLOCK(&agents);
00994 }
00995 if (p->abouttograb) {
00996
00997
00998 p->abouttograb = 0;
00999 } else if (p->dead) {
01000 ast_mutex_destroy(&p->lock);
01001 ast_cond_destroy(&p->app_complete_cond);
01002 ast_cond_destroy(&p->login_wait_cond);
01003 free(p);
01004 } else {
01005 if (p->chan) {
01006
01007 ast_mutex_lock(&p->lock);
01008
01009 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
01010 ast_mutex_unlock(&p->lock);
01011 }
01012 }
01013 return 0;
01014 }
01015
01016 static int agent_cont_sleep( void *data )
01017 {
01018 struct agent_pvt *p;
01019 int res;
01020
01021 p = (struct agent_pvt *)data;
01022
01023 ast_mutex_lock(&p->lock);
01024 res = p->app_sleep_cond;
01025 if (p->lastdisc.tv_sec) {
01026 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
01027 res = 1;
01028 }
01029 ast_mutex_unlock(&p->lock);
01030
01031 if(option_debug > 4 && !res )
01032 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
01033
01034 return res;
01035 }
01036
01037 static int agent_ack_sleep(void *data)
01038 {
01039 struct agent_pvt *p;
01040 int res=0;
01041 int to = 1000;
01042 struct ast_frame *f;
01043
01044
01045
01046 p = (struct agent_pvt *) data;
01047 if (!p->chan)
01048 return -1;
01049
01050 for(;;) {
01051 to = ast_waitfor(p->chan, to);
01052 if (to < 0)
01053 return -1;
01054 if (!to)
01055 return 0;
01056 f = ast_read(p->chan);
01057 if (!f)
01058 return -1;
01059 if (f->frametype == AST_FRAME_DTMF)
01060 res = f->subclass;
01061 else
01062 res = 0;
01063 ast_frfree(f);
01064 ast_mutex_lock(&p->lock);
01065 if (!p->app_sleep_cond) {
01066 ast_mutex_unlock(&p->lock);
01067 return 0;
01068 } else if (res == '#') {
01069 ast_mutex_unlock(&p->lock);
01070 return 1;
01071 }
01072 ast_mutex_unlock(&p->lock);
01073 res = 0;
01074 }
01075 return res;
01076 }
01077
01078 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
01079 {
01080 struct agent_pvt *p = bridge->tech_pvt;
01081 struct ast_channel *ret = NULL;
01082
01083 if (p) {
01084 if (chan == p->chan)
01085 ret = bridge->_bridge;
01086 else if (chan == bridge->_bridge)
01087 ret = p->chan;
01088 }
01089
01090 if (option_debug)
01091 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01092 return ret;
01093 }
01094
01095
01096 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
01097 {
01098 struct ast_channel *tmp;
01099 #if 0
01100 if (!p->chan) {
01101 ast_log(LOG_WARNING, "No channel? :(\n");
01102 return NULL;
01103 }
01104 #endif
01105 if (p->pending)
01106 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
01107 else
01108 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
01109 if (!tmp) {
01110 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01111 return NULL;
01112 }
01113
01114 tmp->tech = &agent_tech;
01115 if (p->chan) {
01116 tmp->nativeformats = p->chan->nativeformats;
01117 tmp->writeformat = p->chan->writeformat;
01118 tmp->rawwriteformat = p->chan->writeformat;
01119 tmp->readformat = p->chan->readformat;
01120 tmp->rawreadformat = p->chan->readformat;
01121 ast_string_field_set(tmp, language, p->chan->language);
01122 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01123 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01124
01125 } else {
01126 tmp->nativeformats = AST_FORMAT_SLINEAR;
01127 tmp->writeformat = AST_FORMAT_SLINEAR;
01128 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01129 tmp->readformat = AST_FORMAT_SLINEAR;
01130 tmp->rawreadformat = AST_FORMAT_SLINEAR;
01131 }
01132
01133 tmp->tech_pvt = p;
01134 p->owner = tmp;
01135
01136 #if 0
01137 ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
01138 #endif
01139 ast_update_use_count();
01140 tmp->priority = 1;
01141 return tmp;
01142 }
01143
01144
01145
01146
01147
01148
01149
01150 static int read_agent_config(void)
01151 {
01152 struct ast_config *cfg;
01153 struct ast_config *ucfg;
01154 struct ast_variable *v;
01155 struct agent_pvt *p;
01156 const char *general_val;
01157 const char *catname;
01158 const char *hasagent;
01159 int genhasagent;
01160
01161 memset(group, 0, sizeof(group));
01162 autologoff = 0;
01163 wrapuptime = 0;
01164 ackcall = 0;
01165 endcall = 1;
01166 cfg = ast_config_load(config);
01167 if (!cfg) {
01168 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01169 return 0;
01170 }
01171 AST_LIST_LOCK(&agents);
01172 AST_LIST_TRAVERSE(&agents, p, list) {
01173 p->dead = 1;
01174 }
01175 strcpy(moh, "default");
01176
01177 recordagentcalls = 0;
01178 strcpy(recordformat, "wav");
01179 strcpy(recordformatext, "wav");
01180 urlprefix[0] = '\0';
01181 savecallsin[0] = '\0';
01182
01183
01184 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
01185 persistent_agents = ast_true(general_val);
01186 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
01187
01188
01189 v = ast_variable_browse(cfg, "agents");
01190 while(v) {
01191
01192 if (!strcasecmp(v->name, "agent")) {
01193 add_agent(v->value, 0);
01194 } else if (!strcasecmp(v->name, "group")) {
01195 ast_get_group(&group, v->value);
01196 } else if (!strcasecmp(v->name, "autologoff")) {
01197 autologoff = atoi(v->value);
01198 if (autologoff < 0)
01199 autologoff = 0;
01200 } else if (!strcasecmp(v->name, "ackcall")) {
01201 if (!strcasecmp(v->value, "always"))
01202 ackcall = 2;
01203 else if (ast_true(v->value))
01204 ackcall = 1;
01205 else
01206 ackcall = 0;
01207 } else if (!strcasecmp(v->name, "endcall")) {
01208 endcall = ast_true(v->value);
01209 } else if (!strcasecmp(v->name, "wrapuptime")) {
01210 wrapuptime = atoi(v->value);
01211 if (wrapuptime < 0)
01212 wrapuptime = 0;
01213 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01214 maxlogintries = atoi(v->value);
01215 if (maxlogintries < 0)
01216 maxlogintries = 0;
01217 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01218 strcpy(agentgoodbye,v->value);
01219 } else if (!strcasecmp(v->name, "musiconhold")) {
01220 ast_copy_string(moh, v->value, sizeof(moh));
01221 } else if (!strcasecmp(v->name, "updatecdr")) {
01222 if (ast_true(v->value))
01223 updatecdr = 1;
01224 else
01225 updatecdr = 0;
01226 } else if (!strcasecmp(v->name, "autologoffunavail")) {
01227 if (ast_true(v->value))
01228 autologoffunavail = 1;
01229 else
01230 autologoffunavail = 0;
01231 } else if (!strcasecmp(v->name, "recordagentcalls")) {
01232 recordagentcalls = ast_true(v->value);
01233 } else if (!strcasecmp(v->name, "recordformat")) {
01234 ast_copy_string(recordformat, v->value, sizeof(recordformat));
01235 if (!strcasecmp(v->value, "wav49"))
01236 strcpy(recordformatext, "WAV");
01237 else
01238 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01239 } else if (!strcasecmp(v->name, "urlprefix")) {
01240 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01241 if (urlprefix[strlen(urlprefix) - 1] != '/')
01242 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01243 } else if (!strcasecmp(v->name, "savecallsin")) {
01244 if (v->value[0] == '/')
01245 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01246 else
01247 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01248 if (savecallsin[strlen(savecallsin) - 1] != '/')
01249 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01250 } else if (!strcasecmp(v->name, "custom_beep")) {
01251 ast_copy_string(beep, v->value, sizeof(beep));
01252 }
01253 v = v->next;
01254 }
01255 if ((ucfg = ast_config_load("users.conf"))) {
01256 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01257 catname = ast_category_browse(ucfg, NULL);
01258 while(catname) {
01259 if (strcasecmp(catname, "general")) {
01260 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01261 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01262 char tmp[256];
01263 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01264 const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01265 if (!fullname)
01266 fullname = "";
01267 if (!secret)
01268 secret = "";
01269 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01270 add_agent(tmp, 0);
01271 }
01272 }
01273 catname = ast_category_browse(ucfg, catname);
01274 }
01275 ast_config_destroy(ucfg);
01276 }
01277 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01278 if (p->dead) {
01279 AST_LIST_REMOVE_CURRENT(&agents, list);
01280
01281 if (!p->owner) {
01282 if (!p->chan) {
01283 ast_mutex_destroy(&p->lock);
01284 ast_cond_destroy(&p->app_complete_cond);
01285 ast_cond_destroy(&p->login_wait_cond);
01286 free(p);
01287 } else {
01288
01289 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01290 }
01291 }
01292 }
01293 }
01294 AST_LIST_TRAVERSE_SAFE_END
01295 AST_LIST_UNLOCK(&agents);
01296 ast_config_destroy(cfg);
01297 return 1;
01298 }
01299
01300 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
01301 {
01302 struct ast_channel *chan=NULL, *parent=NULL;
01303 struct agent_pvt *p;
01304 int res;
01305
01306 if (option_debug)
01307 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
01308 if (needlock)
01309 AST_LIST_LOCK(&agents);
01310 AST_LIST_TRAVERSE(&agents, p, list) {
01311 if (p == newlyavailable) {
01312 continue;
01313 }
01314 ast_mutex_lock(&p->lock);
01315 if (!p->abouttograb && p->pending && ((p->group && ast_have_common_group(&newlyavailable->group, &p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01316 if (option_debug)
01317 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01318
01319 chan = agent_new(newlyavailable, AST_STATE_DOWN);
01320 parent = p->owner;
01321 p->abouttograb = 1;
01322 ast_mutex_unlock(&p->lock);
01323 break;
01324 }
01325 ast_mutex_unlock(&p->lock);
01326 }
01327 if (needlock)
01328 AST_LIST_UNLOCK(&agents);
01329 if (parent && chan) {
01330 if (newlyavailable->ackcall > 1) {
01331
01332 res = 0;
01333 } else {
01334 if (option_debug > 2)
01335 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01336 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01337 if (option_debug > 2)
01338 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01339 if (!res) {
01340 res = ast_waitstream(newlyavailable->chan, "");
01341 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01342 }
01343 }
01344 if (!res) {
01345
01346 if (p->abouttograb) {
01347 newlyavailable->acknowledged = 1;
01348
01349 ast_setstate(parent, AST_STATE_UP);
01350 ast_setstate(chan, AST_STATE_UP);
01351 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01352
01353
01354 ast_mutex_lock(&parent->lock);
01355 ast_set_flag(chan, AST_FLAG_ZOMBIE);
01356 ast_channel_masquerade(parent, chan);
01357 ast_mutex_unlock(&parent->lock);
01358 p->abouttograb = 0;
01359 } else {
01360 if (option_debug)
01361 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
01362 agent_cleanup(newlyavailable);
01363 }
01364 } else {
01365 if (option_debug)
01366 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
01367 agent_cleanup(newlyavailable);
01368 }
01369 }
01370 return 0;
01371 }
01372
01373 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
01374 {
01375 struct agent_pvt *p;
01376 int res=0;
01377
01378 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01379 if (needlock)
01380 AST_LIST_LOCK(&agents);
01381 AST_LIST_TRAVERSE(&agents, p, list) {
01382 if (p == newlyavailable) {
01383 continue;
01384 }
01385 ast_mutex_lock(&p->lock);
01386 if (!p->abouttograb && p->pending && ((p->group && ast_have_common_group(&newlyavailable->group, &p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01387 if (option_debug)
01388 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01389 ast_mutex_unlock(&p->lock);
01390 break;
01391 }
01392 ast_mutex_unlock(&p->lock);
01393 }
01394 if (needlock)
01395 AST_LIST_UNLOCK(&agents);
01396 if (p) {
01397 ast_mutex_unlock(&newlyavailable->lock);
01398 if (option_debug > 2)
01399 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01400 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01401 if (option_debug > 2)
01402 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01403 if (!res) {
01404 res = ast_waitstream(newlyavailable->chan, "");
01405 if (option_debug)
01406 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01407 }
01408 ast_mutex_lock(&newlyavailable->lock);
01409 }
01410 return res;
01411 }
01412
01413
01414 static int allow_multiple_login(char *chan, char *context)
01415 {
01416 struct agent_pvt *p;
01417 char loginchan[80];
01418
01419 if (multiplelogin) {
01420 return 1;
01421 }
01422 if (!chan) {
01423 return 0;
01424 }
01425
01426 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01427
01428 AST_LIST_TRAVERSE(&agents, p, list) {
01429 if(!strcasecmp(loginchan, p->loginchan))
01430 return 0;
01431 }
01432 return -1;
01433 }
01434
01435
01436 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
01437 {
01438 struct agent_pvt *p;
01439 struct ast_channel *chan = NULL;
01440 char *s;
01441 ast_group_t groupmatch;
01442 int groupoff;
01443 int waitforagent=0;
01444 int hasagent = 0;
01445 struct timeval tv;
01446
01447 s = data;
01448 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01449 char tmp[12];
01450 sprintf(tmp, "%d", groupoff);
01451 ast_get_group(&groupmatch, tmp);
01452 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01453 char tmp[12];
01454 sprintf(tmp, "%d", groupoff);
01455 ast_get_group(&groupmatch, tmp);
01456 waitforagent = 1;
01457 } else {
01458 memset(groupmatch, 0, sizeof(groupmatch));
01459 }
01460
01461
01462 AST_LIST_LOCK(&agents);
01463 AST_LIST_TRAVERSE(&agents, p, list) {
01464 ast_mutex_lock(&p->lock);
01465 if (!p->pending && ((!ast_is_empty_group(&groupmatch) && ast_have_common_group(&p->group, &groupmatch)) || !strcmp(data, p->agent)) &&
01466 ast_strlen_zero(p->loginchan)) {
01467 if (p->chan)
01468 hasagent++;
01469 tv = ast_tvnow();
01470 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01471 p->lastdisc = ast_tv(0, 0);
01472
01473 if (!p->owner && p->chan) {
01474
01475 chan = agent_new(p, AST_STATE_DOWN);
01476 }
01477 if (chan) {
01478 ast_mutex_unlock(&p->lock);
01479 break;
01480 }
01481 }
01482 }
01483 ast_mutex_unlock(&p->lock);
01484 }
01485 if (!p) {
01486 AST_LIST_TRAVERSE(&agents, p, list) {
01487 ast_mutex_lock(&p->lock);
01488 if (!p->pending && ((!ast_is_empty_group(&groupmatch) && ast_have_common_group(&p->group, &groupmatch)) || !strcmp(data, p->agent))) {
01489 if (p->chan || !ast_strlen_zero(p->loginchan))
01490 hasagent++;
01491 tv = ast_tvnow();
01492 #if 0
01493 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
01494 #endif
01495 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01496 p->lastdisc = ast_tv(0, 0);
01497
01498 if (!p->owner && p->chan) {
01499
01500 chan = agent_new(p, AST_STATE_DOWN);
01501 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01502
01503 p->chan = ast_request("Local", format, p->loginchan, cause);
01504 if (p->chan)
01505 chan = agent_new(p, AST_STATE_DOWN);
01506 }
01507 if (chan) {
01508 ast_mutex_unlock(&p->lock);
01509 break;
01510 }
01511 }
01512 }
01513 ast_mutex_unlock(&p->lock);
01514 }
01515 }
01516
01517 if (!chan && waitforagent) {
01518
01519
01520 if (hasagent) {
01521 if (option_debug)
01522 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01523 p = add_agent(data, 1);
01524 memcpy(&p->group, &groupmatch, sizeof(p->group));
01525 chan = agent_new(p, AST_STATE_DOWN);
01526 if (!chan)
01527 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
01528 } else
01529 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01530 }
01531 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01532 AST_LIST_UNLOCK(&agents);
01533
01534 if (chan) {
01535 ast_mutex_lock(&p->lock);
01536 if (p->pending) {
01537 ast_mutex_unlock(&p->lock);
01538 return chan;
01539 }
01540
01541 if (!p->chan) {
01542 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01543 *cause = AST_CAUSE_UNREGISTERED;
01544 ast_mutex_unlock(&p->lock);
01545 agent_hangup(chan);
01546 return NULL;
01547 }
01548
01549
01550
01551 if(ast_strlen_zero(p->loginchan)) {
01552 p->app_sleep_cond = 0;
01553 p->app_lock_flag = 1;
01554
01555 ast_queue_frame(p->chan, &ast_null_frame);
01556 ast_cond_wait(&p->login_wait_cond, &p->lock);
01557
01558 if (!p->chan) {
01559 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01560 p->app_sleep_cond = 1;
01561 p->app_lock_flag = 0;
01562 ast_cond_signal(&p->app_complete_cond);
01563 ast_mutex_unlock(&p->lock);
01564 *cause = AST_CAUSE_UNREGISTERED;
01565 agent_hangup(chan);
01566 return NULL;
01567 }
01568
01569 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01570 }
01571 ast_mutex_unlock(&p->lock);
01572 }
01573
01574 return chan;
01575 }
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585 static int action_agents(struct mansession *s, const struct message *m)
01586 {
01587 const char *id = astman_get_header(m,"ActionID");
01588 char idText[256] = "";
01589 char chanbuf[256];
01590 struct agent_pvt *p;
01591 char *username = NULL;
01592 char *loginChan = NULL;
01593 char *talkingtoChan = NULL;
01594 char *status = NULL;
01595
01596 if (!ast_strlen_zero(id))
01597 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01598 astman_send_ack(s, m, "Agents will follow");
01599 AST_LIST_LOCK(&agents);
01600 AST_LIST_TRAVERSE(&agents, p, list) {
01601 ast_mutex_lock(&p->lock);
01602
01603
01604
01605
01606
01607
01608
01609 username = S_OR(p->name, "None");
01610
01611
01612 status = "AGENT_UNKNOWN";
01613
01614 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01615 loginChan = p->loginchan;
01616 talkingtoChan = "n/a";
01617 status = "AGENT_IDLE";
01618 if (p->acknowledged) {
01619 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01620 loginChan = chanbuf;
01621 }
01622 } else if (p->chan) {
01623 loginChan = ast_strdupa(p->chan->name);
01624 if (p->owner && p->owner->_bridge) {
01625 if (ast_bridged_channel(p->owner)) {
01626 talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, ""));
01627 } else {
01628 talkingtoChan = "n/a";
01629 }
01630 status = "AGENT_ONCALL";
01631 } else {
01632 talkingtoChan = "n/a";
01633 status = "AGENT_IDLE";
01634 }
01635 } else {
01636 loginChan = "n/a";
01637 talkingtoChan = "n/a";
01638 status = "AGENT_LOGGEDOFF";
01639 }
01640
01641 astman_append(s, "Event: Agents\r\n"
01642 "Agent: %s\r\n"
01643 "Name: %s\r\n"
01644 "Status: %s\r\n"
01645 "LoggedInChan: %s\r\n"
01646 "LoggedInTime: %d\r\n"
01647 "TalkingTo: %s\r\n"
01648 "%s"
01649 "\r\n",
01650 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
01651 ast_mutex_unlock(&p->lock);
01652 }
01653 AST_LIST_UNLOCK(&agents);
01654 astman_append(s, "Event: AgentsComplete\r\n"
01655 "%s"
01656 "\r\n",idText);
01657 return 0;
01658 }
01659
01660 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
01661 {
01662 char *tmp = NULL;
01663 char agent[AST_MAX_AGENT];
01664
01665 if (!ast_strlen_zero(logcommand))
01666 tmp = logcommand;
01667 else
01668 tmp = ast_strdupa("");
01669
01670 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01671
01672 if (!ast_strlen_zero(uniqueid)) {
01673 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01674 "Agent: %s\r\n"
01675 "Reason: %s\r\n"
01676 "Loginchan: %s\r\n"
01677 "Logintime: %ld\r\n"
01678 "Uniqueid: %s\r\n",
01679 p->agent, tmp, loginchan, logintime, uniqueid);
01680 } else {
01681 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01682 "Agent: %s\r\n"
01683 "Reason: %s\r\n"
01684 "Loginchan: %s\r\n"
01685 "Logintime: %ld\r\n",
01686 p->agent, tmp, loginchan, logintime);
01687 }
01688
01689 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01690 set_agentbycallerid(p->logincallerid, NULL);
01691 p->loginchan[0] ='\0';
01692 p->logincallerid[0] = '\0';
01693 p->inherited_devicestate = -1;
01694 ast_device_state_changed("Agent/%s", p->agent);
01695 if (persistent_agents)
01696 dump_agents();
01697
01698 }
01699
01700 static int agent_logoff(const char *agent, int soft)
01701 {
01702 struct agent_pvt *p;
01703 long logintime;
01704 int ret = -1;
01705
01706 AST_LIST_LOCK(&agents);
01707 AST_LIST_TRAVERSE(&agents, p, list) {
01708 if (!strcasecmp(p->agent, agent)) {
01709 ret = 0;
01710 if (p->owner || p->chan) {
01711 if (!soft) {
01712 ast_mutex_lock(&p->lock);
01713
01714 while (p->owner && ast_channel_trylock(p->owner)) {
01715 DEADLOCK_AVOIDANCE(&p->lock);
01716 }
01717 if (p->owner) {
01718 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01719 ast_channel_unlock(p->owner);
01720 }
01721
01722 while (p->chan && ast_channel_trylock(p->chan)) {
01723 DEADLOCK_AVOIDANCE(&p->lock);
01724 }
01725 if (p->chan) {
01726 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01727 ast_channel_unlock(p->chan);
01728 }
01729
01730 ast_mutex_unlock(&p->lock);
01731 } else
01732 p->deferlogoff = 1;
01733 } else {
01734 logintime = time(NULL) - p->loginstart;
01735 p->loginstart = 0;
01736 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01737 }
01738 break;
01739 }
01740 }
01741 AST_LIST_UNLOCK(&agents);
01742
01743 return ret;
01744 }
01745
01746 static int agent_logoff_cmd(int fd, int argc, char **argv)
01747 {
01748 int ret;
01749 char *agent;
01750
01751 if (argc < 3 || argc > 4)
01752 return RESULT_SHOWUSAGE;
01753 if (argc == 4 && strcasecmp(argv[3], "soft"))
01754 return RESULT_SHOWUSAGE;
01755
01756 agent = argv[2] + 6;
01757 ret = agent_logoff(agent, argc == 4);
01758 if (ret == 0)
01759 ast_cli(fd, "Logging out %s\n", agent);
01760
01761 return RESULT_SUCCESS;
01762 }
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772 static int action_agent_logoff(struct mansession *s, const struct message *m)
01773 {
01774 const char *agent = astman_get_header(m, "Agent");
01775 const char *soft_s = astman_get_header(m, "Soft");
01776 int soft;
01777 int ret;
01778
01779 if (ast_strlen_zero(agent)) {
01780 astman_send_error(s, m, "No agent specified");
01781 return 0;
01782 }
01783
01784 soft = ast_true(soft_s) ? 1 : 0;
01785 ret = agent_logoff(agent, soft);
01786 if (ret == 0)
01787 astman_send_ack(s, m, "Agent logged out");
01788 else
01789 astman_send_error(s, m, "No such agent");
01790
01791 return 0;
01792 }
01793
01794 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
01795 {
01796 char *ret = NULL;
01797
01798 if (pos == 2) {
01799 struct agent_pvt *p;
01800 char name[AST_MAX_AGENT];
01801 int which = 0, len = strlen(word);
01802
01803 AST_LIST_LOCK(&agents);
01804 AST_LIST_TRAVERSE(&agents, p, list) {
01805 snprintf(name, sizeof(name), "Agent/%s", p->agent);
01806 if (!strncasecmp(word, name, len) && ++which > state) {
01807 ret = ast_strdup(name);
01808 break;
01809 }
01810 }
01811 AST_LIST_UNLOCK(&agents);
01812 } else if (pos == 3 && state == 0)
01813 return ast_strdup("soft");
01814
01815 return ret;
01816 }
01817
01818
01819
01820
01821 static int agents_show(int fd, int argc, char **argv)
01822 {
01823 struct agent_pvt *p;
01824 char username[AST_MAX_BUF];
01825 char location[AST_MAX_BUF] = "";
01826 char talkingto[AST_MAX_BUF] = "";
01827 char moh[AST_MAX_BUF];
01828 int count_agents = 0;
01829 int online_agents = 0;
01830 int offline_agents = 0;
01831 if (argc != 2)
01832 return RESULT_SHOWUSAGE;
01833 AST_LIST_LOCK(&agents);
01834 AST_LIST_TRAVERSE(&agents, p, list) {
01835 ast_mutex_lock(&p->lock);
01836 if (p->pending) {
01837 char tmp[256];
01838 if (p->group)
01839 ast_cli(fd, "-- Pending call to group %s\n", ast_print_group(tmp, sizeof(tmp), &p->group));
01840 else
01841 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01842 } else {
01843 if (!ast_strlen_zero(p->name))
01844 snprintf(username, sizeof(username), "(%s) ", p->name);
01845 else
01846 username[0] = '\0';
01847 if (p->chan) {
01848 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01849 if (p->owner && ast_bridged_channel(p->owner))
01850 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01851 else
01852 strcpy(talkingto, " is idle");
01853 online_agents++;
01854 } else if (!ast_strlen_zero(p->loginchan)) {
01855 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec))
01856 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01857 else
01858 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01859 talkingto[0] = '\0';
01860 online_agents++;
01861 if (p->acknowledged)
01862 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01863 } else {
01864 strcpy(location, "not logged in");
01865 talkingto[0] = '\0';
01866 offline_agents++;
01867 }
01868 if (!ast_strlen_zero(p->moh))
01869 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01870 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
01871 username, location, talkingto, moh);
01872 count_agents++;
01873 }
01874 ast_mutex_unlock(&p->lock);
01875 }
01876 AST_LIST_UNLOCK(&agents);
01877 if ( !count_agents )
01878 ast_cli(fd, "No Agents are configured in %s\n",config);
01879 else
01880 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01881 ast_cli(fd, "\n");
01882
01883 return RESULT_SUCCESS;
01884 }
01885
01886
01887 static int agents_show_online(int fd, int argc, char **argv)
01888 {
01889 struct agent_pvt *p;
01890 char username[AST_MAX_BUF];
01891 char location[AST_MAX_BUF] = "";
01892 char talkingto[AST_MAX_BUF] = "";
01893 char moh[AST_MAX_BUF];
01894 int count_agents = 0;
01895 int online_agents = 0;
01896 int agent_status = 0;
01897 if (argc != 3)
01898 return RESULT_SHOWUSAGE;
01899 AST_LIST_LOCK(&agents);
01900 AST_LIST_TRAVERSE(&agents, p, list) {
01901 agent_status = 0;
01902 ast_mutex_lock(&p->lock);
01903 if (!ast_strlen_zero(p->name))
01904 snprintf(username, sizeof(username), "(%s) ", p->name);
01905 else
01906 username[0] = '\0';
01907 if (p->chan) {
01908 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01909 if (p->owner && ast_bridged_channel(p->owner))
01910 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01911 else
01912 strcpy(talkingto, " is idle");
01913 agent_status = 1;
01914 online_agents++;
01915 } else if (!ast_strlen_zero(p->loginchan)) {
01916 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01917 talkingto[0] = '\0';
01918 agent_status = 1;
01919 online_agents++;
01920 if (p->acknowledged)
01921 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01922 }
01923 if (!ast_strlen_zero(p->moh))
01924 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01925 if (agent_status)
01926 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01927 count_agents++;
01928 ast_mutex_unlock(&p->lock);
01929 }
01930 AST_LIST_UNLOCK(&agents);
01931 if (!count_agents)
01932 ast_cli(fd, "No Agents are configured in %s\n", config);
01933 else
01934 ast_cli(fd, "%d agents online\n", online_agents);
01935 ast_cli(fd, "\n");
01936 return RESULT_SUCCESS;
01937 }
01938
01939
01940
01941 static char show_agents_usage[] =
01942 "Usage: agent show\n"
01943 " Provides summary information on agents.\n";
01944
01945 static char show_agents_online_usage[] =
01946 "Usage: agent show online\n"
01947 " Provides a list of all online agents.\n";
01948
01949 static char agent_logoff_usage[] =
01950 "Usage: agent logoff <channel> [soft]\n"
01951 " Sets an agent as no longer logged in.\n"
01952 " If 'soft' is specified, do not hangup existing calls.\n";
01953
01954 static struct ast_cli_entry cli_show_agents_deprecated = {
01955 { "show", "agents", NULL },
01956 agents_show, NULL,
01957 NULL, NULL };
01958
01959 static struct ast_cli_entry cli_show_agents_online_deprecated = {
01960 { "show", "agents", "online" },
01961 agents_show_online, NULL,
01962 NULL, NULL };
01963
01964 static struct ast_cli_entry cli_agents[] = {
01965 { { "agent", "show", NULL },
01966 agents_show, "Show status of agents",
01967 show_agents_usage, NULL, &cli_show_agents_deprecated },
01968
01969 { { "agent", "show", "online" },
01970 agents_show_online, "Show all online agents",
01971 show_agents_online_usage, NULL, &cli_show_agents_online_deprecated },
01972
01973 { { "agent", "logoff", NULL },
01974 agent_logoff_cmd, "Sets an agent offline",
01975 agent_logoff_usage, complete_agent_logoff_cmd },
01976 };
01977
01978
01979
01980
01981
01982
01983
01984
01985 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
01986 {
01987 int res=0;
01988 int tries = 0;
01989 int max_login_tries = maxlogintries;
01990 struct agent_pvt *p;
01991 struct ast_module_user *u;
01992 int login_state = 0;
01993 char user[AST_MAX_AGENT] = "";
01994 char pass[AST_MAX_AGENT];
01995 char agent[AST_MAX_AGENT] = "";
01996 char xpass[AST_MAX_AGENT] = "";
01997 char *errmsg;
01998 char *parse;
01999 AST_DECLARE_APP_ARGS(args,
02000 AST_APP_ARG(agent_id);
02001 AST_APP_ARG(options);
02002 AST_APP_ARG(extension);
02003 );
02004 const char *tmpoptions = NULL;
02005 char *context = NULL;
02006 int play_announcement = 1;
02007 char agent_goodbye[AST_MAX_FILENAME_LEN];
02008 int update_cdr = updatecdr;
02009 char *filename = "agent-loginok";
02010 char tmpchan[AST_MAX_BUF] = "";
02011
02012 u = ast_module_user_add(chan);
02013
02014 parse = ast_strdupa(data);
02015
02016 AST_STANDARD_APP_ARGS(args, parse);
02017
02018 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
02019
02020 ast_channel_lock(chan);
02021
02022 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
02023 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
02024 if (max_login_tries < 0)
02025 max_login_tries = 0;
02026 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
02027 if (option_verbose > 2)
02028 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);
02029 }
02030 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
02031 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
02032 update_cdr = 1;
02033 else
02034 update_cdr = 0;
02035 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
02036 if (option_verbose > 2)
02037 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
02038 }
02039 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
02040 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
02041 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
02042 if (option_verbose > 2)
02043 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
02044 }
02045 ast_channel_unlock(chan);
02046
02047
02048 if (callbackmode && args.extension) {
02049 parse = args.extension;
02050 args.extension = strsep(&parse, "@");
02051 context = parse;
02052 }
02053
02054 if (!ast_strlen_zero(args.options)) {
02055 if (strchr(args.options, 's')) {
02056 play_announcement = 0;
02057 }
02058 }
02059
02060 if (chan->_state != AST_STATE_UP)
02061 res = ast_answer(chan);
02062 if (!res) {
02063 if (!ast_strlen_zero(args.agent_id))
02064 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
02065 else
02066 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
02067 }
02068 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
02069 tries++;
02070
02071 AST_LIST_LOCK(&agents);
02072 AST_LIST_TRAVERSE(&agents, p, list) {
02073 if (!strcmp(p->agent, user) && !p->pending)
02074 ast_copy_string(xpass, p->password, sizeof(xpass));
02075 }
02076 AST_LIST_UNLOCK(&agents);
02077 if (!res) {
02078 if (!ast_strlen_zero(xpass))
02079 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
02080 else
02081 pass[0] = '\0';
02082 }
02083 errmsg = "agent-incorrect";
02084
02085 #if 0
02086 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
02087 #endif
02088
02089
02090 AST_LIST_LOCK(&agents);
02091 AST_LIST_TRAVERSE(&agents, p, list) {
02092 int unlock_channel = 1;
02093 ast_channel_lock(chan);
02094 ast_mutex_lock(&p->lock);
02095 if (!strcmp(p->agent, user) &&
02096 !strcmp(p->password, pass) && !p->pending) {
02097 login_state = 1;
02098
02099
02100 gettimeofday(&p->lastdisc, NULL);
02101 p->lastdisc.tv_sec++;
02102
02103
02104 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02105 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
02106 p->ackcall = 2;
02107 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
02108 p->ackcall = 1;
02109 else
02110 p->ackcall = 0;
02111 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
02112 if (option_verbose > 2)
02113 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
02114 } else {
02115 p->ackcall = ackcall;
02116 }
02117 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
02118 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
02119 if (p->autologoff < 0)
02120 p->autologoff = 0;
02121 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
02122 if (option_verbose > 2)
02123 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
02124 } else {
02125 p->autologoff = autologoff;
02126 }
02127 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
02128 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
02129 if (p->wrapuptime < 0)
02130 p->wrapuptime = 0;
02131 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
02132 if (option_verbose > 2)
02133 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
02134 } else {
02135 p->wrapuptime = wrapuptime;
02136 }
02137 ast_channel_unlock(chan);
02138 unlock_channel = 0;
02139
02140 if (!p->chan) {
02141 char last_loginchan[80] = "";
02142 long logintime;
02143 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
02144
02145 if (callbackmode) {
02146 int pos = 0;
02147
02148 for (;;) {
02149 if (!ast_strlen_zero(args.extension)) {
02150 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
02151 res = 0;
02152 } else
02153 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
02154 if (ast_strlen_zero(tmpchan) )
02155 break;
02156 if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
02157 if(!allow_multiple_login(tmpchan,context) ) {
02158 args.extension = NULL;
02159 pos = 0;
02160 } else
02161 break;
02162 }
02163 if (args.extension) {
02164 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
02165 args.extension = NULL;
02166 pos = 0;
02167 } else {
02168 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
02169 res = ast_streamfile(chan, "invalid", chan->language);
02170 if (!res)
02171 res = ast_waitstream(chan, AST_DIGIT_ANY);
02172 if (res > 0) {
02173 tmpchan[0] = res;
02174 tmpchan[1] = '\0';
02175 pos = 1;
02176 } else {
02177 tmpchan[0] = '\0';
02178 pos = 0;
02179 }
02180 }
02181 }
02182 args.extension = tmpchan;
02183 if (!res) {
02184 set_agentbycallerid(p->logincallerid, NULL);
02185 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
02186 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
02187 else {
02188 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
02189 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
02190 }
02191 p->acknowledged = 0;
02192 if (ast_strlen_zero(p->loginchan)) {
02193 login_state = 2;
02194 filename = "agent-loggedoff";
02195 } else {
02196 if (chan->cid.cid_num) {
02197 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
02198 set_agentbycallerid(p->logincallerid, p->agent);
02199 } else
02200 p->logincallerid[0] = '\0';
02201 }
02202
02203 if(update_cdr && chan->cdr)
02204 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02205
02206 }
02207 } else {
02208 p->loginchan[0] = '\0';
02209 p->logincallerid[0] = '\0';
02210 p->acknowledged = 0;
02211 }
02212 ast_mutex_unlock(&p->lock);
02213 AST_LIST_UNLOCK(&agents);
02214 if( !res && play_announcement==1 )
02215 res = ast_streamfile(chan, filename, chan->language);
02216 if (!res)
02217 ast_waitstream(chan, "");
02218 AST_LIST_LOCK(&agents);
02219 ast_mutex_lock(&p->lock);
02220 if (!res) {
02221 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02222 if (res)
02223 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
02224 }
02225 if (!res) {
02226 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02227 if (res)
02228 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
02229 }
02230
02231 if (p->chan)
02232 res = -1;
02233 if (callbackmode && !res) {
02234
02235 if (!ast_strlen_zero(p->loginchan)) {
02236 if (p->loginstart == 0)
02237 time(&p->loginstart);
02238 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02239 "Agent: %s\r\n"
02240 "Loginchan: %s\r\n"
02241 "Uniqueid: %s\r\n",
02242 p->agent, p->loginchan, chan->uniqueid);
02243 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02244 if (option_verbose > 1)
02245 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02246 ast_device_state_changed("Agent/%s", p->agent);
02247 if (persistent_agents)
02248 dump_agents();
02249 } else {
02250 logintime = time(NULL) - p->loginstart;
02251 p->loginstart = 0;
02252
02253 agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
02254 if (option_verbose > 1)
02255 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
02256 }
02257 AST_LIST_UNLOCK(&agents);
02258 if (!res)
02259 res = ast_safe_sleep(chan, 500);
02260 ast_mutex_unlock(&p->lock);
02261 } else if (!res) {
02262 ast_indicate_data(chan, AST_CONTROL_HOLD,
02263 S_OR(p->moh, NULL),
02264 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02265 if (p->loginstart == 0)
02266 time(&p->loginstart);
02267 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02268 "Agent: %s\r\n"
02269 "Channel: %s\r\n"
02270 "Uniqueid: %s\r\n",
02271 p->agent, chan->name, chan->uniqueid);
02272 if (update_cdr && chan->cdr)
02273 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02274 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02275 if (option_verbose > 1)
02276 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
02277 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02278
02279 p->chan = chan;
02280 if (p->ackcall > 1)
02281 check_beep(p, 0);
02282 else
02283 check_availability(p, 0);
02284 ast_mutex_unlock(&p->lock);
02285 AST_LIST_UNLOCK(&agents);
02286 ast_device_state_changed("Agent/%s", p->agent);
02287 while (res >= 0) {
02288 ast_mutex_lock(&p->lock);
02289 if (p->deferlogoff && p->chan) {
02290 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
02291 p->deferlogoff = 0;
02292 }
02293 if (p->chan != chan)
02294 res = -1;
02295 ast_mutex_unlock(&p->lock);
02296
02297 sched_yield();
02298 if (res)
02299 break;
02300
02301 AST_LIST_LOCK(&agents);
02302 ast_mutex_lock(&p->lock);
02303 if (p->lastdisc.tv_sec) {
02304 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02305 if (option_debug)
02306 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
02307 p->lastdisc = ast_tv(0, 0);
02308 ast_device_state_changed("Agent/%s", p->agent);
02309 if (p->ackcall > 1)
02310 check_beep(p, 0);
02311 else
02312 check_availability(p, 0);
02313 }
02314 }
02315 ast_mutex_unlock(&p->lock);
02316 AST_LIST_UNLOCK(&agents);
02317
02318
02319 ast_mutex_lock(&p->lock);
02320 if (p->app_lock_flag == 1) {
02321 ast_cond_signal(&p->login_wait_cond);
02322 ast_cond_wait(&p->app_complete_cond, &p->lock);
02323 }
02324 ast_mutex_unlock(&p->lock);
02325
02326 if (p->ackcall > 1)
02327 res = agent_ack_sleep(p);
02328 else
02329 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02330 if ((p->ackcall > 1) && (res == 1)) {
02331 AST_LIST_LOCK(&agents);
02332 ast_mutex_lock(&p->lock);
02333 check_availability(p, 0);
02334 ast_mutex_unlock(&p->lock);
02335 AST_LIST_UNLOCK(&agents);
02336 res = 0;
02337 }
02338 sched_yield();
02339 }
02340 ast_mutex_lock(&p->lock);
02341
02342 if (p->chan == chan) {
02343 p->chan = NULL;
02344 p->inherited_devicestate = -1;
02345 }
02346
02347
02348 if (p->app_lock_flag == 1) {
02349 ast_cond_signal(&p->login_wait_cond);
02350 ast_cond_wait(&p->app_complete_cond, &p->lock);
02351 }
02352
02353 if (res && p->owner)
02354 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
02355
02356 p->acknowledged = 0;
02357 logintime = time(NULL) - p->loginstart;
02358 p->loginstart = 0;
02359 ast_mutex_unlock(&p->lock);
02360 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02361 "Agent: %s\r\n"
02362 "Logintime: %ld\r\n"
02363 "Uniqueid: %s\r\n",
02364 p->agent, logintime, chan->uniqueid);
02365 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02366 if (option_verbose > 1)
02367 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
02368
02369 ast_device_state_changed("Agent/%s", p->agent);
02370 if (p->dead && !p->owner) {
02371 ast_mutex_destroy(&p->lock);
02372 ast_cond_destroy(&p->app_complete_cond);
02373 ast_cond_destroy(&p->login_wait_cond);
02374 free(p);
02375 }
02376 }
02377 else {
02378 ast_mutex_unlock(&p->lock);
02379 p = NULL;
02380 }
02381 res = -1;
02382 } else {
02383 ast_mutex_unlock(&p->lock);
02384 errmsg = "agent-alreadyon";
02385 p = NULL;
02386 }
02387 break;
02388 }
02389 ast_mutex_unlock(&p->lock);
02390 if (unlock_channel) {
02391 ast_channel_unlock(chan);
02392 }
02393 }
02394 if (!p)
02395 AST_LIST_UNLOCK(&agents);
02396
02397 if (!res && (max_login_tries==0 || tries < max_login_tries))
02398 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02399 }
02400
02401 if (!res)
02402 res = ast_safe_sleep(chan, 500);
02403
02404
02405 if (!callbackmode) {
02406 ast_module_user_remove(u);
02407 return -1;
02408 } else {
02409
02410 if (login_state > 0) {
02411 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
02412 if (login_state==1) {
02413 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
02414 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
02415 } else
02416 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
02417 } else {
02418 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
02419 }
02420 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
02421 ast_module_user_remove(u);
02422 return 0;
02423 }
02424
02425 if (play_announcement) {
02426 if (!res)
02427 res = ast_safe_sleep(chan, 1000);
02428 res = ast_streamfile(chan, agent_goodbye, chan->language);
02429 if (!res)
02430 res = ast_waitstream(chan, "");
02431 if (!res)
02432 res = ast_safe_sleep(chan, 1000);
02433 }
02434 }
02435
02436 ast_module_user_remove(u);
02437
02438
02439 return -1;
02440 }
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450 static int login_exec(struct ast_channel *chan, void *data)
02451 {
02452 return __login_exec(chan, data, 0);
02453 }
02454
02455 static void callback_deprecated(void)
02456 {
02457 static int depwarning = 0;
02458
02459 if (!depwarning) {
02460 depwarning = 1;
02461
02462 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02463 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02464 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02465 }
02466 }
02467
02468
02469
02470
02471
02472
02473
02474
02475
02476 static int callback_exec(struct ast_channel *chan, void *data)
02477 {
02478 callback_deprecated();
02479
02480 return __login_exec(chan, data, 1);
02481 }
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491 static int action_agent_callback_login(struct mansession *s, const struct message *m)
02492 {
02493 const char *agent = astman_get_header(m, "Agent");
02494 const char *exten = astman_get_header(m, "Exten");
02495 const char *context = astman_get_header(m, "Context");
02496 const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02497 const char *ackcall_s = astman_get_header(m, "AckCall");
02498 struct agent_pvt *p;
02499 int login_state = 0;
02500
02501 callback_deprecated();
02502
02503 if (ast_strlen_zero(agent)) {
02504 astman_send_error(s, m, "No agent specified");
02505 return 0;
02506 }
02507
02508 if (ast_strlen_zero(exten)) {
02509 astman_send_error(s, m, "No extension specified");
02510 return 0;
02511 }
02512
02513 AST_LIST_LOCK(&agents);
02514 AST_LIST_TRAVERSE(&agents, p, list) {
02515 if (strcmp(p->agent, agent) || p->pending)
02516 continue;
02517 if (p->chan) {
02518 login_state = 2;
02519 break;
02520 }
02521 ast_mutex_lock(&p->lock);
02522 login_state = 1;
02523
02524 if (ast_strlen_zero(context))
02525 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02526 else
02527 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02528
02529 if (!ast_strlen_zero(wrapuptime_s)) {
02530 p->wrapuptime = atoi(wrapuptime_s);
02531 if (p->wrapuptime < 0)
02532 p->wrapuptime = 0;
02533 }
02534
02535 if (!strcasecmp(ackcall_s, "always"))
02536 p->ackcall = 2;
02537 else if (ast_true(ackcall_s))
02538 p->ackcall = 1;
02539 else
02540 p->ackcall = 0;
02541
02542 if (p->loginstart == 0)
02543 time(&p->loginstart);
02544 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02545 "Agent: %s\r\n"
02546 "Loginchan: %s\r\n",
02547 p->agent, p->loginchan);
02548 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02549 if (option_verbose > 1)
02550 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02551 ast_device_state_changed("Agent/%s", p->agent);
02552 ast_mutex_unlock(&p->lock);
02553 if (persistent_agents)
02554 dump_agents();
02555 }
02556 AST_LIST_UNLOCK(&agents);
02557
02558 if (login_state == 1)
02559 astman_send_ack(s, m, "Agent logged in");
02560 else if (login_state == 0)
02561 astman_send_error(s, m, "No such agent");
02562 else if (login_state == 2)
02563 astman_send_error(s, m, "Agent already logged in");
02564
02565 return 0;
02566 }
02567
02568
02569
02570
02571
02572
02573
02574
02575
02576 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
02577 {
02578 int exitifnoagentid = 0;
02579 int nowarnings = 0;
02580 int changeoutgoing = 0;
02581 int res = 0;
02582 char agent[AST_MAX_AGENT];
02583
02584 if (data) {
02585 if (strchr(data, 'd'))
02586 exitifnoagentid = 1;
02587 if (strchr(data, 'n'))
02588 nowarnings = 1;
02589 if (strchr(data, 'c'))
02590 changeoutgoing = 1;
02591 }
02592 if (chan->cid.cid_num) {
02593 const char *tmp;
02594 char agentvar[AST_MAX_BUF];
02595 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02596 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02597 struct agent_pvt *p;
02598 ast_copy_string(agent, tmp, sizeof(agent));
02599 AST_LIST_LOCK(&agents);
02600 AST_LIST_TRAVERSE(&agents, p, list) {
02601 if (!strcasecmp(p->agent, tmp)) {
02602 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02603 __agent_start_monitoring(chan, p, 1);
02604 break;
02605 }
02606 }
02607 AST_LIST_UNLOCK(&agents);
02608
02609 } else {
02610 res = -1;
02611 if (!nowarnings)
02612 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);
02613 }
02614 } else {
02615 res = -1;
02616 if (!nowarnings)
02617 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");
02618 }
02619
02620
02621 if (res) {
02622 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02623 chan->priority+=100;
02624 if (option_verbose > 2)
02625 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02626 } else if (exitifnoagentid)
02627 return res;
02628 }
02629 return 0;
02630 }
02631
02632
02633
02634
02635 static void dump_agents(void)
02636 {
02637 struct agent_pvt *cur_agent = NULL;
02638 char buf[256];
02639
02640 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02641 if (cur_agent->chan)
02642 continue;
02643
02644 if (!ast_strlen_zero(cur_agent->loginchan)) {
02645 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02646 if (ast_db_put(pa_family, cur_agent->agent, buf))
02647 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02648 else if (option_debug)
02649 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02650 } else {
02651
02652 ast_db_del(pa_family, cur_agent->agent);
02653 }
02654 }
02655 }
02656
02657
02658
02659
02660 static void reload_agents(void)
02661 {
02662 char *agent_num;
02663 struct ast_db_entry *db_tree;
02664 struct ast_db_entry *entry;
02665 struct agent_pvt *cur_agent;
02666 char agent_data[256];
02667 char *parse;
02668 char *agent_chan;
02669 char *agent_callerid;
02670
02671 db_tree = ast_db_gettree(pa_family, NULL);
02672
02673 AST_LIST_LOCK(&agents);
02674 for (entry = db_tree; entry; entry = entry->next) {
02675 agent_num = entry->key + strlen(pa_family) + 2;
02676 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02677 ast_mutex_lock(&cur_agent->lock);
02678 if (strcmp(agent_num, cur_agent->agent) == 0)
02679 break;
02680 ast_mutex_unlock(&cur_agent->lock);
02681 }
02682 if (!cur_agent) {
02683 ast_db_del(pa_family, agent_num);
02684 continue;
02685 } else
02686 ast_mutex_unlock(&cur_agent->lock);
02687 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02688 if (option_debug)
02689 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02690 parse = agent_data;
02691 agent_chan = strsep(&parse, ";");
02692 agent_callerid = strsep(&parse, ";");
02693 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02694 if (agent_callerid) {
02695 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02696 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02697 } else
02698 cur_agent->logincallerid[0] = '\0';
02699 if (cur_agent->loginstart == 0)
02700 time(&cur_agent->loginstart);
02701 ast_device_state_changed("Agent/%s", cur_agent->agent);
02702 }
02703 }
02704 AST_LIST_UNLOCK(&agents);
02705 if (db_tree) {
02706 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02707 ast_db_freetree(db_tree);
02708 }
02709 }
02710
02711
02712 static int agent_devicestate(void *data)
02713 {
02714 struct agent_pvt *p;
02715 char *s;
02716 ast_group_t groupmatch;
02717 int groupoff;
02718 int waitforagent=0;
02719 int res = AST_DEVICE_INVALID;
02720
02721 s = data;
02722 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02723 char tmp[12];
02724 sprintf(tmp, "%d", groupoff);
02725 ast_get_group(&groupmatch, tmp);
02726 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02727 char tmp[12];
02728 sprintf(tmp, "%d", groupoff);
02729 ast_get_group(&groupmatch, tmp);
02730 waitforagent = 1;
02731 } else {
02732 memset(&groupmatch, 0, sizeof(groupmatch));
02733 }
02734
02735
02736 AST_LIST_LOCK(&agents);
02737 AST_LIST_TRAVERSE(&agents, p, list) {
02738 ast_mutex_lock(&p->lock);
02739 if (!p->pending && ((!ast_is_empty_group(&groupmatch) && ast_have_common_group(&p->group, &groupmatch)) || !strcmp(data, p->agent))) {
02740 if (p->owner) {
02741 if (res != AST_DEVICE_INUSE)
02742 res = AST_DEVICE_BUSY;
02743 } else if (p->inherited_devicestate > -1) {
02744 res = p->inherited_devicestate;
02745 } else {
02746 if (res == AST_DEVICE_BUSY)
02747 res = AST_DEVICE_INUSE;
02748 if (p->chan || !ast_strlen_zero(p->loginchan)) {
02749 if (res == AST_DEVICE_INVALID)
02750 res = AST_DEVICE_UNKNOWN;
02751 } else if (res == AST_DEVICE_INVALID)
02752 res = AST_DEVICE_UNAVAILABLE;
02753 }
02754 if (!strcmp(data, p->agent)) {
02755 ast_mutex_unlock(&p->lock);
02756 break;
02757 }
02758 }
02759 ast_mutex_unlock(&p->lock);
02760 }
02761 AST_LIST_UNLOCK(&agents);
02762 return res;
02763 }
02764
02765
02766
02767
02768 static struct agent_pvt *find_agent(char *agentid)
02769 {
02770 struct agent_pvt *cur;
02771
02772 AST_LIST_TRAVERSE(&agents, cur, list) {
02773 if (!strcmp(cur->agent, agentid))
02774 break;
02775 }
02776
02777 return cur;
02778 }
02779
02780 static int function_agent(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
02781 {
02782 char *parse;
02783 AST_DECLARE_APP_ARGS(args,
02784 AST_APP_ARG(agentid);
02785 AST_APP_ARG(item);
02786 );
02787 char *tmp;
02788 struct agent_pvt *agent;
02789
02790 buf[0] = '\0';
02791
02792 if (ast_strlen_zero(data)) {
02793 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02794 return -1;
02795 }
02796
02797 parse = ast_strdupa(data);
02798
02799 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02800 if (!args.item)
02801 args.item = "status";
02802
02803 AST_LIST_LOCK(&agents);
02804
02805 if (!(agent = find_agent(args.agentid))) {
02806 AST_LIST_UNLOCK(&agents);
02807 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02808 return -1;
02809 }
02810
02811 if (!strcasecmp(args.item, "status")) {
02812 char *status = "LOGGEDOUT";
02813 if (agent->chan || !ast_strlen_zero(agent->loginchan))
02814 status = "LOGGEDIN";
02815 ast_copy_string(buf, status, len);
02816 } else if (!strcasecmp(args.item, "password"))
02817 ast_copy_string(buf, agent->password, len);
02818 else if (!strcasecmp(args.item, "name"))
02819 ast_copy_string(buf, agent->name, len);
02820 else if (!strcasecmp(args.item, "mohclass"))
02821 ast_copy_string(buf, agent->moh, len);
02822 else if (!strcasecmp(args.item, "channel")) {
02823 if (agent->chan) {
02824 ast_channel_lock(agent->chan);
02825 ast_copy_string(buf, agent->chan->name, len);
02826 ast_channel_unlock(agent->chan);
02827 tmp = strrchr(buf, '-');
02828 if (tmp)
02829 *tmp = '\0';
02830 }
02831 } else if (!strcasecmp(args.item, "exten"))
02832 ast_copy_string(buf, agent->loginchan, len);
02833
02834 AST_LIST_UNLOCK(&agents);
02835
02836 return 0;
02837 }
02838
02839 struct ast_custom_function agent_function = {
02840 .name = "AGENT",
02841 .synopsis = "Gets information about an Agent",
02842 .syntax = "AGENT(<agentid>[:item])",
02843 .read = function_agent,
02844 .desc = "The valid items to retrieve are:\n"
02845 "- status (default) The status of the agent\n"
02846 " LOGGEDIN | LOGGEDOUT\n"
02847 "- password The password of the agent\n"
02848 "- name The name of the agent\n"
02849 "- mohclass MusicOnHold class\n"
02850 "- exten The callback extension for the Agent (AgentCallbackLogin)\n"
02851 "- channel The name of the active channel for the Agent (AgentLogin)\n"
02852 };
02853
02854
02855
02856
02857
02858
02859
02860
02861
02862 static int load_module(void)
02863 {
02864
02865 if (ast_channel_register(&agent_tech)) {
02866 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02867 return -1;
02868 }
02869
02870 if (!read_agent_config())
02871 return AST_MODULE_LOAD_DECLINE;
02872 if (persistent_agents)
02873 reload_agents();
02874
02875 ast_register_application(app, login_exec, synopsis, descrip);
02876 ast_register_application(app2, callback_exec, synopsis2, descrip2);
02877 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02878
02879
02880 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02881 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02882 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02883
02884
02885 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02886
02887
02888 ast_custom_function_register(&agent_function);
02889
02890 ast_devstate_add(agent_devicestate_cb, NULL);
02891
02892 return 0;
02893 }
02894
02895 static int reload(void)
02896 {
02897 read_agent_config();
02898 if (persistent_agents)
02899 reload_agents();
02900 return 0;
02901 }
02902
02903 static int unload_module(void)
02904 {
02905 struct agent_pvt *p;
02906
02907 ast_channel_unregister(&agent_tech);
02908
02909 ast_devstate_del(agent_devicestate_cb, NULL);
02910
02911 ast_custom_function_unregister(&agent_function);
02912
02913 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02914
02915 ast_unregister_application(app);
02916 ast_unregister_application(app2);
02917 ast_unregister_application(app3);
02918
02919 ast_manager_unregister("Agents");
02920 ast_manager_unregister("AgentLogoff");
02921 ast_manager_unregister("AgentCallbackLogin");
02922
02923 AST_LIST_LOCK(&agents);
02924
02925 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02926 if (p->owner)
02927 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02928 free(p);
02929 }
02930 AST_LIST_UNLOCK(&agents);
02931 return 0;
02932 }
02933
02934 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
02935 .load = load_module,
02936 .unload = unload_module,
02937 .reload = reload,
02938 );