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