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