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: 354884 $")
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_channel_lock(p->chan);
00970 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00971 ast_channel_unlock(p->chan);
00972 } else if (p->loginstart) {
00973 indicate_chan = ast_channel_ref(p->chan);
00974 tmp_moh = ast_strdupa(p->moh);
00975 }
00976 }
00977 ast_mutex_unlock(&p->lock);
00978
00979 if (indicate_chan) {
00980 ast_channel_lock(indicate_chan);
00981 ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
00982 S_OR(tmp_moh, NULL),
00983 !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
00984 ast_channel_unlock(indicate_chan);
00985 indicate_chan = ast_channel_unref(indicate_chan);
00986 }
00987
00988
00989 if (!p->loginstart) {
00990 p->logincallerid[0] = '\0';
00991 } else {
00992 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
00993 }
00994
00995 if (p->abouttograb) {
00996
00997
00998 p->abouttograb = 0;
00999 } else if (p->dead) {
01000 ast_mutex_destroy(&p->lock);
01001 ast_cond_destroy(&p->app_complete_cond);
01002 ast_cond_destroy(&p->login_wait_cond);
01003 ast_free(p);
01004 } else {
01005 if (p->chan) {
01006
01007 ast_mutex_lock(&p->lock);
01008
01009 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
01010 ast_mutex_unlock(&p->lock);
01011 }
01012 }
01013 return 0;
01014 }
01015
01016 static int agent_cont_sleep( void *data )
01017 {
01018 struct agent_pvt *p;
01019 int res;
01020
01021 p = (struct agent_pvt *)data;
01022
01023 ast_mutex_lock(&p->lock);
01024 res = p->app_sleep_cond;
01025 if (p->lastdisc.tv_sec) {
01026 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
01027 res = 1;
01028 }
01029 ast_mutex_unlock(&p->lock);
01030
01031 if (!res)
01032 ast_debug(5, "agent_cont_sleep() returning %d\n", res );
01033
01034 return res;
01035 }
01036
01037 static int agent_ack_sleep(void *data)
01038 {
01039 struct agent_pvt *p;
01040 int res=0;
01041 int to = 1000;
01042 struct ast_frame *f;
01043
01044
01045
01046 p = (struct agent_pvt *) data;
01047 if (!p->chan)
01048 return -1;
01049
01050 for(;;) {
01051 to = ast_waitfor(p->chan, to);
01052 if (to < 0)
01053 return -1;
01054 if (!to)
01055 return 0;
01056 f = ast_read(p->chan);
01057 if (!f)
01058 return -1;
01059 if (f->frametype == AST_FRAME_DTMF)
01060 res = f->subclass.integer;
01061 else
01062 res = 0;
01063 ast_frfree(f);
01064 ast_mutex_lock(&p->lock);
01065 if (!p->app_sleep_cond) {
01066 ast_mutex_unlock(&p->lock);
01067 return 0;
01068 } else if (res == p->acceptdtmf) {
01069 ast_mutex_unlock(&p->lock);
01070 return 1;
01071 }
01072 ast_mutex_unlock(&p->lock);
01073 res = 0;
01074 }
01075 return res;
01076 }
01077
01078 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
01079 {
01080 struct agent_pvt *p = bridge->tech_pvt;
01081 struct ast_channel *ret = NULL;
01082
01083 if (p) {
01084 if (chan == p->chan)
01085 ret = bridge->_bridge;
01086 else if (chan == bridge->_bridge)
01087 ret = p->chan;
01088 }
01089
01090 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01091 return ret;
01092 }
01093
01094
01095 static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid)
01096 {
01097 struct ast_channel *tmp;
01098 #if 0
01099 if (!p->chan) {
01100 ast_log(LOG_WARNING, "No channel? :(\n");
01101 return NULL;
01102 }
01103 #endif
01104 if (p->pending)
01105 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);
01106 else
01107 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent);
01108 if (!tmp) {
01109 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01110 return NULL;
01111 }
01112
01113 tmp->tech = &agent_tech;
01114 if (p->chan) {
01115 tmp->nativeformats = p->chan->nativeformats;
01116 tmp->writeformat = p->chan->writeformat;
01117 tmp->rawwriteformat = p->chan->writeformat;
01118 tmp->readformat = p->chan->readformat;
01119 tmp->rawreadformat = p->chan->readformat;
01120 ast_string_field_set(tmp, language, p->chan->language);
01121 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01122 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01123
01124 } else {
01125 tmp->nativeformats = AST_FORMAT_SLINEAR;
01126 tmp->writeformat = AST_FORMAT_SLINEAR;
01127 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01128 tmp->readformat = AST_FORMAT_SLINEAR;
01129 tmp->rawreadformat = AST_FORMAT_SLINEAR;
01130 }
01131
01132 tmp->tech_pvt = p;
01133 p->owner = tmp;
01134 tmp->priority = 1;
01135 return tmp;
01136 }
01137
01138
01139
01140
01141
01142
01143
01144 static int read_agent_config(int reload)
01145 {
01146 struct ast_config *cfg;
01147 struct ast_config *ucfg;
01148 struct ast_variable *v;
01149 struct agent_pvt *p;
01150 const char *catname;
01151 const char *hasagent;
01152 int genhasagent;
01153 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01154
01155 group = 0;
01156 autologoff = 0;
01157 wrapuptime = 0;
01158 ackcall = 0;
01159 endcall = 1;
01160 cfg = ast_config_load(config, config_flags);
01161 if (!cfg) {
01162 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01163 return 0;
01164 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
01165 return -1;
01166 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01167 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config);
01168 return 0;
01169 }
01170 if ((ucfg = ast_config_load("users.conf", config_flags))) {
01171 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
01172 ucfg = NULL;
01173 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
01174 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n");
01175 return 0;
01176 }
01177 }
01178
01179 AST_LIST_LOCK(&agents);
01180 AST_LIST_TRAVERSE(&agents, p, list) {
01181 p->dead = 1;
01182 }
01183 strcpy(moh, "default");
01184
01185 recordagentcalls = 0;
01186 strcpy(recordformat, "wav");
01187 strcpy(recordformatext, "wav");
01188 urlprefix[0] = '\0';
01189 savecallsin[0] = '\0';
01190
01191
01192 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
01193
01194
01195 v = ast_variable_browse(cfg, "agents");
01196 while(v) {
01197
01198 if (!strcasecmp(v->name, "agent")) {
01199 add_agent(v->value, 0);
01200 } else if (!strcasecmp(v->name, "group")) {
01201 group = ast_get_group(v->value);
01202 } else if (!strcasecmp(v->name, "autologoff")) {
01203 autologoff = atoi(v->value);
01204 if (autologoff < 0)
01205 autologoff = 0;
01206 } else if (!strcasecmp(v->name, "ackcall")) {
01207 if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
01208 ackcall = 1;
01209 }
01210 } else if (!strcasecmp(v->name, "endcall")) {
01211 endcall = ast_true(v->value);
01212 } else if (!strcasecmp(v->name, "acceptdtmf")) {
01213 acceptdtmf = *(v->value);
01214 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
01215 } else if (!strcasecmp(v->name, "enddtmf")) {
01216 enddtmf = *(v->value);
01217 } else if (!strcasecmp(v->name, "wrapuptime")) {
01218 wrapuptime = atoi(v->value);
01219 if (wrapuptime < 0)
01220 wrapuptime = 0;
01221 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01222 maxlogintries = atoi(v->value);
01223 if (maxlogintries < 0)
01224 maxlogintries = 0;
01225 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01226 strcpy(agentgoodbye,v->value);
01227 } else if (!strcasecmp(v->name, "musiconhold")) {
01228 ast_copy_string(moh, v->value, sizeof(moh));
01229 } else if (!strcasecmp(v->name, "updatecdr")) {
01230 if (ast_true(v->value))
01231 updatecdr = 1;
01232 else
01233 updatecdr = 0;
01234 } else if (!strcasecmp(v->name, "autologoffunavail")) {
01235 if (ast_true(v->value))
01236 autologoffunavail = 1;
01237 else
01238 autologoffunavail = 0;
01239 } else if (!strcasecmp(v->name, "recordagentcalls")) {
01240 recordagentcalls = ast_true(v->value);
01241 } else if (!strcasecmp(v->name, "recordformat")) {
01242 ast_copy_string(recordformat, v->value, sizeof(recordformat));
01243 if (!strcasecmp(v->value, "wav49"))
01244 strcpy(recordformatext, "WAV");
01245 else
01246 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01247 } else if (!strcasecmp(v->name, "urlprefix")) {
01248 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01249 if (urlprefix[strlen(urlprefix) - 1] != '/')
01250 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01251 } else if (!strcasecmp(v->name, "savecallsin")) {
01252 if (v->value[0] == '/')
01253 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01254 else
01255 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01256 if (savecallsin[strlen(savecallsin) - 1] != '/')
01257 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01258 } else if (!strcasecmp(v->name, "custom_beep")) {
01259 ast_copy_string(beep, v->value, sizeof(beep));
01260 }
01261 v = v->next;
01262 }
01263 if (ucfg) {
01264 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01265 catname = ast_category_browse(ucfg, NULL);
01266 while(catname) {
01267 if (strcasecmp(catname, "general")) {
01268 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01269 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01270 char tmp[256];
01271 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01272 const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01273 if (!fullname)
01274 fullname = "";
01275 if (!secret)
01276 secret = "";
01277 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01278 add_agent(tmp, 0);
01279 }
01280 }
01281 catname = ast_category_browse(ucfg, catname);
01282 }
01283 ast_config_destroy(ucfg);
01284 }
01285 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01286 if (p->dead) {
01287 AST_LIST_REMOVE_CURRENT(list);
01288
01289 if (!p->owner) {
01290 if (!p->chan) {
01291 ast_mutex_destroy(&p->lock);
01292 ast_cond_destroy(&p->app_complete_cond);
01293 ast_cond_destroy(&p->login_wait_cond);
01294 ast_free(p);
01295 } else {
01296
01297 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01298 }
01299 }
01300 }
01301 }
01302 AST_LIST_TRAVERSE_SAFE_END;
01303 AST_LIST_UNLOCK(&agents);
01304 ast_config_destroy(cfg);
01305 return 1;
01306 }
01307
01308 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
01309 {
01310 struct ast_channel *chan=NULL, *parent=NULL;
01311 struct agent_pvt *p;
01312 int res;
01313
01314 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
01315 if (needlock)
01316 AST_LIST_LOCK(&agents);
01317 AST_LIST_TRAVERSE(&agents, p, list) {
01318 if (p == newlyavailable) {
01319 continue;
01320 }
01321 ast_mutex_lock(&p->lock);
01322 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01323 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01324
01325 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL);
01326 parent = p->owner;
01327 p->abouttograb = 1;
01328 ast_mutex_unlock(&p->lock);
01329 break;
01330 }
01331 ast_mutex_unlock(&p->lock);
01332 }
01333 if (needlock)
01334 AST_LIST_UNLOCK(&agents);
01335 if (parent && chan) {
01336 if (newlyavailable->ackcall) {
01337
01338 res = 0;
01339 } else {
01340 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01341 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01342 ast_debug(3, "Played beep, result '%d'\n", res);
01343 if (!res) {
01344 res = ast_waitstream(newlyavailable->chan, "");
01345 ast_debug(1, "Waited for stream, result '%d'\n", res);
01346 }
01347 }
01348 if (!res) {
01349
01350 if (p->abouttograb) {
01351 newlyavailable->acknowledged = 1;
01352
01353 ast_setstate(parent, AST_STATE_UP);
01354 ast_setstate(chan, AST_STATE_UP);
01355 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01356 ast_channel_masquerade(parent, chan);
01357 ast_hangup(chan);
01358 p->abouttograb = 0;
01359 } else {
01360 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
01361 agent_cleanup(newlyavailable);
01362 }
01363 } else {
01364 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n");
01365 agent_cleanup(newlyavailable);
01366 }
01367 }
01368 return 0;
01369 }
01370
01371 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
01372 {
01373 struct agent_pvt *p;
01374 int res=0;
01375
01376 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01377 if (needlock)
01378 AST_LIST_LOCK(&agents);
01379 AST_LIST_TRAVERSE(&agents, p, list) {
01380 if (p == newlyavailable) {
01381 continue;
01382 }
01383 ast_mutex_lock(&p->lock);
01384 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01385 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01386 ast_mutex_unlock(&p->lock);
01387 break;
01388 }
01389 ast_mutex_unlock(&p->lock);
01390 }
01391 if (needlock)
01392 AST_LIST_UNLOCK(&agents);
01393 if (p) {
01394 ast_mutex_unlock(&newlyavailable->lock);
01395 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01396 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01397 ast_debug(1, "Played beep, result '%d'\n", res);
01398 if (!res) {
01399 res = ast_waitstream(newlyavailable->chan, "");
01400 ast_debug(1, "Waited for stream, result '%d'\n", res);
01401 }
01402 ast_mutex_lock(&newlyavailable->lock);
01403 }
01404 return res;
01405 }
01406
01407
01408 static struct ast_channel *agent_request(const char *type, format_t format, const struct ast_channel* requestor, void *data, int *cause)
01409 {
01410 struct agent_pvt *p;
01411 struct ast_channel *chan = NULL;
01412 char *s;
01413 ast_group_t groupmatch;
01414 int groupoff;
01415 int waitforagent=0;
01416 int hasagent = 0;
01417 struct timeval now;
01418
01419 s = data;
01420 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01421 groupmatch = (1 << groupoff);
01422 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01423 groupmatch = (1 << groupoff);
01424 waitforagent = 1;
01425 } else
01426 groupmatch = 0;
01427
01428
01429 AST_LIST_LOCK(&agents);
01430 AST_LIST_TRAVERSE(&agents, p, list) {
01431 ast_mutex_lock(&p->lock);
01432 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01433 if (p->chan)
01434 hasagent++;
01435 now = ast_tvnow();
01436 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01437 p->lastdisc = ast_tv(0, 0);
01438
01439 if (!p->owner && p->chan) {
01440
01441 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01442 }
01443 if (chan) {
01444 ast_mutex_unlock(&p->lock);
01445 break;
01446 }
01447 }
01448 }
01449 ast_mutex_unlock(&p->lock);
01450 }
01451 if (!p) {
01452 AST_LIST_TRAVERSE(&agents, p, list) {
01453 ast_mutex_lock(&p->lock);
01454 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01455 if (p->chan) {
01456 hasagent++;
01457 }
01458 now = ast_tvnow();
01459 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01460 p->lastdisc = ast_tv(0, 0);
01461
01462 if (!p->owner && p->chan) {
01463
01464 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01465 }
01466 if (chan) {
01467 ast_mutex_unlock(&p->lock);
01468 break;
01469 }
01470 }
01471 }
01472 ast_mutex_unlock(&p->lock);
01473 }
01474 }
01475
01476 if (!chan && waitforagent) {
01477
01478
01479 if (hasagent) {
01480 ast_debug(1, "Creating place holder for '%s'\n", s);
01481 p = add_agent(data, 1);
01482 p->group = groupmatch;
01483 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01484 if (!chan)
01485 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
01486 } else {
01487 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
01488 }
01489 }
01490 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01491 AST_LIST_UNLOCK(&agents);
01492
01493 if (chan) {
01494 ast_mutex_lock(&p->lock);
01495 if (p->pending) {
01496 ast_mutex_unlock(&p->lock);
01497 return chan;
01498 }
01499
01500 if (!p->chan) {
01501 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01502 *cause = AST_CAUSE_UNREGISTERED;
01503 ast_mutex_unlock(&p->lock);
01504 agent_hangup(chan);
01505 return NULL;
01506 }
01507
01508
01509
01510 p->app_sleep_cond = 0;
01511 p->app_lock_flag = 1;
01512
01513 ast_queue_frame(p->chan, &ast_null_frame);
01514 ast_cond_wait(&p->login_wait_cond, &p->lock);
01515
01516 if (!p->chan) {
01517 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01518 p->app_sleep_cond = 1;
01519 p->app_lock_flag = 0;
01520 ast_cond_signal(&p->app_complete_cond);
01521 ast_mutex_unlock(&p->lock);
01522 *cause = AST_CAUSE_UNREGISTERED;
01523 agent_hangup(chan);
01524 return NULL;
01525 }
01526
01527 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01528 ast_mutex_unlock(&p->lock);
01529 }
01530
01531 return chan;
01532 }
01533
01534 static force_inline int powerof(unsigned int d)
01535 {
01536 int x = ffs(d);
01537
01538 if (x)
01539 return x - 1;
01540
01541 return 0;
01542 }
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554 static int action_agents(struct mansession *s, const struct message *m)
01555 {
01556 const char *id = astman_get_header(m,"ActionID");
01557 char idText[256] = "";
01558 struct agent_pvt *p;
01559 char *username = NULL;
01560 char *loginChan = NULL;
01561 char *talkingto = NULL;
01562 char *talkingtoChan = NULL;
01563 char *status = NULL;
01564 struct ast_channel *bridge;
01565
01566 if (!ast_strlen_zero(id))
01567 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01568 astman_send_ack(s, m, "Agents will follow");
01569 AST_LIST_LOCK(&agents);
01570 AST_LIST_TRAVERSE(&agents, p, list) {
01571 struct ast_channel *owner;
01572 ast_mutex_lock(&p->lock);
01573 owner = agent_lock_owner(p);
01574
01575
01576
01577
01578
01579
01580
01581 username = S_OR(p->name, "None");
01582
01583
01584 status = "AGENT_UNKNOWN";
01585
01586 if (p->chan) {
01587 loginChan = ast_strdupa(p->chan->name);
01588 if (owner && owner->_bridge) {
01589 talkingto = S_COR(p->chan->caller.id.number.valid,
01590 p->chan->caller.id.number.str, "n/a");
01591 if ((bridge = ast_bridged_channel(owner))) {
01592 talkingtoChan = ast_strdupa(bridge->name);
01593 } else {
01594 talkingtoChan = "n/a";
01595 }
01596 status = "AGENT_ONCALL";
01597 } else {
01598 talkingto = "n/a";
01599 talkingtoChan = "n/a";
01600 status = "AGENT_IDLE";
01601 }
01602 } else {
01603 loginChan = "n/a";
01604 talkingto = "n/a";
01605 talkingtoChan = "n/a";
01606 status = "AGENT_LOGGEDOFF";
01607 }
01608
01609 if (owner) {
01610 ast_channel_unlock(owner);
01611 owner = ast_channel_unref(owner);
01612 }
01613
01614 astman_append(s, "Event: Agents\r\n"
01615 "Agent: %s\r\n"
01616 "Name: %s\r\n"
01617 "Status: %s\r\n"
01618 "LoggedInChan: %s\r\n"
01619 "LoggedInTime: %d\r\n"
01620 "TalkingTo: %s\r\n"
01621 "TalkingToChan: %s\r\n"
01622 "%s"
01623 "\r\n",
01624 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
01625 ast_mutex_unlock(&p->lock);
01626 }
01627 AST_LIST_UNLOCK(&agents);
01628 astman_append(s, "Event: AgentsComplete\r\n"
01629 "%s"
01630 "\r\n",idText);
01631 return 0;
01632 }
01633
01634 static int agent_logoff(const char *agent, int soft)
01635 {
01636 struct agent_pvt *p;
01637 int ret = -1;
01638
01639 AST_LIST_LOCK(&agents);
01640 AST_LIST_TRAVERSE(&agents, p, list) {
01641 if (!strcasecmp(p->agent, agent)) {
01642 ret = 0;
01643 if (p->owner || p->chan) {
01644 if (!soft) {
01645 struct ast_channel *owner;
01646 ast_mutex_lock(&p->lock);
01647 owner = agent_lock_owner(p);
01648
01649 if (owner) {
01650 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
01651 ast_channel_unlock(owner);
01652 owner = ast_channel_unref(owner);
01653 }
01654
01655 while (p->chan && ast_channel_trylock(p->chan)) {
01656 DEADLOCK_AVOIDANCE(&p->lock);
01657 }
01658 if (p->chan) {
01659 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01660 ast_channel_unlock(p->chan);
01661 }
01662
01663 ast_mutex_unlock(&p->lock);
01664 } else
01665 p->deferlogoff = 1;
01666 }
01667 break;
01668 }
01669 }
01670 AST_LIST_UNLOCK(&agents);
01671
01672 return ret;
01673 }
01674
01675 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01676 {
01677 int ret;
01678 const char *agent;
01679
01680 switch (cmd) {
01681 case CLI_INIT:
01682 e->command = "agent logoff";
01683 e->usage =
01684 "Usage: agent logoff <channel> [soft]\n"
01685 " Sets an agent as no longer logged in.\n"
01686 " If 'soft' is specified, do not hangup existing calls.\n";
01687 return NULL;
01688 case CLI_GENERATE:
01689 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n);
01690 }
01691
01692 if (a->argc < 3 || a->argc > 4)
01693 return CLI_SHOWUSAGE;
01694 if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01695 return CLI_SHOWUSAGE;
01696
01697 agent = a->argv[2] + 6;
01698 ret = agent_logoff(agent, a->argc == 4);
01699 if (ret == 0)
01700 ast_cli(a->fd, "Logging out %s\n", agent);
01701
01702 return CLI_SUCCESS;
01703 }
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713 static int action_agent_logoff(struct mansession *s, const struct message *m)
01714 {
01715 const char *agent = astman_get_header(m, "Agent");
01716 const char *soft_s = astman_get_header(m, "Soft");
01717 int soft;
01718 int ret;
01719
01720 if (ast_strlen_zero(agent)) {
01721 astman_send_error(s, m, "No agent specified");
01722 return 0;
01723 }
01724
01725 soft = ast_true(soft_s) ? 1 : 0;
01726 ret = agent_logoff(agent, soft);
01727 if (ret == 0)
01728 astman_send_ack(s, m, "Agent logged out");
01729 else
01730 astman_send_error(s, m, "No such agent");
01731
01732 return 0;
01733 }
01734
01735 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
01736 {
01737 char *ret = NULL;
01738
01739 if (pos == 2) {
01740 struct agent_pvt *p;
01741 char name[AST_MAX_AGENT];
01742 int which = 0, len = strlen(word);
01743
01744 AST_LIST_LOCK(&agents);
01745 AST_LIST_TRAVERSE(&agents, p, list) {
01746 snprintf(name, sizeof(name), "Agent/%s", p->agent);
01747 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01748 ret = ast_strdup(name);
01749 break;
01750 }
01751 }
01752 AST_LIST_UNLOCK(&agents);
01753 } else if (pos == 3 && state == 0)
01754 return ast_strdup("soft");
01755
01756 return ret;
01757 }
01758
01759
01760
01761
01762 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01763 {
01764 struct agent_pvt *p;
01765 char username[AST_MAX_BUF];
01766 char location[AST_MAX_BUF] = "";
01767 char talkingto[AST_MAX_BUF] = "";
01768 char music[AST_MAX_BUF];
01769 int count_agents = 0;
01770 int online_agents = 0;
01771 int offline_agents = 0;
01772
01773 switch (cmd) {
01774 case CLI_INIT:
01775 e->command = "agent show";
01776 e->usage =
01777 "Usage: agent show\n"
01778 " Provides summary information on agents.\n";
01779 return NULL;
01780 case CLI_GENERATE:
01781 return NULL;
01782 }
01783
01784 if (a->argc != 2)
01785 return CLI_SHOWUSAGE;
01786
01787 AST_LIST_LOCK(&agents);
01788 AST_LIST_TRAVERSE(&agents, p, list) {
01789 struct ast_channel *owner;
01790 ast_mutex_lock(&p->lock);
01791 owner = agent_lock_owner(p);
01792 if (p->pending) {
01793 if (p->group)
01794 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01795 else
01796 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01797 } else {
01798 if (!ast_strlen_zero(p->name))
01799 snprintf(username, sizeof(username), "(%s) ", p->name);
01800 else
01801 username[0] = '\0';
01802 if (p->chan) {
01803 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01804 if (owner && ast_bridged_channel(owner)) {
01805 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01806 } else {
01807 strcpy(talkingto, " is idle");
01808 }
01809 online_agents++;
01810 } else {
01811 strcpy(location, "not logged in");
01812 talkingto[0] = '\0';
01813 offline_agents++;
01814 }
01815 if (!ast_strlen_zero(p->moh))
01816 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01817 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent,
01818 username, location, talkingto, music);
01819 count_agents++;
01820 }
01821
01822 if (owner) {
01823 ast_channel_unlock(owner);
01824 owner = ast_channel_unref(owner);
01825 }
01826 ast_mutex_unlock(&p->lock);
01827 }
01828 AST_LIST_UNLOCK(&agents);
01829 if ( !count_agents )
01830 ast_cli(a->fd, "No Agents are configured in %s\n",config);
01831 else
01832 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01833 ast_cli(a->fd, "\n");
01834
01835 return CLI_SUCCESS;
01836 }
01837
01838
01839 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01840 {
01841 struct agent_pvt *p;
01842 char username[AST_MAX_BUF];
01843 char location[AST_MAX_BUF] = "";
01844 char talkingto[AST_MAX_BUF] = "";
01845 char music[AST_MAX_BUF];
01846 int count_agents = 0;
01847 int online_agents = 0;
01848 int agent_status = 0;
01849
01850 switch (cmd) {
01851 case CLI_INIT:
01852 e->command = "agent show online";
01853 e->usage =
01854 "Usage: agent show online\n"
01855 " Provides a list of all online agents.\n";
01856 return NULL;
01857 case CLI_GENERATE:
01858 return NULL;
01859 }
01860
01861 if (a->argc != 3)
01862 return CLI_SHOWUSAGE;
01863
01864 AST_LIST_LOCK(&agents);
01865 AST_LIST_TRAVERSE(&agents, p, list) {
01866 struct ast_channel *owner;
01867
01868 agent_status = 0;
01869 ast_mutex_lock(&p->lock);
01870 owner = agent_lock_owner(p);
01871
01872 if (!ast_strlen_zero(p->name))
01873 snprintf(username, sizeof(username), "(%s) ", p->name);
01874 else
01875 username[0] = '\0';
01876 if (p->chan) {
01877 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01878 if (owner && ast_bridged_channel(owner)) {
01879 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name);
01880 } else {
01881 strcpy(talkingto, " is idle");
01882 }
01883 agent_status = 1;
01884 online_agents++;
01885 }
01886
01887 if (owner) {
01888 ast_channel_unlock(owner);
01889 owner = ast_channel_unref(owner);
01890 }
01891
01892 if (!ast_strlen_zero(p->moh))
01893 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01894 if (agent_status)
01895 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01896 count_agents++;
01897 ast_mutex_unlock(&p->lock);
01898 }
01899 AST_LIST_UNLOCK(&agents);
01900 if (!count_agents)
01901 ast_cli(a->fd, "No Agents are configured in %s\n", config);
01902 else
01903 ast_cli(a->fd, "%d agents online\n", online_agents);
01904 ast_cli(a->fd, "\n");
01905 return CLI_SUCCESS;
01906 }
01907
01908 static const char agent_logoff_usage[] =
01909 "Usage: agent logoff <channel> [soft]\n"
01910 " Sets an agent as no longer logged in.\n"
01911 " If 'soft' is specified, do not hangup existing calls.\n";
01912
01913 static struct ast_cli_entry cli_agents[] = {
01914 AST_CLI_DEFINE(agents_show, "Show status of agents"),
01915 AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
01916 AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
01917 };
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929 static int login_exec(struct ast_channel *chan, const char *data)
01930 {
01931 int res=0;
01932 int tries = 0;
01933 int max_login_tries = maxlogintries;
01934 struct agent_pvt *p;
01935 struct ast_module_user *u;
01936 char user[AST_MAX_AGENT] = "";
01937 char pass[AST_MAX_AGENT];
01938 char agent[AST_MAX_AGENT] = "";
01939 char xpass[AST_MAX_AGENT] = "";
01940 char *errmsg;
01941 char *parse;
01942 AST_DECLARE_APP_ARGS(args,
01943 AST_APP_ARG(agent_id);
01944 AST_APP_ARG(options);
01945 AST_APP_ARG(extension);
01946 );
01947 const char *tmpoptions = NULL;
01948 int play_announcement = 1;
01949 char agent_goodbye[AST_MAX_FILENAME_LEN];
01950 int update_cdr = updatecdr;
01951 char *filename = "agent-loginok";
01952
01953 u = ast_module_user_add(chan);
01954
01955 parse = ast_strdupa(data);
01956
01957 AST_STANDARD_APP_ARGS(args, parse);
01958
01959 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
01960
01961 ast_channel_lock(chan);
01962
01963 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
01964 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
01965 if (max_login_tries < 0)
01966 max_login_tries = 0;
01967 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
01968 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
01969 }
01970 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
01971 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
01972 update_cdr = 1;
01973 else
01974 update_cdr = 0;
01975 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
01976 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
01977 }
01978 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
01979 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
01980 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
01981 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
01982 }
01983 ast_channel_unlock(chan);
01984
01985
01986 if (!ast_strlen_zero(args.options)) {
01987 if (strchr(args.options, 's')) {
01988 play_announcement = 0;
01989 }
01990 }
01991
01992 if (chan->_state != AST_STATE_UP)
01993 res = ast_answer(chan);
01994 if (!res) {
01995 if (!ast_strlen_zero(args.agent_id))
01996 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
01997 else
01998 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
01999 }
02000 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
02001 tries++;
02002
02003 AST_LIST_LOCK(&agents);
02004 AST_LIST_TRAVERSE(&agents, p, list) {
02005 if (!strcmp(p->agent, user) && !p->pending)
02006 ast_copy_string(xpass, p->password, sizeof(xpass));
02007 }
02008 AST_LIST_UNLOCK(&agents);
02009 if (!res) {
02010 if (!ast_strlen_zero(xpass))
02011 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
02012 else
02013 pass[0] = '\0';
02014 }
02015 errmsg = "agent-incorrect";
02016
02017 #if 0
02018 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
02019 #endif
02020
02021
02022 AST_LIST_LOCK(&agents);
02023 AST_LIST_TRAVERSE(&agents, p, list) {
02024 int unlock_channel = 1;
02025 ast_channel_lock(chan);
02026 ast_mutex_lock(&p->lock);
02027 if (!strcmp(p->agent, user) &&
02028 !strcmp(p->password, pass) && !p->pending) {
02029
02030
02031 p->lastdisc = ast_tvnow();
02032 p->lastdisc.tv_sec++;
02033
02034
02035 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02036 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02037 p->ackcall = 1;
02038 } else {
02039 p->ackcall = 0;
02040 }
02041 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
02042 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
02043 ast_set_flag(p, AGENT_FLAG_ACKCALL);
02044 } else {
02045 p->ackcall = ackcall;
02046 }
02047 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
02048 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
02049 if (p->autologoff < 0)
02050 p->autologoff = 0;
02051 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
02052 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
02053 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
02054 } else {
02055 p->autologoff = autologoff;
02056 }
02057 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
02058 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
02059 if (p->wrapuptime < 0)
02060 p->wrapuptime = 0;
02061 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
02062 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
02063 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
02064 } else {
02065 p->wrapuptime = wrapuptime;
02066 }
02067 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
02068 if (!ast_strlen_zero(tmpoptions)) {
02069 p->acceptdtmf = *tmpoptions;
02070 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
02071 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
02072 }
02073 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
02074 if (!ast_strlen_zero(tmpoptions)) {
02075 p->enddtmf = *tmpoptions;
02076 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
02077 ast_set_flag(p, AGENT_FLAG_ENDDTMF);
02078 }
02079 ast_channel_unlock(chan);
02080 unlock_channel = 0;
02081
02082 if (!p->chan) {
02083 long logintime;
02084 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
02085
02086 p->logincallerid[0] = '\0';
02087 p->acknowledged = 0;
02088
02089 ast_mutex_unlock(&p->lock);
02090 AST_LIST_UNLOCK(&agents);
02091 if( !res && play_announcement==1 )
02092 res = ast_streamfile(chan, filename, chan->language);
02093 if (!res)
02094 ast_waitstream(chan, "");
02095 AST_LIST_LOCK(&agents);
02096 ast_mutex_lock(&p->lock);
02097 if (!res) {
02098 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02099 if (res)
02100 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats)));
02101 }
02102 if (!res) {
02103 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02104 if (res)
02105 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats)));
02106 }
02107
02108 if (p->chan)
02109 res = -1;
02110 if (!res) {
02111 ast_indicate_data(chan, AST_CONTROL_HOLD,
02112 S_OR(p->moh, NULL),
02113 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02114 if (p->loginstart == 0)
02115 time(&p->loginstart);
02116 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02117 "Agent: %s\r\n"
02118 "Channel: %s\r\n"
02119 "Uniqueid: %s\r\n",
02120 p->agent, chan->name, chan->uniqueid);
02121 if (update_cdr && chan->cdr)
02122 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02123 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02124 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
02125 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02126
02127 p->chan = chan;
02128 if (p->ackcall) {
02129 check_beep(p, 0);
02130 } else {
02131 check_availability(p, 0);
02132 }
02133 ast_mutex_unlock(&p->lock);
02134 AST_LIST_UNLOCK(&agents);
02135 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
02136 while (res >= 0) {
02137 ast_mutex_lock(&p->lock);
02138 if (p->deferlogoff && p->chan) {
02139 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
02140 p->deferlogoff = 0;
02141 }
02142 if (p->chan != chan)
02143 res = -1;
02144 ast_mutex_unlock(&p->lock);
02145
02146 sched_yield();
02147 if (res)
02148 break;
02149
02150 AST_LIST_LOCK(&agents);
02151 ast_mutex_lock(&p->lock);
02152 if (p->lastdisc.tv_sec) {
02153 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02154 ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
02155 p->lastdisc = ast_tv(0, 0);
02156 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
02157 if (p->ackcall) {
02158 check_beep(p, 0);
02159 } else {
02160 check_availability(p, 0);
02161 }
02162 }
02163 }
02164 ast_mutex_unlock(&p->lock);
02165 AST_LIST_UNLOCK(&agents);
02166
02167
02168 ast_mutex_lock(&p->lock);
02169 if (p->app_lock_flag == 1) {
02170 ast_cond_signal(&p->login_wait_cond);
02171 ast_cond_wait(&p->app_complete_cond, &p->lock);
02172 }
02173 ast_mutex_unlock(&p->lock);
02174 if (p->ackcall) {
02175 res = agent_ack_sleep(p);
02176 } else {
02177 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02178 }
02179 if (p->ackcall && (res == 1)) {
02180 AST_LIST_LOCK(&agents);
02181 ast_mutex_lock(&p->lock);
02182 check_availability(p, 0);
02183 ast_mutex_unlock(&p->lock);
02184 AST_LIST_UNLOCK(&agents);
02185 res = 0;
02186 }
02187 sched_yield();
02188 }
02189 ast_mutex_lock(&p->lock);
02190
02191 if (p->chan == chan) {
02192 p->chan = NULL;
02193 }
02194
02195
02196 if (p->app_lock_flag == 1) {
02197 ast_cond_signal(&p->login_wait_cond);
02198 ast_cond_wait(&p->app_complete_cond, &p->lock);
02199 }
02200
02201 if (res && p->owner)
02202 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
02203
02204 p->acknowledged = 0;
02205 logintime = time(NULL) - p->loginstart;
02206 p->loginstart = 0;
02207 ast_mutex_unlock(&p->lock);
02208 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02209 "Agent: %s\r\n"
02210 "Logintime: %ld\r\n"
02211 "Uniqueid: %s\r\n",
02212 p->agent, logintime, chan->uniqueid);
02213 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02214 ast_verb(2, "Agent '%s' logged out\n", p->agent);
02215
02216 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
02217 if (p->dead && !p->owner) {
02218 ast_mutex_destroy(&p->lock);
02219 ast_cond_destroy(&p->app_complete_cond);
02220 ast_cond_destroy(&p->login_wait_cond);
02221 ast_free(p);
02222 }
02223 }
02224 else {
02225 ast_mutex_unlock(&p->lock);
02226 p = NULL;
02227 }
02228 res = -1;
02229 } else {
02230 ast_mutex_unlock(&p->lock);
02231 errmsg = "agent-alreadyon";
02232 p = NULL;
02233 }
02234 break;
02235 }
02236 ast_mutex_unlock(&p->lock);
02237 if (unlock_channel) {
02238 ast_channel_unlock(chan);
02239 }
02240 }
02241 if (!p)
02242 AST_LIST_UNLOCK(&agents);
02243
02244 if (!res && (max_login_tries==0 || tries < max_login_tries))
02245 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02246 }
02247
02248 if (!res)
02249 res = ast_safe_sleep(chan, 500);
02250
02251 ast_module_user_remove(u);
02252
02253 return -1;
02254 }
02255
02256
02257
02258
02259
02260
02261
02262
02263
02264 static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
02265 {
02266 int exitifnoagentid = 0;
02267 int nowarnings = 0;
02268 int changeoutgoing = 0;
02269 int res = 0;
02270 char agent[AST_MAX_AGENT];
02271
02272 if (data) {
02273 if (strchr(data, 'd'))
02274 exitifnoagentid = 1;
02275 if (strchr(data, 'n'))
02276 nowarnings = 1;
02277 if (strchr(data, 'c'))
02278 changeoutgoing = 1;
02279 }
02280 if (chan->caller.id.number.valid
02281 && !ast_strlen_zero(chan->caller.id.number.str)) {
02282 const char *tmp;
02283 char agentvar[AST_MAX_BUF];
02284 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
02285 chan->caller.id.number.str);
02286 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02287 struct agent_pvt *p;
02288 ast_copy_string(agent, tmp, sizeof(agent));
02289 AST_LIST_LOCK(&agents);
02290 AST_LIST_TRAVERSE(&agents, p, list) {
02291 if (!strcasecmp(p->agent, tmp)) {
02292 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02293 __agent_start_monitoring(chan, p, 1);
02294 break;
02295 }
02296 }
02297 AST_LIST_UNLOCK(&agents);
02298
02299 } else {
02300 res = -1;
02301 if (!nowarnings)
02302 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);
02303 }
02304 } else {
02305 res = -1;
02306 if (!nowarnings)
02307 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");
02308 }
02309 if (res) {
02310 if (exitifnoagentid)
02311 return res;
02312 }
02313 return 0;
02314 }
02315
02316
02317 static int agent_devicestate(void *data)
02318 {
02319 struct agent_pvt *p;
02320 char *s;
02321 ast_group_t groupmatch;
02322 int groupoff;
02323 int res = AST_DEVICE_INVALID;
02324
02325 s = data;
02326 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02327 groupmatch = (1 << groupoff);
02328 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02329 groupmatch = (1 << groupoff);
02330 } else
02331 groupmatch = 0;
02332
02333
02334 AST_LIST_LOCK(&agents);
02335 AST_LIST_TRAVERSE(&agents, p, list) {
02336 ast_mutex_lock(&p->lock);
02337 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02338 if (p->owner) {
02339 if (res != AST_DEVICE_INUSE)
02340 res = AST_DEVICE_BUSY;
02341 } else {
02342 if (res == AST_DEVICE_BUSY)
02343 res = AST_DEVICE_INUSE;
02344 if (p->chan) {
02345 if (res == AST_DEVICE_INVALID)
02346 res = AST_DEVICE_UNKNOWN;
02347 } else if (res == AST_DEVICE_INVALID)
02348 res = AST_DEVICE_UNAVAILABLE;
02349 }
02350 if (!strcmp(data, p->agent)) {
02351 ast_mutex_unlock(&p->lock);
02352 break;
02353 }
02354 }
02355 ast_mutex_unlock(&p->lock);
02356 }
02357 AST_LIST_UNLOCK(&agents);
02358 return res;
02359 }
02360
02361
02362
02363
02364 static struct agent_pvt *find_agent(char *agentid)
02365 {
02366 struct agent_pvt *cur;
02367
02368 AST_LIST_TRAVERSE(&agents, cur, list) {
02369 if (!strcmp(cur->agent, agentid))
02370 break;
02371 }
02372
02373 return cur;
02374 }
02375
02376 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
02377 {
02378 char *parse;
02379 AST_DECLARE_APP_ARGS(args,
02380 AST_APP_ARG(agentid);
02381 AST_APP_ARG(item);
02382 );
02383 char *tmp;
02384 struct agent_pvt *agent;
02385
02386 buf[0] = '\0';
02387
02388 if (ast_strlen_zero(data)) {
02389 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02390 return -1;
02391 }
02392
02393 parse = ast_strdupa(data);
02394
02395 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02396 if (!args.item)
02397 args.item = "status";
02398
02399 AST_LIST_LOCK(&agents);
02400
02401 if (!(agent = find_agent(args.agentid))) {
02402 AST_LIST_UNLOCK(&agents);
02403 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02404 return -1;
02405 }
02406
02407 if (!strcasecmp(args.item, "status")) {
02408 char *status = "LOGGEDOUT";
02409 if (agent->chan) {
02410 status = "LOGGEDIN";
02411 }
02412 ast_copy_string(buf, status, len);
02413 } else if (!strcasecmp(args.item, "password"))
02414 ast_copy_string(buf, agent->password, len);
02415 else if (!strcasecmp(args.item, "name"))
02416 ast_copy_string(buf, agent->name, len);
02417 else if (!strcasecmp(args.item, "mohclass"))
02418 ast_copy_string(buf, agent->moh, len);
02419 else if (!strcasecmp(args.item, "channel")) {
02420 if (agent->chan) {
02421 ast_channel_lock(agent->chan);
02422 ast_copy_string(buf, agent->chan->name, len);
02423 ast_channel_unlock(agent->chan);
02424 tmp = strrchr(buf, '-');
02425 if (tmp)
02426 *tmp = '\0';
02427 }
02428 } else if (!strcasecmp(args.item, "fullchannel")) {
02429 if (agent->chan) {
02430 ast_channel_lock(agent->chan);
02431 ast_copy_string(buf, agent->chan->name, len);
02432 ast_channel_unlock(agent->chan);
02433 }
02434 } else if (!strcasecmp(args.item, "exten")) {
02435 buf[0] = '\0';
02436 }
02437
02438 AST_LIST_UNLOCK(&agents);
02439
02440 return 0;
02441 }
02442
02443 static struct ast_custom_function agent_function = {
02444 .name = "AGENT",
02445 .read = function_agent,
02446 };
02447
02448
02449
02450
02451
02452
02453
02454
02455 static int agents_data_provider_get(const struct ast_data_search *search,
02456 struct ast_data *data_root)
02457 {
02458 struct agent_pvt *p;
02459 struct ast_data *data_agent, *data_channel, *data_talkingto;
02460
02461 AST_LIST_LOCK(&agents);
02462 AST_LIST_TRAVERSE(&agents, p, list) {
02463 struct ast_channel *owner;
02464
02465 data_agent = ast_data_add_node(data_root, "agent");
02466 if (!data_agent) {
02467 continue;
02468 }
02469
02470 ast_mutex_lock(&p->lock);
02471 owner = agent_lock_owner(p);
02472
02473 if (!(p->pending)) {
02474 ast_data_add_str(data_agent, "id", p->agent);
02475 ast_data_add_structure(agent_pvt, data_agent, p);
02476
02477 ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
02478 if (p->chan) {
02479 data_channel = ast_data_add_node(data_agent, "loggedon");
02480 if (!data_channel) {
02481 ast_mutex_unlock(&p->lock);
02482 ast_data_remove_node(data_root, data_agent);
02483 if (owner) {
02484 ast_channel_unlock(owner);
02485 owner = ast_channel_unref(owner);
02486 }
02487 continue;
02488 }
02489 ast_channel_data_add_structure(data_channel, p->chan, 0);
02490 if (owner && ast_bridged_channel(owner)) {
02491 data_talkingto = ast_data_add_node(data_agent, "talkingto");
02492 if (!data_talkingto) {
02493 ast_mutex_unlock(&p->lock);
02494 ast_data_remove_node(data_root, data_agent);
02495 if (owner) {
02496 ast_channel_unlock(owner);
02497 owner = ast_channel_unref(owner);
02498 }
02499 continue;
02500 }
02501 ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
02502 }
02503 } else {
02504 ast_data_add_node(data_agent, "talkingto");
02505 ast_data_add_node(data_agent, "loggedon");
02506 }
02507 ast_data_add_str(data_agent, "musiconhold", p->moh);
02508 }
02509
02510 if (owner) {
02511 ast_channel_unlock(owner);
02512 owner = ast_channel_unref(owner);
02513 }
02514
02515 ast_mutex_unlock(&p->lock);
02516
02517
02518 if (!ast_data_search_match(search, data_agent)) {
02519 ast_data_remove_node(data_root, data_agent);
02520 }
02521 }
02522 AST_LIST_UNLOCK(&agents);
02523
02524 return 0;
02525 }
02526
02527 static const struct ast_data_handler agents_data_provider = {
02528 .version = AST_DATA_HANDLER_VERSION,
02529 .get = agents_data_provider_get
02530 };
02531
02532 static const struct ast_data_entry agents_data_providers[] = {
02533 AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
02534 };
02535
02536
02537
02538
02539
02540
02541
02542
02543 static int load_module(void)
02544 {
02545
02546 if (ast_channel_register(&agent_tech)) {
02547 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02548 return AST_MODULE_LOAD_FAILURE;
02549 }
02550
02551 if (!read_agent_config(0))
02552 return AST_MODULE_LOAD_DECLINE;
02553
02554 ast_register_application_xml(app, login_exec);
02555 ast_register_application_xml(app3, agentmonitoroutgoing_exec);
02556
02557
02558 ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
02559
02560
02561 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
02562 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
02563
02564
02565 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
02566
02567
02568 ast_custom_function_register(&agent_function);
02569
02570 return AST_MODULE_LOAD_SUCCESS;
02571 }
02572
02573 static int reload(void)
02574 {
02575 return read_agent_config(1);
02576 }
02577
02578 static int unload_module(void)
02579 {
02580 struct agent_pvt *p;
02581
02582 ast_channel_unregister(&agent_tech);
02583
02584 ast_custom_function_unregister(&agent_function);
02585
02586 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
02587
02588 ast_unregister_application(app);
02589 ast_unregister_application(app3);
02590
02591 ast_manager_unregister("Agents");
02592 ast_manager_unregister("AgentLogoff");
02593
02594 ast_data_unregister(NULL);
02595
02596 AST_LIST_LOCK(&agents);
02597
02598 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02599 if (p->owner)
02600 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02601 ast_free(p);
02602 }
02603 AST_LIST_UNLOCK(&agents);
02604 return 0;
02605 }
02606
02607 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
02608 .load = load_module,
02609 .unload = unload_module,
02610 .reload = reload,
02611 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
02612 .nonoptreq = "res_monitor,chan_local",
02613 );