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