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