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