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