![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
chan_agent.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2006, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 00020 /*! \file 00021 * 00022 * \brief Implementation of Agents (proxy channel) 00023 * 00024 * \author Mark Spencer <markster@digium.com> 00025 * 00026 * This file is the implementation of Agents modules. 00027 * It is a dynamic module that is loaded by Asterisk. 00028 * \par See also 00029 * \arg \ref Config_agent 00030 * 00031 * \ingroup channel_drivers 00032 */ 00033 00034 #include "asterisk.h" 00035 00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51385 $") 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 app3[] = "AgentMonitorOutgoing"; 00081 00082 static const char synopsis[] = "Call agent login"; 00083 static const char synopsis3[] = "Record agent's outgoing call"; 00084 00085 static const char descrip[] = 00086 " AgentLogin([AgentNo][|options]):\n" 00087 "Asks the agent to login to the system. Always returns -1. While\n" 00088 "logged in, the agent can receive calls and will hear a 'beep'\n" 00089 "when a new call comes in. The agent can dump the call by pressing\n" 00090 "the star key.\n" 00091 "The option string may contain zero or more of the following characters:\n" 00092 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n"; 00093 00094 static const char descrip3[] = 00095 " AgentMonitorOutgoing([options]):\n" 00096 "Tries to figure out the id of the agent who is placing outgoing call based on\n" 00097 "comparison of the callerid of the current interface and the global variable \n" 00098 "placed by the AgentCallbackLogin application. That's why it should be used only\n" 00099 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n" 00100 "instead of Monitor application. That have to be configured in the agents.conf file.\n" 00101 "\nReturn value:\n" 00102 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n" 00103 "the agentid are not specified it'll look for n+101 priority.\n" 00104 "\nOptions:\n" 00105 " 'd' - make the app return -1 if there is an error condition and there is\n" 00106 " no extension n+101\n" 00107 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n" 00108 " 'n' - don't generate the warnings when there is no callerid or the\n" 00109 " agentid is not known.\n" 00110 " It's handy if you want to have one context for agent and non-agent calls.\n"; 00111 00112 static const char mandescr_agents[] = 00113 "Description: Will list info about all possible agents.\n" 00114 "Variables: NONE\n"; 00115 00116 static const char mandescr_agent_logoff[] = 00117 "Description: Sets an agent as no longer logged in.\n" 00118 "Variables: (Names marked with * are required)\n" 00119 " *Agent: Agent ID of the agent to log off\n" 00120 " Soft: Set to 'true' to not hangup existing calls\n"; 00121 00122 static const char mandescr_agent_callback_login[] = 00123 "Description: Sets an agent as logged in with callback.\n" 00124 "Variables: (Names marked with * are required)\n" 00125 " *Agent: Agent ID of the agent to login\n" 00126 " *Exten: Extension to use for callback\n" 00127 " Context: Context to use for callback\n" 00128 " AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n" 00129 " WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n"; 00130 00131 static char moh[80] = "default"; 00132 00133 #define AST_MAX_AGENT 80 /*!< Agent ID or Password max length */ 00134 #define AST_MAX_BUF 256 00135 #define AST_MAX_FILENAME_LEN 256 00136 00137 static const char pa_family[] = "/Agents"; /*!< Persistent Agents astdb family */ 00138 #define PA_MAX_LEN 2048 /*!< The maximum length of each persistent member agent database entry */ 00139 00140 static int persistent_agents = 0; /*!< queues.conf [general] option */ 00141 static void dump_agents(void); 00142 00143 static ast_group_t group; 00144 static int autologoff; 00145 static int wrapuptime; 00146 static int ackcall; 00147 static int endcall; 00148 static int multiplelogin = 1; 00149 static int autologoffunavail = 0; 00150 00151 static int maxlogintries = 3; 00152 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye"; 00153 00154 static int recordagentcalls = 0; 00155 static char recordformat[AST_MAX_BUF] = ""; 00156 static char recordformatext[AST_MAX_BUF] = ""; 00157 static char urlprefix[AST_MAX_BUF] = ""; 00158 static char savecallsin[AST_MAX_BUF] = ""; 00159 static int updatecdr = 0; 00160 static char beep[AST_MAX_BUF] = "beep"; 00161 00162 #define GETAGENTBYCALLERID "AGENTBYCALLERID" 00163 00164 /*! \brief Structure representing an agent. */ 00165 struct agent_pvt { 00166 ast_mutex_t lock; /*!< Channel private lock */ 00167 int dead; /*!< Poised for destruction? */ 00168 int pending; /*!< Not a real agent -- just pending a match */ 00169 int abouttograb; /*!< About to grab */ 00170 int autologoff; /*!< Auto timeout time */ 00171 int ackcall; /*!< ackcall */ 00172 time_t loginstart; /*!< When agent first logged in (0 when logged off) */ 00173 time_t start; /*!< When call started */ 00174 struct timeval lastdisc; /*!< When last disconnected */ 00175 int wrapuptime; /*!< Wrapup time in ms */ 00176 ast_group_t group; /*!< Group memberships */ 00177 int acknowledged; /*!< Acknowledged */ 00178 char moh[80]; /*!< Which music on hold */ 00179 char agent[AST_MAX_AGENT]; /*!< Agent ID */ 00180 char password[AST_MAX_AGENT]; /*!< Password for Agent login */ 00181 char name[AST_MAX_AGENT]; 00182 ast_mutex_t app_lock; /**< Synchronization between owning applications */ 00183 volatile pthread_t owning_app; /**< Owning application thread id */ 00184 volatile int app_sleep_cond; /**< Sleep condition for the login app */ 00185 struct ast_channel *owner; /**< Agent */ 00186 char loginchan[80]; /**< channel they logged in from */ 00187 char logincallerid[80]; /**< Caller ID they had when they logged in */ 00188 struct ast_channel *chan; /**< Channel we use */ 00189 AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */ 00190 }; 00191 00192 static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (loaded form agents.conf). */ 00193 00194 #define CHECK_FORMATS(ast, p) do { \ 00195 if (p->chan) {\ 00196 if (ast->nativeformats != p->chan->nativeformats) { \ 00197 if (option_debug) \ 00198 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \ 00199 /* Native formats changed, reset things */ \ 00200 ast->nativeformats = p->chan->nativeformats; \ 00201 if (option_debug) \ 00202 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\ 00203 ast_set_read_format(ast, ast->readformat); \ 00204 ast_set_write_format(ast, ast->writeformat); \ 00205 } \ 00206 if (p->chan->readformat != ast->rawreadformat) \ 00207 ast_set_read_format(p->chan, ast->rawreadformat); \ 00208 if (p->chan->writeformat != ast->rawwriteformat) \ 00209 ast_set_write_format(p->chan, ast->rawwriteformat); \ 00210 } \ 00211 } while(0) 00212 00213 /*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things 00214 properly for a timingfd XXX This might need more work if agents were logged in as agents or other 00215 totally impractical combinations XXX */ 00216 00217 #define CLEANUP(ast, p) do { \ 00218 int x; \ 00219 if (p->chan) { \ 00220 for (x=0;x<AST_MAX_FDS;x++) {\ 00221 if (x != AST_TIMING_FD) \ 00222 ast->fds[x] = p->chan->fds[x]; \ 00223 } \ 00224 ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \ 00225 } \ 00226 } while(0) 00227 00228 /*--- Forward declarations */ 00229 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause); 00230 static int agent_devicestate(void *data); 00231 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand); 00232 static int agent_digit_begin(struct ast_channel *ast, char digit); 00233 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration); 00234 static int agent_call(struct ast_channel *ast, char *dest, int timeout); 00235 static int agent_hangup(struct ast_channel *ast); 00236 static int agent_answer(struct ast_channel *ast); 00237 static struct ast_frame *agent_read(struct ast_channel *ast); 00238 static int agent_write(struct ast_channel *ast, struct ast_frame *f); 00239 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); 00240 static int agent_sendtext(struct ast_channel *ast, const char *text); 00241 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen); 00242 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); 00243 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge); 00244 static void set_agentbycallerid(const char *callerid, const char *agent); 00245 00246 /*! \brief Channel interface description for PBX integration */ 00247 static const struct ast_channel_tech agent_tech = { 00248 .type = "Agent", 00249 .description = tdesc, 00250 .capabilities = -1, 00251 .requester = agent_request, 00252 .devicestate = agent_devicestate, 00253 .send_digit_begin = agent_digit_begin, 00254 .send_digit_end = agent_digit_end, 00255 .call = agent_call, 00256 .hangup = agent_hangup, 00257 .answer = agent_answer, 00258 .read = agent_read, 00259 .write = agent_write, 00260 .write_video = agent_write, 00261 .send_html = agent_sendhtml, 00262 .send_text = agent_sendtext, 00263 .exception = agent_read, 00264 .indicate = agent_indicate, 00265 .fixup = agent_fixup, 00266 .bridged_channel = agent_bridgedchannel, 00267 }; 00268 00269 /*! 00270 * Adds an agent to the global list of agents. 00271 * 00272 * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" 00273 * \param pending If it is pending or not. 00274 * @return The just created agent. 00275 * \sa agent_pvt, agents. 00276 */ 00277 static struct agent_pvt *add_agent(char *agent, int pending) 00278 { 00279 char *parse; 00280 AST_DECLARE_APP_ARGS(args, 00281 AST_APP_ARG(agt); 00282 AST_APP_ARG(password); 00283 AST_APP_ARG(name); 00284 ); 00285 char *password = NULL; 00286 char *name = NULL; 00287 char *agt = NULL; 00288 struct agent_pvt *p; 00289 00290 parse = ast_strdupa(agent); 00291 00292 /* Extract username (agt), password and name from agent (args). */ 00293 AST_NONSTANDARD_APP_ARGS(args, parse, ','); 00294 00295 if(args.argc == 0) { 00296 ast_log(LOG_WARNING, "A blank agent line!\n"); 00297 return NULL; 00298 } 00299 00300 if(ast_strlen_zero(args.agt) ) { 00301 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00302 return NULL; 00303 } else 00304 agt = args.agt; 00305 00306 if(!ast_strlen_zero(args.password)) { 00307 password = args.password; 00308 while (*password && *password < 33) password++; 00309 } 00310 if(!ast_strlen_zero(args.name)) { 00311 name = args.name; 00312 while (*name && *name < 33) name++; 00313 } 00314 00315 /* Are we searching for the agent here ? To see if it exists already ? */ 00316 AST_LIST_TRAVERSE(&agents, p, list) { 00317 if (!pending && !strcmp(p->agent, agt)) 00318 break; 00319 } 00320 if (!p) { 00321 // Build the agent. 00322 if (!(p = ast_calloc(1, sizeof(*p)))) 00323 return NULL; 00324 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00325 ast_mutex_init(&p->lock); 00326 ast_mutex_init(&p->app_lock); 00327 p->owning_app = (pthread_t) -1; 00328 p->app_sleep_cond = 1; 00329 p->group = group; 00330 p->pending = pending; 00331 AST_LIST_INSERT_TAIL(&agents, p, list); 00332 } 00333 00334 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00335 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00336 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00337 p->ackcall = ackcall; 00338 p->autologoff = autologoff; 00339 00340 /* If someone reduces the wrapuptime and reloads, we want it 00341 * to change the wrapuptime immediately on all calls */ 00342 if (p->wrapuptime > wrapuptime) { 00343 struct timeval now = ast_tvnow(); 00344 /* XXX check what is this exactly */ 00345 00346 /* We won't be pedantic and check the tv_usec val */ 00347 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00348 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00349 p->lastdisc.tv_usec = now.tv_usec; 00350 } 00351 } 00352 p->wrapuptime = wrapuptime; 00353 00354 if (pending) 00355 p->dead = 1; 00356 else 00357 p->dead = 0; 00358 return p; 00359 } 00360 00361 /*! 00362 * Deletes an agent after doing some clean up. 00363 * Further documentation: How safe is this function ? What state should the agent be to be cleaned. 00364 * \param p Agent to be deleted. 00365 * \returns Always 0. 00366 */ 00367 static int agent_cleanup(struct agent_pvt *p) 00368 { 00369 struct ast_channel *chan = p->owner; 00370 p->owner = NULL; 00371 chan->tech_pvt = NULL; 00372 p->app_sleep_cond = 1; 00373 /* Release ownership of the agent to other threads (presumably running the login app). */ 00374 ast_mutex_unlock(&p->app_lock); 00375 if (chan) 00376 ast_channel_free(chan); 00377 if (p->dead) { 00378 ast_mutex_destroy(&p->lock); 00379 ast_mutex_destroy(&p->app_lock); 00380 free(p); 00381 } 00382 return 0; 00383 } 00384 00385 static int check_availability(struct agent_pvt *newlyavailable, int needlock); 00386 00387 static int agent_answer(struct ast_channel *ast) 00388 { 00389 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00390 return -1; 00391 } 00392 00393 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock) 00394 { 00395 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00396 char filename[AST_MAX_BUF]; 00397 int res = -1; 00398 if (!p) 00399 return -1; 00400 if (!ast->monitor) { 00401 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00402 /* substitute . for - */ 00403 if ((pointer = strchr(filename, '.'))) 00404 *pointer = '-'; 00405 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename); 00406 ast_monitor_start(ast, recordformat, tmp, needlock); 00407 ast_monitor_setjoinfiles(ast, 1); 00408 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext); 00409 #if 0 00410 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00411 #endif 00412 if (!ast->cdr) 00413 ast->cdr = ast_cdr_alloc(); 00414 ast_cdr_setuserfield(ast, tmp2); 00415 res = 0; 00416 } else 00417 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00418 return res; 00419 } 00420 00421 static int agent_start_monitoring(struct ast_channel *ast, int needlock) 00422 { 00423 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00424 } 00425 00426 static struct ast_frame *agent_read(struct ast_channel *ast) 00427 { 00428 struct agent_pvt *p = ast->tech_pvt; 00429 struct ast_frame *f = NULL; 00430 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00431 const char *status; 00432 ast_mutex_lock(&p->lock); 00433 CHECK_FORMATS(ast, p); 00434 if (p->chan) { 00435 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00436 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00437 f = ast_read(p->chan); 00438 } else 00439 f = &ast_null_frame; 00440 if (!f) { 00441 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00442 if (p->chan) { 00443 p->chan->_bridge = NULL; 00444 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00445 for us when the PBX instance that called login finishes */ 00446 if (!ast_strlen_zero(p->loginchan)) { 00447 if (p->chan && option_debug) 00448 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00449 00450 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00451 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00452 long logintime = time(NULL) - p->loginstart; 00453 p->loginstart = 0; 00454 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00455 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00456 } 00457 ast_hangup(p->chan); 00458 if (p->wrapuptime && p->acknowledged) 00459 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00460 } 00461 p->chan = NULL; 00462 p->acknowledged = 0; 00463 } 00464 } else { 00465 /* if acknowledgement is not required, and the channel is up, we may have missed 00466 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00467 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) 00468 p->acknowledged = 1; 00469 switch (f->frametype) { 00470 case AST_FRAME_CONTROL: 00471 if (f->subclass == AST_CONTROL_ANSWER) { 00472 if (p->ackcall) { 00473 if (option_verbose > 2) 00474 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name); 00475 /* Don't pass answer along */ 00476 ast_frfree(f); 00477 f = &ast_null_frame; 00478 } else { 00479 p->acknowledged = 1; 00480 /* Use the builtin answer frame for the 00481 recording start check below. */ 00482 ast_frfree(f); 00483 f = &answer_frame; 00484 } 00485 } 00486 break; 00487 case AST_FRAME_DTMF_BEGIN: 00488 case AST_FRAME_DTMF_END: 00489 if (!p->acknowledged && (f->subclass == '#')) { 00490 if (option_verbose > 2) 00491 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name); 00492 p->acknowledged = 1; 00493 ast_frfree(f); 00494 f = &answer_frame; 00495 } else if (f->subclass == '*' && endcall) { 00496 /* terminates call */ 00497 ast_frfree(f); 00498 f = NULL; 00499 } 00500 break; 00501 case AST_FRAME_VOICE: 00502 case AST_FRAME_VIDEO: 00503 /* don't pass voice or video until the call is acknowledged */ 00504 if (!p->acknowledged) { 00505 ast_frfree(f); 00506 f = &ast_null_frame; 00507 } 00508 default: 00509 /* pass everything else on through */ 00510 break; 00511 } 00512 } 00513 00514 CLEANUP(ast,p); 00515 if (p->chan && !p->chan->_bridge) { 00516 if (strcasecmp(p->chan->tech->type, "Local")) { 00517 p->chan->_bridge = ast; 00518 if (p->chan && option_debug) 00519 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00520 } 00521 } 00522 ast_mutex_unlock(&p->lock); 00523 if (recordagentcalls && f == &answer_frame) 00524 agent_start_monitoring(ast,0); 00525 return f; 00526 } 00527 00528 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) 00529 { 00530 struct agent_pvt *p = ast->tech_pvt; 00531 int res = -1; 00532 ast_mutex_lock(&p->lock); 00533 if (p->chan) 00534 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00535 ast_mutex_unlock(&p->lock); 00536 return res; 00537 } 00538 00539 static int agent_sendtext(struct ast_channel *ast, const char *text) 00540 { 00541 struct agent_pvt *p = ast->tech_pvt; 00542 int res = -1; 00543 ast_mutex_lock(&p->lock); 00544 if (p->chan) 00545 res = ast_sendtext(p->chan, text); 00546 ast_mutex_unlock(&p->lock); 00547 return res; 00548 } 00549 00550 static int agent_write(struct ast_channel *ast, struct ast_frame *f) 00551 { 00552 struct agent_pvt *p = ast->tech_pvt; 00553 int res = -1; 00554 CHECK_FORMATS(ast, p); 00555 ast_mutex_lock(&p->lock); 00556 if (!p->chan) 00557 res = 0; 00558 else { 00559 if ((f->frametype != AST_FRAME_VOICE) || 00560 (f->frametype != AST_FRAME_VIDEO) || 00561 (f->subclass == p->chan->writeformat)) { 00562 res = ast_write(p->chan, f); 00563 } else { 00564 if (option_debug) 00565 ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00566 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00567 ast->name, p->chan->name); 00568 res = 0; 00569 } 00570 } 00571 CLEANUP(ast, p); 00572 ast_mutex_unlock(&p->lock); 00573 return res; 00574 } 00575 00576 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) 00577 { 00578 struct agent_pvt *p = newchan->tech_pvt; 00579 ast_mutex_lock(&p->lock); 00580 if (p->owner != oldchan) { 00581 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00582 ast_mutex_unlock(&p->lock); 00583 return -1; 00584 } 00585 p->owner = newchan; 00586 ast_mutex_unlock(&p->lock); 00587 return 0; 00588 } 00589 00590 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen) 00591 { 00592 struct agent_pvt *p = ast->tech_pvt; 00593 int res = -1; 00594 ast_mutex_lock(&p->lock); 00595 if (p->chan) 00596 res = ast_indicate_data(p->chan, condition, data, datalen); 00597 else 00598 res = 0; 00599 ast_mutex_unlock(&p->lock); 00600 return res; 00601 } 00602 00603 static int agent_digit_begin(struct ast_channel *ast, char digit) 00604 { 00605 struct agent_pvt *p = ast->tech_pvt; 00606 int res = -1; 00607 ast_mutex_lock(&p->lock); 00608 ast_senddigit_begin(p->chan, digit); 00609 ast_mutex_unlock(&p->lock); 00610 return res; 00611 } 00612 00613 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration) 00614 { 00615 struct agent_pvt *p = ast->tech_pvt; 00616 int res = -1; 00617 ast_mutex_lock(&p->lock); 00618 ast_senddigit_end(p->chan, digit, duration); 00619 ast_mutex_unlock(&p->lock); 00620 return res; 00621 } 00622 00623 static int agent_call(struct ast_channel *ast, char *dest, int timeout) 00624 { 00625 struct agent_pvt *p = ast->tech_pvt; 00626 int res = -1; 00627 int newstate=0; 00628 ast_mutex_lock(&p->lock); 00629 p->acknowledged = 0; 00630 if (!p->chan) { 00631 if (p->pending) { 00632 if (option_debug) 00633 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00634 newstate = AST_STATE_DIALING; 00635 res = 0; 00636 } else { 00637 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00638 res = -1; 00639 } 00640 ast_mutex_unlock(&p->lock); 00641 if (newstate) 00642 ast_setstate(ast, newstate); 00643 return res; 00644 } else if (!ast_strlen_zero(p->loginchan)) { 00645 time(&p->start); 00646 /* Call on this agent */ 00647 if (option_verbose > 2) 00648 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00649 ast_set_callerid(p->chan, 00650 ast->cid.cid_num, ast->cid.cid_name, NULL); 00651 ast_channel_inherit_variables(ast, p->chan); 00652 res = ast_call(p->chan, p->loginchan, 0); 00653 CLEANUP(ast,p); 00654 ast_mutex_unlock(&p->lock); 00655 return res; 00656 } 00657 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00658 if (option_debug > 2) 00659 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language); 00660 res = ast_streamfile(p->chan, beep, p->chan->language); 00661 if (option_debug > 2) 00662 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res); 00663 if (!res) { 00664 res = ast_waitstream(p->chan, ""); 00665 if (option_debug > 2) 00666 ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res); 00667 } 00668 if (!res) { 00669 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00670 if (option_debug > 2) 00671 ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res); 00672 if (res) 00673 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00674 } else { 00675 /* Agent hung-up */ 00676 p->chan = NULL; 00677 } 00678 00679 if (!res) { 00680 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00681 if (option_debug > 2) 00682 ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res); 00683 if (res) 00684 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00685 } 00686 if(!res) { 00687 /* Call is immediately up, or might need ack */ 00688 if (p->ackcall > 1) 00689 newstate = AST_STATE_RINGING; 00690 else { 00691 newstate = AST_STATE_UP; 00692 if (recordagentcalls) 00693 agent_start_monitoring(ast, 0); 00694 p->acknowledged = 1; 00695 } 00696 res = 0; 00697 } 00698 CLEANUP(ast, p); 00699 ast_mutex_unlock(&p->lock); 00700 if (newstate) 00701 ast_setstate(ast, newstate); 00702 return res; 00703 } 00704 00705 /*! \brief store/clear the global variable that stores agentid based on the callerid */ 00706 static void set_agentbycallerid(const char *callerid, const char *agent) 00707 { 00708 char buf[AST_MAX_BUF]; 00709 00710 /* if there is no Caller ID, nothing to do */ 00711 if (ast_strlen_zero(callerid)) 00712 return; 00713 00714 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00715 pbx_builtin_setvar_helper(NULL, buf, agent); 00716 } 00717 00718 static int agent_hangup(struct ast_channel *ast) 00719 { 00720 struct agent_pvt *p = ast->tech_pvt; 00721 int howlong = 0; 00722 const char *status; 00723 ast_mutex_lock(&p->lock); 00724 p->owner = NULL; 00725 ast->tech_pvt = NULL; 00726 p->app_sleep_cond = 1; 00727 p->acknowledged = 0; 00728 00729 /* if they really are hung up then set start to 0 so the test 00730 * later if we're called on an already downed channel 00731 * doesn't cause an agent to be logged out like when 00732 * agent_request() is followed immediately by agent_hangup() 00733 * as in apps/app_chanisavail.c:chanavail_exec() 00734 */ 00735 00736 if (option_debug) 00737 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00738 if (p->start && (ast->_state != AST_STATE_UP)) { 00739 howlong = time(NULL) - p->start; 00740 p->start = 0; 00741 } else if (ast->_state == AST_STATE_RESERVED) 00742 howlong = 0; 00743 else 00744 p->start = 0; 00745 if (p->chan) { 00746 p->chan->_bridge = NULL; 00747 /* If they're dead, go ahead and hang up on the agent now */ 00748 if (!ast_strlen_zero(p->loginchan)) { 00749 /* Store last disconnect time */ 00750 if (p->wrapuptime) 00751 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00752 else 00753 p->lastdisc = ast_tv(0,0); 00754 if (p->chan) { 00755 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00756 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00757 long logintime = time(NULL) - p->loginstart; 00758 p->loginstart = 0; 00759 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00760 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00761 } 00762 /* Recognize the hangup and pass it along immediately */ 00763 ast_hangup(p->chan); 00764 p->chan = NULL; 00765 } 00766 if (option_debug) 00767 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00768 if (howlong && p->autologoff && (howlong > p->autologoff)) { 00769 long logintime = time(NULL) - p->loginstart; 00770 p->loginstart = 0; 00771 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00772 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00773 } 00774 } else if (p->dead) { 00775 ast_channel_lock(p->chan); 00776 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00777 ast_channel_unlock(p->chan); 00778 } else if (p->loginstart) { 00779 ast_channel_lock(p->chan); 00780 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00781 S_OR(p->moh, NULL), 00782 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00783 ast_channel_unlock(p->chan); 00784 } 00785 } 00786 ast_mutex_unlock(&p->lock); 00787 /* Only register a device state change if the agent is still logged in */ 00788 if (p->loginstart) 00789 ast_device_state_changed("Agent/%s", p->agent); 00790 00791 if (p->p