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