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