00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 141366 $")
00040
00041 #include <stdio.h>
00042 #include <string.h>
00043 #include <errno.h>
00044 #include <unistd.h>
00045 #include <sys/socket.h>
00046 #include <stdlib.h>
00047 #include <fcntl.h>
00048 #include <netdb.h>
00049 #include <netinet/in.h>
00050 #include <arpa/inet.h>
00051 #include <sys/signal.h>
00052
00053 #include "asterisk/lock.h"
00054 #include "asterisk/channel.h"
00055 #include "asterisk/config.h"
00056 #include "asterisk/logger.h"
00057 #include "asterisk/module.h"
00058 #include "asterisk/pbx.h"
00059 #include "asterisk/options.h"
00060 #include "asterisk/lock.h"
00061 #include "asterisk/sched.h"
00062 #include "asterisk/io.h"
00063 #include "asterisk/rtp.h"
00064 #include "asterisk/acl.h"
00065 #include "asterisk/callerid.h"
00066 #include "asterisk/file.h"
00067 #include "asterisk/cli.h"
00068 #include "asterisk/app.h"
00069 #include "asterisk/musiconhold.h"
00070 #include "asterisk/manager.h"
00071 #include "asterisk/features.h"
00072 #include "asterisk/utils.h"
00073 #include "asterisk/causes.h"
00074 #include "asterisk/astdb.h"
00075 #include "asterisk/devicestate.h"
00076 #include "asterisk/monitor.h"
00077 #include "asterisk/stringfields.h"
00078
00079 static const char tdesc[] = "Call Agent Proxy Channel";
00080 static const char config[] = "agents.conf";
00081
00082 static const char app[] = "AgentLogin";
00083 static const char app2[] = "AgentCallbackLogin";
00084 static const char app3[] = "AgentMonitorOutgoing";
00085
00086 static const char synopsis[] = "Call agent login";
00087 static const char synopsis2[] = "Call agent callback login";
00088 static const char synopsis3[] = "Record agent's outgoing call";
00089
00090 static const char descrip[] =
00091 " AgentLogin([AgentNo][|options]):\n"
00092 "Asks the agent to login to the system. Always returns -1. While\n"
00093 "logged in, the agent can receive calls and will hear a 'beep'\n"
00094 "when a new call comes in. The agent can dump the call by pressing\n"
00095 "the star key.\n"
00096 "The option string may contain zero or more of the following characters:\n"
00097 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
00098
00099 static const char descrip2[] =
00100 " AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]):\n"
00101 "Asks the agent to login to the system with callback.\n"
00102 "The agent's callback extension is called (optionally with the specified\n"
00103 "context).\n"
00104 "The option string may contain zero or more of the following characters:\n"
00105 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
00106
00107 static const char descrip3[] =
00108 " AgentMonitorOutgoing([options]):\n"
00109 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
00110 "comparison of the callerid of the current interface and the global variable \n"
00111 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
00112 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
00113 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
00114 "\nReturn value:\n"
00115 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
00116 "the agentid are not specified it'll look for n+101 priority.\n"
00117 "\nOptions:\n"
00118 " 'd' - make the app return -1 if there is an error condition and there is\n"
00119 " no extension n+101\n"
00120 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
00121 " 'n' - don't generate the warnings when there is no callerid or the\n"
00122 " agentid is not known.\n"
00123 " It's handy if you want to have one context for agent and non-agent calls.\n";
00124
00125 static const char mandescr_agents[] =
00126 "Description: Will list info about all possible agents.\n"
00127 "Variables: NONE\n";
00128
00129 static const char mandescr_agent_logoff[] =
00130 "Description: Sets an agent as no longer logged in.\n"
00131 "Variables: (Names marked with * are required)\n"
00132 " *Agent: Agent ID of the agent to log off\n"
00133 " Soft: Set to 'true' to not hangup existing calls\n";
00134
00135 static const char mandescr_agent_callback_login[] =
00136 "Description: Sets an agent as logged in with callback.\n"
00137 "Variables: (Names marked with * are required)\n"
00138 " *Agent: Agent ID of the agent to login\n"
00139 " *Exten: Extension to use for callback\n"
00140 " Context: Context to use for callback\n"
00141 " AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
00142 " WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
00143
00144 static char moh[80] = "default";
00145
00146 #define AST_MAX_AGENT 80
00147 #define AST_MAX_BUF 256
00148 #define AST_MAX_FILENAME_LEN 256
00149
00150 static const char pa_family[] = "Agents";
00151 #define PA_MAX_LEN 2048
00152
00153 static int persistent_agents = 0;
00154 static void dump_agents(void);
00155
00156 static ast_group_t group;
00157 static int autologoff;
00158 static int wrapuptime;
00159 static int ackcall;
00160 static int endcall;
00161 static int multiplelogin = 1;
00162 static int autologoffunavail = 0;
00163
00164 static int maxlogintries = 3;
00165 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
00166
00167 static int recordagentcalls = 0;
00168 static char recordformat[AST_MAX_BUF] = "";
00169 static char recordformatext[AST_MAX_BUF] = "";
00170 static char urlprefix[AST_MAX_BUF] = "";
00171 static char savecallsin[AST_MAX_BUF] = "";
00172 static int updatecdr = 0;
00173 static char beep[AST_MAX_BUF] = "beep";
00174
00175 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
00176
00177
00178 struct agent_pvt {
00179 ast_mutex_t lock;
00180 int dead;
00181 int pending;
00182 int abouttograb;
00183 int autologoff;
00184 int ackcall;
00185 int deferlogoff;
00186 time_t loginstart;
00187 time_t start;
00188 struct timeval lastdisc;
00189 int wrapuptime;
00190 ast_group_t group;
00191 int acknowledged;
00192 char moh[80];
00193 char agent[AST_MAX_AGENT];
00194 char password[AST_MAX_AGENT];
00195 char name[AST_MAX_AGENT];
00196 int inherited_devicestate;
00197 ast_mutex_t app_lock;
00198 volatile pthread_t owning_app;
00199 volatile int app_sleep_cond;
00200 struct ast_channel *owner;
00201 char loginchan[80];
00202 char logincallerid[80];
00203 struct ast_channel *chan;
00204 AST_LIST_ENTRY(agent_pvt) list;
00205 };
00206
00207 static AST_LIST_HEAD_STATIC(agents, agent_pvt);
00208
00209 #define CHECK_FORMATS(ast, p) do { \
00210 if (p->chan) {\
00211 if (ast->nativeformats != p->chan->nativeformats) { \
00212 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
00213 \
00214 ast->nativeformats = p->chan->nativeformats; \
00215 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
00216 ast_set_read_format(ast, ast->readformat); \
00217 ast_set_write_format(ast, ast->writeformat); \
00218 } \
00219 if (p->chan->readformat != ast->rawreadformat && !p->chan->generator) \
00220 ast_set_read_format(p->chan, ast->rawreadformat); \
00221 if (p->chan->writeformat != ast->rawwriteformat && !p->chan->generator) \
00222 ast_set_write_format(p->chan, ast->rawwriteformat); \
00223 } \
00224 } while(0)
00225
00226
00227
00228
00229
00230 #define CLEANUP(ast, p) do { \
00231 int x; \
00232 if (p->chan) { \
00233 for (x=0;x<AST_MAX_FDS;x++) {\
00234 if (x != AST_TIMING_FD) \
00235 ast->fds[x] = p->chan->fds[x]; \
00236 } \
00237 ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
00238 } \
00239 } while(0)
00240
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 void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
00245 static int agent_digit_begin(struct ast_channel *ast, char digit);
00246 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
00247 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
00248 static int agent_hangup(struct ast_channel *ast);
00249 static int agent_answer(struct ast_channel *ast);
00250 static struct ast_frame *agent_read(struct ast_channel *ast);
00251 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
00252 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
00253 static int agent_sendtext(struct ast_channel *ast, const char *text);
00254 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
00255 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
00256 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00257 static void set_agentbycallerid(const char *callerid, const char *agent);
00258 static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
00259 static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
00260
00261
00262 static const struct ast_channel_tech agent_tech = {
00263 .type = "Agent",
00264 .description = tdesc,
00265 .capabilities = -1,
00266 .requester = agent_request,
00267 .devicestate = agent_devicestate,
00268 .send_digit_begin = agent_digit_begin,
00269 .send_digit_end = agent_digit_end,
00270 .call = agent_call,
00271 .hangup = agent_hangup,
00272 .answer = agent_answer,
00273 .read = agent_read,
00274 .write = agent_write,
00275 .write_video = agent_write,
00276 .send_html = agent_sendhtml,
00277 .send_text = agent_sendtext,
00278 .exception = agent_read,
00279 .indicate = agent_indicate,
00280 .fixup = agent_fixup,
00281 .bridged_channel = agent_bridgedchannel,
00282 .get_base_channel = agent_get_base_channel,
00283 .set_base_channel = agent_set_base_channel,
00284 };
00285
00286 static int agent_devicestate_cb(const char *dev, int state, void *data)
00287 {
00288 int res, i;
00289 struct agent_pvt *p;
00290 char basename[AST_CHANNEL_NAME], *tmp;
00291
00292
00293 if (!strncasecmp(dev, "Agent/", 6)) {
00294 return 0;
00295 }
00296
00297
00298 for (i = 0; i < 10; i++) {
00299 if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
00300 break;
00301 }
00302 }
00303 if (res) {
00304 return -1;
00305 }
00306
00307 AST_LIST_TRAVERSE(&agents, p, list) {
00308 ast_mutex_lock(&p->lock);
00309 if (p->chan) {
00310 ast_copy_string(basename, p->chan->name, sizeof(basename));
00311 if ((tmp = strrchr(basename, '-'))) {
00312 *tmp = '\0';
00313 }
00314 if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) {
00315 p->inherited_devicestate = state;
00316 ast_device_state_changed("Agent/%s", p->agent);
00317 }
00318 }
00319 ast_mutex_unlock(&p->lock);
00320 }
00321 AST_LIST_UNLOCK(&agents);
00322 return 0;
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 static struct agent_pvt *add_agent(char *agent, int pending)
00334 {
00335 char *parse;
00336 AST_DECLARE_APP_ARGS(args,
00337 AST_APP_ARG(agt);
00338 AST_APP_ARG(password);
00339 AST_APP_ARG(name);
00340 );
00341 char *password = NULL;
00342 char *name = NULL;
00343 char *agt = NULL;
00344 struct agent_pvt *p;
00345
00346 parse = ast_strdupa(agent);
00347
00348
00349 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
00350
00351 if(args.argc == 0) {
00352 ast_log(LOG_WARNING, "A blank agent line!\n");
00353 return NULL;
00354 }
00355
00356 if(ast_strlen_zero(args.agt) ) {
00357 ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00358 return NULL;
00359 } else
00360 agt = args.agt;
00361
00362 if(!ast_strlen_zero(args.password)) {
00363 password = args.password;
00364 while (*password && *password < 33) password++;
00365 }
00366 if(!ast_strlen_zero(args.name)) {
00367 name = args.name;
00368 while (*name && *name < 33) name++;
00369 }
00370
00371
00372 AST_LIST_TRAVERSE(&agents, p, list) {
00373 if (!pending && !strcmp(p->agent, agt))
00374 break;
00375 }
00376 if (!p) {
00377
00378 if (!(p = ast_calloc(1, sizeof(*p))))
00379 return NULL;
00380 ast_copy_string(p->agent, agt, sizeof(p->agent));
00381 ast_mutex_init(&p->lock);
00382 ast_mutex_init(&p->app_lock);
00383 p->owning_app = (pthread_t) -1;
00384 p->app_sleep_cond = 1;
00385 p->group = group;
00386 p->pending = pending;
00387 p->inherited_devicestate = -1;
00388 AST_LIST_INSERT_TAIL(&agents, p, list);
00389 }
00390
00391 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00392 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00393 ast_copy_string(p->moh, moh, sizeof(p->moh));
00394 p->ackcall = ackcall;
00395 p->autologoff = autologoff;
00396
00397
00398
00399 if (p->wrapuptime > wrapuptime) {
00400 struct timeval now = ast_tvnow();
00401
00402
00403
00404 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00405 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00406 p->lastdisc.tv_usec = now.tv_usec;
00407 }
00408 }
00409 p->wrapuptime = wrapuptime;
00410
00411 if (pending)
00412 p->dead = 1;
00413 else
00414 p->dead = 0;
00415 return p;
00416 }
00417
00418
00419
00420
00421
00422
00423
00424 static int agent_cleanup(struct agent_pvt *p)
00425 {
00426 struct ast_channel *chan = p->owner;
00427 p->owner = NULL;
00428 chan->tech_pvt = NULL;
00429 p->app_sleep_cond = 1;
00430
00431 ast_mutex_unlock(&p->app_lock);
00432 if (chan)
00433 ast_channel_free(chan);
00434 if (p->dead) {
00435 ast_mutex_destroy(&p->lock);
00436 ast_mutex_destroy(&p->app_lock);
00437 free(p);
00438 }
00439 return 0;
00440 }
00441
00442 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
00443
00444 static int agent_answer(struct ast_channel *ast)
00445 {
00446 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
00447 return -1;
00448 }
00449
00450 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
00451 {
00452 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00453 char filename[AST_MAX_BUF];
00454 int res = -1;
00455 if (!p)
00456 return -1;
00457 if (!ast->monitor) {
00458 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00459
00460 if ((pointer = strchr(filename, '.')))
00461 *pointer = '-';
00462 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00463 ast_monitor_start(ast, recordformat, tmp, needlock);
00464 ast_monitor_setjoinfiles(ast, 1);
00465 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00466 #if 0
00467 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00468 #endif
00469 if (!ast->cdr)
00470 ast->cdr = ast_cdr_alloc();
00471 ast_cdr_setuserfield(ast, tmp2);
00472 res = 0;
00473 } else
00474 ast_log(LOG_ERROR, "Recording already started on that call.\n");
00475 return res;
00476 }
00477
00478 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
00479 {
00480 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00481 }
00482
00483 static struct ast_frame *agent_read(struct ast_channel *ast)
00484 {
00485 struct agent_pvt *p = ast->tech_pvt;
00486 struct ast_frame *f = NULL;
00487 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00488 const char *status;
00489 ast_mutex_lock(&p->lock);
00490 CHECK_FORMATS(ast, p);
00491 if (p->chan) {
00492 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00493 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00494 f = ast_read(p->chan);
00495 } else
00496 f = &ast_null_frame;
00497 if (!f) {
00498
00499 if (p->chan) {
00500 p->chan->_bridge = NULL;
00501
00502
00503 if (!ast_strlen_zero(p->loginchan)) {
00504 if (p->chan)
00505 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00506 if (p->owner->_state != AST_STATE_UP) {
00507 int howlong = time(NULL) - p->start;
00508 if (p->autologoff && howlong > p->autologoff) {
00509 long logintime = time(NULL) - p->loginstart;
00510 p->loginstart = 0;
00511 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00512 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00513 if (persistent_agents)
00514 dump_agents();
00515 }
00516 }
00517 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00518 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00519 long logintime = time(NULL) - p->loginstart;
00520 p->loginstart = 0;
00521 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
00522 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00523 }
00524 ast_hangup(p->chan);
00525 if (p->wrapuptime && p->acknowledged)
00526 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00527 }
00528 p->chan = NULL;
00529 p->inherited_devicestate = -1;
00530 ast_device_state_changed("Agent/%s", p->agent);
00531 p->acknowledged = 0;
00532 }
00533 } else {
00534
00535
00536 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
00537 p->acknowledged = 1;
00538 switch (f->frametype) {
00539 case AST_FRAME_CONTROL:
00540 if (f->subclass == AST_CONTROL_ANSWER) {
00541 if (p->ackcall) {
00542 if (option_verbose > 2)
00543 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
00544
00545 ast_frfree(f);
00546 f = &ast_null_frame;
00547 } else {
00548 p->acknowledged = 1;
00549
00550
00551 ast_frfree(f);
00552 f = &answer_frame;
00553 }
00554 }
00555 break;
00556 case AST_FRAME_DTMF_BEGIN:
00557
00558 if((!p->acknowledged && f->subclass == '#') || (f->subclass == '*' && endcall)){
00559 ast_frfree(f);
00560 f = &ast_null_frame;
00561 }
00562 break;
00563 case AST_FRAME_DTMF_END:
00564 if (!p->acknowledged && (f->subclass == '#')) {
00565 if (option_verbose > 2)
00566 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
00567 p->acknowledged = 1;
00568 ast_frfree(f);
00569 f = &answer_frame;
00570 } else if (f->subclass == '*' && endcall) {
00571
00572 ast_frfree(f);
00573 f = NULL;
00574 }
00575 break;
00576 case AST_FRAME_VOICE:
00577 case AST_FRAME_VIDEO:
00578
00579 if (!p->acknowledged) {
00580 ast_frfree(f);
00581 f = &ast_null_frame;
00582 }
00583 default:
00584
00585 break;
00586 }
00587 }
00588
00589 CLEANUP(ast,p);
00590 if (p->chan && !p->chan->_bridge) {
00591 if (strcasecmp(p->chan->tech->type, "Local")) {
00592 p->chan->_bridge = ast;
00593 if (p->chan)
00594 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00595 }
00596 }
00597 ast_mutex_unlock(&p->lock);
00598 if (recordagentcalls && f == &answer_frame)
00599 agent_start_monitoring(ast,0);
00600 return f;
00601 }
00602
00603 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
00604 {
00605 struct agent_pvt *p = ast->tech_pvt;
00606 int res = -1;
00607 ast_mutex_lock(&p->lock);
00608 if (p->chan)
00609 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00610 ast_mutex_unlock(&p->lock);
00611 return res;
00612 }
00613
00614 static int agent_sendtext(struct ast_channel *ast, const char *text)
00615 {
00616 struct agent_pvt *p = ast->tech_pvt;
00617 int res = -1;
00618 ast_mutex_lock(&p->lock);
00619 if (p->chan)
00620 res = ast_sendtext(p->chan, text);
00621 ast_mutex_unlock(&p->lock);
00622 return res;
00623 }
00624
00625 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
00626 {
00627 struct agent_pvt *p = ast->tech_pvt;
00628 int res = -1;
00629 CHECK_FORMATS(ast, p);
00630 ast_mutex_lock(&p->lock);
00631 if (!p->chan)
00632 res = 0;
00633 else {
00634 if ((f->frametype != AST_FRAME_VOICE) ||
00635 (f->frametype != AST_FRAME_VIDEO) ||
00636 (f->subclass == p->chan->writeformat)) {
00637 res = ast_write(p->chan, f);
00638 } else {
00639 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n",
00640 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00641 ast->name, p->chan->name);
00642 res = 0;
00643 }
00644 }
00645 CLEANUP(ast, p);
00646 ast_mutex_unlock(&p->lock);
00647 return res;
00648 }
00649
00650 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
00651 {
00652 struct agent_pvt *p = newchan->tech_pvt;
00653 ast_mutex_lock(&p->lock);
00654 if (p->owner != oldchan) {
00655 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00656 ast_mutex_unlock(&p->lock);
00657 return -1;
00658 }
00659 p->owner = newchan;
00660 ast_mutex_unlock(&p->lock);
00661 return 0;
00662 }
00663
00664 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
00665 {
00666 struct agent_pvt *p = ast->tech_pvt;
00667 int res = -1;
00668 ast_mutex_lock(&p->lock);
00669 if (p->chan && !ast_check_hangup(p->chan))
00670 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00671 else
00672 res = 0;
00673 ast_mutex_unlock(&p->lock);
00674 return res;
00675 }
00676
00677 static int agent_digit_begin(struct ast_channel *ast, char digit)
00678 {
00679 struct agent_pvt *p = ast->tech_pvt;
00680 ast_mutex_lock(&p->lock);
00681 if (p->chan) {
00682 ast_senddigit_begin(p->chan, digit);
00683 }
00684 ast_mutex_unlock(&p->lock);
00685 return 0;
00686 }
00687
00688 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
00689 {
00690 struct agent_pvt *p = ast->tech_pvt;
00691 ast_mutex_lock(&p->lock);
00692 if (p->chan) {
00693 ast_senddigit_end(p->chan, digit, duration);
00694 }
00695 ast_mutex_unlock(&p->lock);
00696 return 0;
00697 }
00698
00699 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
00700 {
00701 struct agent_pvt *p = ast->tech_pvt;
00702 int res = -1;
00703 int newstate=0;
00704 ast_mutex_lock(&p->lock);
00705 p->acknowledged = 0;
00706 if (!p->chan) {
00707 if (p->pending) {
00708 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00709 newstate = AST_STATE_DIALING;
00710 res = 0;
00711 } else {
00712 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
00713 res = -1;
00714 }
00715 ast_mutex_unlock(&p->lock);
00716 if (newstate)
00717 ast_setstate(ast, newstate);
00718 return res;
00719 } else if (!ast_strlen_zero(p->loginchan)) {
00720 time(&p->start);
00721
00722 if (option_verbose > 2)
00723 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00724 ast_set_callerid(p->chan,
00725 ast->cid.cid_num, ast->cid.cid_name, NULL);
00726 ast_channel_inherit_variables(ast, p->chan);
00727 res = ast_call(p->chan, p->loginchan, 0);
00728 CLEANUP(ast,p);
00729 ast_mutex_unlock(&p->lock);
00730 return res;
00731 }
00732 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00733 if (option_debug > 2)
00734 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
00735 res = ast_streamfile(p->chan, beep, p->chan->language);
00736 if (option_debug > 2)
00737 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
00738 if (!res) {
00739 res = ast_waitstream(p->chan, "");
00740 if (option_debug > 2)
00741 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
00742 }
00743 if (!res) {
00744 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00745 if (option_debug > 2)
00746 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
00747 if (res)
00748 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00749 } else {
00750
00751 p->chan = NULL;
00752 p->inherited_devicestate = -1;
00753 ast_device_state_changed("Agent/%s", p->agent);
00754 }
00755
00756 if (!res) {
00757 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00758 if (option_debug > 2)
00759 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
00760 if (res)
00761 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00762 }
00763 if(!res) {
00764
00765 if (p->ackcall > 1)
00766 newstate = AST_STATE_RINGING;
00767 else {
00768 newstate = AST_STATE_UP;
00769 if (recordagentcalls)
00770 agent_start_monitoring(ast, 0);
00771 p->acknowledged = 1;
00772 }
00773 res = 0;
00774 }
00775 CLEANUP(ast, p);
00776 ast_mutex_unlock(&p->lock);
00777 if (newstate)
00778 ast_setstate(ast, newstate);
00779 return res;
00780 }
00781
00782
00783 static void set_agentbycallerid(const char *callerid, const char *agent)
00784 {
00785 char buf[AST_MAX_BUF];
00786
00787
00788 if (ast_strlen_zero(callerid))
00789 return;
00790
00791 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00792 pbx_builtin_setvar_helper(NULL, buf, agent);