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