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