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