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