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