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