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