#include "asterisk.h"
#include <sys/socket.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/signal.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"

Go to the source code of this file.
Data Structures | |
| struct | agent_pvt |
| Structure representing an agent. More... | |
| struct | agents |
Defines | |
| #define | AST_MAX_AGENT 80 |
| #define | AST_MAX_BUF 256 |
| #define | AST_MAX_FILENAME_LEN 256 |
| #define | CHECK_FORMATS(ast, p) |
| #define | CLEANUP(ast, p) |
| Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
| #define | DEFAULT_ACCEPTDTMF '#' |
| #define | DEFAULT_ENDDTMF '*' |
| #define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
| #define | PA_MAX_LEN 2048 |
Enumerations | |
| enum | { AGENT_FLAG_ACKCALL = (1 << 0), AGENT_FLAG_AUTOLOGOFF = (1 << 1), AGENT_FLAG_WRAPUPTIME = (1 << 2), AGENT_FLAG_ACCEPTDTMF = (1 << 3), AGENT_FLAG_ENDDTMF = (1 << 4) } |
Functions | |
| static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | action_agent_logoff (struct mansession *s, const struct message *m) |
| static int | action_agents (struct mansession *s, const struct message *m) |
| static struct agent_pvt * | add_agent (const char *agent, int pending) |
| static int | agent_ack_sleep (void *data) |
| static int | agent_answer (struct ast_channel *ast) |
| static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
| static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
| static int | agent_cleanup (struct agent_pvt *p) |
| static int | agent_cont_sleep (void *data) |
| static int | agent_devicestate (void *data) |
| Part of PBX channel interface. | |
| static int | agent_digit_begin (struct ast_channel *ast, char digit) |
| static int | agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
| static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
| static struct ast_channel * | agent_get_base_channel (struct ast_channel *chan) |
| return the channel or base channel if one exists. This function assumes the channel it is called on is already locked | |
| static int | agent_hangup (struct ast_channel *ast) |
| static int | agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
| static int | agent_logoff (const char *agent, int soft) |
| static char * | agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static struct ast_channel * | agent_new (struct agent_pvt *p, int state, const char *linkedid) |
| Create new agent channel. | |
| static struct ast_frame * | agent_read (struct ast_channel *ast) |
| static struct ast_channel * | agent_request (const char *type, int format, const struct ast_channel *requestor, void *data, int *cause) |
| Part of the Asterisk PBX interface. | |
| static int | agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen) |
| static int | agent_sendtext (struct ast_channel *ast, const char *text) |
| static int | agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base) |
| static int | agent_start_monitoring (struct ast_channel *ast, int needlock) |
| static int | agent_write (struct ast_channel *ast, struct ast_frame *f) |
| static int | agentmonitoroutgoing_exec (struct ast_channel *chan, const char *data) |
| Called by the AgentMonitorOutgoing application (from the dial plan). | |
| static char * | agents_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | agents_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | check_availability (struct agent_pvt *newlyavailable, int needlock) |
| static int | check_beep (struct agent_pvt *newlyavailable, int needlock) |
| static char * | complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state) |
| static struct agent_pvt * | find_agent (char *agentid) |
| static int | function_agent (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
| static int | load_module (void) |
| Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file. | |
| static int | login_exec (struct ast_channel *chan, const char *data) |
| Log in agent application. | |
| static force_inline int | powerof (unsigned int d) |
| static int | read_agent_config (int reload) |
| static int | reload (void) |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| static char | acceptdtmf = DEFAULT_ACCEPTDTMF |
| static int | ackcall |
| static struct ast_custom_function | agent_function |
| static const char | agent_logoff_usage [] |
| static struct ast_channel_tech | agent_tech |
| Channel interface description for PBX integration. | |
| static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye" |
| static const char | app [] = "AgentLogin" |
| static const char | app3 [] = "AgentMonitorOutgoing" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static int | autologoff |
| static int | autologoffunavail = 0 |
| static char | beep [AST_MAX_BUF] = "beep" |
| static struct ast_cli_entry | cli_agents [] |
| static const char | config [] = "agents.conf" |
| static int | endcall |
| static char | enddtmf = DEFAULT_ENDDTMF |
| static ast_group_t | group |
| static int | maxlogintries = 3 |
| static char | moh [80] = "default" |
| static int | multiplelogin = 1 |
| static const char | pa_family [] = "Agents" |
| static int | recordagentcalls = 0 |
| static char | recordformat [AST_MAX_BUF] = "" |
| static char | recordformatext [AST_MAX_BUF] = "" |
| static char | savecallsin [AST_MAX_BUF] = "" |
| static const char | tdesc [] = "Call Agent Proxy Channel" |
| static int | updatecdr = 0 |
| static char | urlprefix [AST_MAX_BUF] = "" |
| static int | wrapuptime |
This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.
Definition in file chan_agent.c.
| #define AST_MAX_AGENT 80 |
Agent ID or Password max length
Definition at line 205 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().
| #define AST_MAX_BUF 256 |
Definition at line 206 of file chan_agent.c.
Referenced by __agent_start_monitoring(), agentmonitoroutgoing_exec(), agents_show(), and agents_show_online().
| #define AST_MAX_FILENAME_LEN 256 |
| #define CHECK_FORMATS | ( | ast, | |||
| p | ) |
| #define CLEANUP | ( | ast, | |||
| p | ) |
Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
Definition at line 301 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
| #define DEFAULT_ACCEPTDTMF '#' |
Definition at line 212 of file chan_agent.c.
| #define DEFAULT_ENDDTMF '*' |
Definition at line 213 of file chan_agent.c.
| #define GETAGENTBYCALLERID "AGENTBYCALLERID" |
| #define PA_MAX_LEN 2048 |
The maximum length of each persistent member agent database entry
Definition at line 210 of file chan_agent.c.
| anonymous enum |
| AGENT_FLAG_ACKCALL | |
| AGENT_FLAG_AUTOLOGOFF | |
| AGENT_FLAG_WRAPUPTIME | |
| AGENT_FLAG_ACCEPTDTMF | |
| AGENT_FLAG_ENDDTMF |
Definition at line 238 of file chan_agent.c.
00238 { 00239 AGENT_FLAG_ACKCALL = (1 << 0), 00240 AGENT_FLAG_AUTOLOGOFF = (1 << 1), 00241 AGENT_FLAG_WRAPUPTIME = (1 << 2), 00242 AGENT_FLAG_ACCEPTDTMF = (1 << 3), 00243 AGENT_FLAG_ENDDTMF = (1 << 4), 00244 };
| static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
| struct agent_pvt * | p, | |||
| int | needlock | |||
| ) | [static] |
Definition at line 495 of file chan_agent.c.
References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose, ast_channel::cdr, LOG_ERROR, ast_channel::monitor, ast_channel::uniqueid, X_REC_IN, and X_REC_OUT.
Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().
00496 { 00497 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00498 char filename[AST_MAX_BUF]; 00499 int res = -1; 00500 if (!p) 00501 return -1; 00502 if (!ast->monitor) { 00503 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00504 /* substitute . for - */ 00505 if ((pointer = strchr(filename, '.'))) 00506 *pointer = '-'; 00507 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00508 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT); 00509 ast_monitor_setjoinfiles(ast, 1); 00510 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00511 #if 0 00512 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00513 #endif 00514 if (!ast->cdr) 00515 ast->cdr = ast_cdr_alloc(); 00516 ast_cdr_setuserfield(ast, tmp2); 00517 res = 0; 00518 } else 00519 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00520 return res; 00521 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2362 of file chan_agent.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2362 of file chan_agent.c.
| static int action_agent_logoff | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Sets an agent as no longer logged in in the Manager API. It is registered on load_module() and it gets called by the manager backend.
| s | ||
| m |
Definition at line 1591 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().
Referenced by load_module().
01592 { 01593 const char *agent = astman_get_header(m, "Agent"); 01594 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01595 int soft; 01596 int ret; /* return value of agent_logoff */ 01597 01598 if (ast_strlen_zero(agent)) { 01599 astman_send_error(s, m, "No agent specified"); 01600 return 0; 01601 } 01602 01603 soft = ast_true(soft_s) ? 1 : 0; 01604 ret = agent_logoff(agent, soft); 01605 if (ret == 0) 01606 astman_send_ack(s, m, "Agent logged out"); 01607 else 01608 astman_send_error(s, m, "No such agent"); 01609 01610 return 0; 01611 }
| static int action_agents | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.
| s | ||
| m |
Definition at line 1442 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::agent, ast_bridged_channel(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::lock, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, S_OR, and status.
Referenced by load_module().
01443 { 01444 const char *id = astman_get_header(m,"ActionID"); 01445 char idText[256] = ""; 01446 struct agent_pvt *p; 01447 char *username = NULL; 01448 char *loginChan = NULL; 01449 char *talkingto = NULL; 01450 char *talkingtoChan = NULL; 01451 char *status = NULL; 01452 01453 if (!ast_strlen_zero(id)) 01454 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01455 astman_send_ack(s, m, "Agents will follow"); 01456 AST_LIST_LOCK(&agents); 01457 AST_LIST_TRAVERSE(&agents, p, list) { 01458 ast_mutex_lock(&p->lock); 01459 01460 /* Status Values: 01461 AGENT_LOGGEDOFF - Agent isn't logged in 01462 AGENT_IDLE - Agent is logged in, and waiting for call 01463 AGENT_ONCALL - Agent is logged in, and on a call 01464 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01465 01466 username = S_OR(p->name, "None"); 01467 01468 /* Set a default status. It 'should' get changed. */ 01469 status = "AGENT_UNKNOWN"; 01470 01471 if (p->chan) { 01472 loginChan = ast_strdupa(p->chan->name); 01473 if (p->owner && p->owner->_bridge) { 01474 talkingto = p->chan->cid.cid_num; 01475 if (ast_bridged_channel(p->owner)) 01476 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name); 01477 else 01478 talkingtoChan = "n/a"; 01479 status = "AGENT_ONCALL"; 01480 } else { 01481 talkingto = "n/a"; 01482 talkingtoChan = "n/a"; 01483 status = "AGENT_IDLE"; 01484 } 01485 } else { 01486 loginChan = "n/a"; 01487 talkingto = "n/a"; 01488 talkingtoChan = "n/a"; 01489 status = "AGENT_LOGGEDOFF"; 01490 } 01491 01492 astman_append(s, "Event: Agents\r\n" 01493 "Agent: %s\r\n" 01494 "Name: %s\r\n" 01495 "Status: %s\r\n" 01496 "LoggedInChan: %s\r\n" 01497 "LoggedInTime: %d\r\n" 01498 "TalkingTo: %s\r\n" 01499 "TalkingToChan: %s\r\n" 01500 "%s" 01501 "\r\n", 01502 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01503 ast_mutex_unlock(&p->lock); 01504 } 01505 AST_LIST_UNLOCK(&agents); 01506 astman_append(s, "Event: AgentsComplete\r\n" 01507 "%s" 01508 "\r\n",idText); 01509 return 0; 01510 }
| static struct agent_pvt* add_agent | ( | const char * | agent, | |
| int | pending | |||
| ) | [static, read] |
Adds an agent to the global list of agents.
| agent | A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith" | |
| pending | If it is pending or not. |
Definition at line 365 of file chan_agent.c.
References agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::agent, AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_APP_ARG, ast_calloc, ast_cond_init(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::enddtmf, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00366 { 00367 char *parse; 00368 AST_DECLARE_APP_ARGS(args, 00369 AST_APP_ARG(agt); 00370 AST_APP_ARG(password); 00371 AST_APP_ARG(name); 00372 ); 00373 char *password = NULL; 00374 char *name = NULL; 00375 char *agt = NULL; 00376 struct agent_pvt *p; 00377 00378 parse = ast_strdupa(agent); 00379 00380 /* Extract username (agt), password and name from agent (args). */ 00381 AST_STANDARD_APP_ARGS(args, parse); 00382 00383 if(args.argc == 0) { 00384 ast_log(LOG_WARNING, "A blank agent line!\n"); 00385 return NULL; 00386 } 00387 00388 if(ast_strlen_zero(args.agt) ) { 00389 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00390 return NULL; 00391 } else 00392 agt = args.agt; 00393 00394 if(!ast_strlen_zero(args.password)) { 00395 password = args.password; 00396 while (*password && *password < 33) password++; 00397 } 00398 if(!ast_strlen_zero(args.name)) { 00399 name = args.name; 00400 while (*name && *name < 33) name++; 00401 } 00402 00403 /* Are we searching for the agent here ? To see if it exists already ? */ 00404 AST_LIST_TRAVERSE(&agents, p, list) { 00405 if (!pending && !strcmp(p->agent, agt)) 00406 break; 00407 } 00408 if (!p) { 00409 // Build the agent. 00410 if (!(p = ast_calloc(1, sizeof(*p)))) 00411 return NULL; 00412 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00413 ast_mutex_init(&p->lock); 00414 ast_mutex_init(&p->app_lock); 00415 ast_cond_init(&p->app_complete_cond, NULL); 00416 p->app_lock_flag = 0; 00417 p->app_sleep_cond = 1; 00418 p->group = group; 00419 p->pending = pending; 00420 AST_LIST_INSERT_TAIL(&agents, p, list); 00421 } 00422 00423 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00424 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00425 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00426 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) { 00427 p->ackcall = ackcall; 00428 } 00429 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) { 00430 p->autologoff = autologoff; 00431 } 00432 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) { 00433 p->acceptdtmf = acceptdtmf; 00434 } 00435 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) { 00436 p->enddtmf = enddtmf; 00437 } 00438 00439 /* If someone reduces the wrapuptime and reloads, we want it 00440 * to change the wrapuptime immediately on all calls */ 00441 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) { 00442 struct timeval now = ast_tvnow(); 00443 /* XXX check what is this exactly */ 00444 00445 /* We won't be pedantic and check the tv_usec val */ 00446 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00447 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00448 p->lastdisc.tv_usec = now.tv_usec; 00449 } 00450 } 00451 p->wrapuptime = wrapuptime; 00452 00453 if (pending) 00454 p->dead = 1; 00455 else 00456 p->dead = 0; 00457 return p; 00458 }
| static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 931 of file chan_agent.c.
References agent_pvt::acceptdtmf, agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, f, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.
Referenced by login_exec().
00932 { 00933 struct agent_pvt *p; 00934 int res=0; 00935 int to = 1000; 00936 struct ast_frame *f; 00937 00938 /* Wait a second and look for something */ 00939 00940 p = (struct agent_pvt *) data; 00941 if (!p->chan) 00942 return -1; 00943 00944 for(;;) { 00945 to = ast_waitfor(p->chan, to); 00946 if (to < 0) 00947 return -1; 00948 if (!to) 00949 return 0; 00950 f = ast_read(p->chan); 00951 if (!f) 00952 return -1; 00953 if (f->frametype == AST_FRAME_DTMF) 00954 res = f->subclass; 00955 else 00956 res = 0; 00957 ast_frfree(f); 00958 ast_mutex_lock(&p->lock); 00959 if (!p->app_sleep_cond) { 00960 ast_mutex_unlock(&p->lock); 00961 return 0; 00962 } else if (res == p->acceptdtmf) { 00963 ast_mutex_unlock(&p->lock); 00964 return 1; 00965 } 00966 ast_mutex_unlock(&p->lock); 00967 res = 0; 00968 } 00969 return res; 00970 }
| static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 489 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00490 { 00491 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00492 return -1; 00493 }
| static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | bridge | |||
| ) | [static, read] |
Definition at line 972 of file chan_agent.c.
References ast_channel::_bridge, ast_debug, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.
00973 { 00974 struct agent_pvt *p = bridge->tech_pvt; 00975 struct ast_channel *ret = NULL; 00976 00977 if (p) { 00978 if (chan == p->chan) 00979 ret = bridge->_bridge; 00980 else if (chan == bridge->_bridge) 00981 ret = p->chan; 00982 } 00983 00984 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 00985 return ret; 00986 }
| static int agent_call | ( | struct ast_channel * | ast, | |
| char * | dest, | |||
| int | timeout | |||
| ) | [static] |
Definition at line 732 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_best_codec(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_verb, ast_waitstream(), agent_pvt::chan, CLEANUP, ast_channel::language, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.
00733 { 00734 struct agent_pvt *p = ast->tech_pvt; 00735 int res = -1; 00736 int newstate=0; 00737 ast_mutex_lock(&p->lock); 00738 p->acknowledged = 0; 00739 if (!p->chan) { 00740 if (p->pending) { 00741 ast_debug(1, "Pretending to dial on pending agent\n"); 00742 newstate = AST_STATE_DIALING; 00743 res = 0; 00744 } else { 00745 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00746 res = -1; 00747 } 00748 ast_mutex_unlock(&p->lock); 00749 if (newstate) 00750 ast_setstate(ast, newstate); 00751 return res; 00752 } 00753 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00754 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language); 00755 res = ast_streamfile(p->chan, beep, p->chan->language); 00756 ast_debug(3, "Played beep, result '%d'\n", res); 00757 if (!res) { 00758 res = ast_waitstream(p->chan, ""); 00759 ast_debug(3, "Waited for stream, result '%d'\n", res); 00760 } 00761 if (!res) { 00762 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00763 ast_debug(3, "Set read format, result '%d'\n", res); 00764 if (res) 00765 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00766 } else { 00767 /* Agent hung-up */ 00768 p->chan = NULL; 00769 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00770 } 00771 00772 if (!res) { 00773 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00774 ast_debug(3, "Set write format, result '%d'\n", res); 00775 if (res) 00776 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00777 } 00778 if(!res) { 00779 /* Call is immediately up, or might need ack */ 00780 if (p->ackcall) { 00781 newstate = AST_STATE_RINGING; 00782 } else { 00783 newstate = AST_STATE_UP; 00784 if (recordagentcalls) 00785 agent_start_monitoring(ast, 0); 00786 p->acknowledged = 1; 00787 } 00788 res = 0; 00789 } 00790 CLEANUP(ast, p); 00791 ast_mutex_unlock(&p->lock); 00792 if (newstate) 00793 ast_setstate(ast, newstate); 00794 return res; 00795 }
| static int agent_cleanup | ( | struct agent_pvt * | p | ) | [static] |
Deletes an agent after doing some clean up. Further documentation: How safe is this function ? What state should the agent be to be cleaned.
| p | Agent to be deleted. |
Definition at line 466 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_release(), ast_cond_destroy(), ast_cond_signal(), ast_free, ast_mutex_destroy(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00467 { 00468 struct ast_channel *chan = p->owner; 00469 p->owner = NULL; 00470 chan->tech_pvt = NULL; 00471 p->app_sleep_cond = 1; 00472 /* Release ownership of the agent to other threads (presumably running the login app). */ 00473 p->app_lock_flag = 0; 00474 ast_cond_signal(&p->app_complete_cond); 00475 if (chan) { 00476 chan = ast_channel_release(chan); 00477 } 00478 if (p->dead) { 00479 ast_mutex_destroy(&p->lock); 00480 ast_mutex_destroy(&p->app_lock); 00481 ast_cond_destroy(&p->app_complete_cond); 00482 ast_free(p); 00483 } 00484 return 0; 00485 }
| static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 910 of file chan_agent.c.
References agent_pvt::app_sleep_cond, ast_debug, ast_mutex_lock(), ast_mutex_unlock(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::lastdisc, and agent_pvt::lock.
Referenced by login_exec().
00911 { 00912 struct agent_pvt *p; 00913 int res; 00914 00915 p = (struct agent_pvt *)data; 00916 00917 ast_mutex_lock(&p->lock); 00918 res = p->app_sleep_cond; 00919 if (p->lastdisc.tv_sec) { 00920 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 00921 res = 1; 00922 } 00923 ast_mutex_unlock(&p->lock); 00924 00925 if (!res) 00926 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 00927 00928 return res; 00929 }
| static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2168 of file chan_agent.c.
References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, agent_pvt::owner, agent_pvt::pending, and s.
02169 { 02170 struct agent_pvt *p; 02171 char *s; 02172 ast_group_t groupmatch; 02173 int groupoff; 02174 int res = AST_DEVICE_INVALID; 02175 02176 s = data; 02177 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) 02178 groupmatch = (1 << groupoff); 02179 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02180 groupmatch = (1 << groupoff); 02181 } else 02182 groupmatch = 0; 02183 02184 /* Check actual logged in agents first */ 02185 AST_LIST_LOCK(&agents); 02186 AST_LIST_TRAVERSE(&agents, p, list) { 02187 ast_mutex_lock(&p->lock); 02188 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02189 if (p->owner) { 02190 if (res != AST_DEVICE_INUSE) 02191 res = AST_DEVICE_BUSY; 02192 } else { 02193 if (res == AST_DEVICE_BUSY) 02194 res = AST_DEVICE_INUSE; 02195 if (p->chan) { 02196 if (res == AST_DEVICE_INVALID) 02197 res = AST_DEVICE_UNKNOWN; 02198 } else if (res == AST_DEVICE_INVALID) 02199 res = AST_DEVICE_UNAVAILABLE; 02200 } 02201 if (!strcmp(data, p->agent)) { 02202 ast_mutex_unlock(&p->lock); 02203 break; 02204 } 02205 } 02206 ast_mutex_unlock(&p->lock); 02207 } 02208 AST_LIST_UNLOCK(&agents); 02209 return res; 02210 }
| static int agent_digit_begin | ( | struct ast_channel * | ast, | |
| char | digit | |||
| ) | [static] |
Definition at line 710 of file chan_agent.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_senddigit_begin(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00711 { 00712 struct agent_pvt *p = ast->tech_pvt; 00713 ast_mutex_lock(&p->lock); 00714 if (p->chan) { 00715 ast_senddigit_begin(p->chan, digit); 00716 } 00717 ast_mutex_unlock(&p->lock); 00718 return 0; 00719 }
| static int agent_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 721 of file chan_agent.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_senddigit_end(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00722 { 00723 struct agent_pvt *p = ast->tech_pvt; 00724 ast_mutex_lock(&p->lock); 00725 if (p->chan) { 00726 ast_senddigit_end(p->chan, digit, duration); 00727 } 00728 ast_mutex_unlock(&p->lock); 00729 return 0; 00730 }
| static int agent_fixup | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
Definition at line 677 of file chan_agent.c.
References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lock, LOG_WARNING, agent_pvt::owner, and ast_channel::tech_pvt.
00678 { 00679 struct agent_pvt *p = newchan->tech_pvt; 00680 ast_mutex_lock(&p->lock); 00681 if (p->owner != oldchan) { 00682 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00683 ast_mutex_unlock(&p->lock); 00684 return -1; 00685 } 00686 p->owner = newchan; 00687 ast_mutex_unlock(&p->lock); 00688 return 0; 00689 }
| struct ast_channel * agent_get_base_channel | ( | struct ast_channel * | chan | ) | [static, read] |
return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
Definition at line 798 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00799 { 00800 struct agent_pvt *p = NULL; 00801 struct ast_channel *base = chan; 00802 00803 /* chan is locked by the calling function */ 00804 if (!chan || !chan->tech_pvt) { 00805 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); 00806 return NULL; 00807 } 00808 p = chan->tech_pvt; 00809 if (p->chan) 00810 base = p->chan; 00811 return base; 00812 }
| static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 831 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), AST_CONTROL_HOLD, ast_debug, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), ast_free, ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), ast_tvnow(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::logincallerid, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::owner, agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.
00832 { 00833 struct agent_pvt *p = ast->tech_pvt; 00834 int howlong = 0; 00835 00836 ast_mutex_lock(&p->lock); 00837 p->owner = NULL; 00838 ast->tech_pvt = NULL; 00839 p->app_sleep_cond = 1; 00840 p->acknowledged = 0; 00841 00842 /* if they really are hung up then set start to 0 so the test 00843 * later if we're called on an already downed channel 00844 * doesn't cause an agent to be logged out like when 00845 * agent_request() is followed immediately by agent_hangup() 00846 * as in apps/app_chanisavail.c:chanavail_exec() 00847 */ 00848 00849 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00850 if (p->start && (ast->_state != AST_STATE_UP)) { 00851 howlong = time(NULL) - p->start; 00852 p->start = 0; 00853 } else if (ast->_state == AST_STATE_RESERVED) 00854 howlong = 0; 00855 else 00856 p->start = 0; 00857 if (p->chan) { 00858 p->chan->_bridge = NULL; 00859 /* If they're dead, go ahead and hang up on the agent now */ 00860 if (p->dead) { 00861 ast_channel_lock(p->chan); 00862 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00863 ast_channel_unlock(p->chan); 00864 } else if (p->loginstart) { 00865 ast_channel_lock(p->chan); 00866 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00867 S_OR(p->moh, NULL), 00868 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00869 ast_channel_unlock(p->chan); 00870 } 00871 } 00872 ast_mutex_unlock(&p->lock); 00873 00874 /* Only register a device state change if the agent is still logged in */ 00875 if (!p->loginstart) { 00876 p->logincallerid[0] = '\0'; 00877 } else { 00878 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00879 } 00880 00881 if (p->pending) { 00882 AST_LIST_LOCK(&agents); 00883 AST_LIST_REMOVE(&agents, p, list); 00884 AST_LIST_UNLOCK(&agents); 00885 } 00886 if (p->abouttograb) { 00887 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00888 kill it later */ 00889 p->abouttograb = 0; 00890 } else if (p->dead) { 00891 ast_mutex_destroy(&p->lock); 00892 ast_mutex_destroy(&p->app_lock); 00893 ast_cond_destroy(&p->app_complete_cond); 00894 ast_free(p); 00895 } else { 00896 if (p->chan) { 00897 /* Not dead -- check availability now */ 00898 ast_mutex_lock(&p->lock); 00899 /* Store last disconnect time */ 00900 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00901 ast_mutex_unlock(&p->lock); 00902 } 00903 /* Release ownership of the agent to other threads (presumably running the login app). */ 00904 p->app_lock_flag = 0; 00905 ast_cond_signal(&p->app_complete_cond); 00906 } 00907 return 0; 00908 }
| static int agent_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 691 of file chan_agent.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, ast_channel::tech, and ast_channel::tech_pvt.
00692 { 00693 struct agent_pvt *p = ast->tech_pvt; 00694 int res = -1; 00695 ast_mutex_lock(&p->lock); 00696 if (p->chan && !ast_check_hangup(p->chan)) { 00697 while (ast_channel_trylock(p->chan)) { 00698 ast_channel_unlock(ast); 00699 usleep(1); 00700 ast_channel_lock(ast); 00701 } 00702 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00703 ast_channel_unlock(p->chan); 00704 } else 00705 res = 0; 00706 ast_mutex_unlock(&p->lock); 00707 return res; 00708 }
| static int agent_logoff | ( | const char * | agent, | |
| int | soft | |||
| ) | [static] |
Definition at line 1512 of file chan_agent.c.
References agent_pvt::agent, ast_channel_trylock, ast_channel_unlock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, DEADLOCK_AVOIDANCE, agent_pvt::deferlogoff, agent_pvt::lock, and agent_pvt::owner.
Referenced by action_agent_logoff(), agent_logoff_cmd(), and agent_read().
01513 { 01514 struct agent_pvt *p; 01515 int ret = -1; /* Return -1 if no agent if found */ 01516 01517 AST_LIST_LOCK(&agents); 01518 AST_LIST_TRAVERSE(&agents, p, list) { 01519 if (!strcasecmp(p->agent, agent)) { 01520 ret = 0; 01521 if (p->owner || p->chan) { 01522 if (!soft) { 01523 ast_mutex_lock(&p->lock); 01524 01525 while (p->owner && ast_channel_trylock(p->owner)) { 01526 DEADLOCK_AVOIDANCE(&p->lock); 01527 } 01528 if (p->owner) { 01529 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01530 ast_channel_unlock(p->owner); 01531 } 01532 01533 while (p->chan && ast_channel_trylock(p->chan)) { 01534 DEADLOCK_AVOIDANCE(&p->lock); 01535 } 01536 if (p->chan) { 01537 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01538 ast_channel_unlock(p->chan); 01539 } 01540 01541 ast_mutex_unlock(&p->lock); 01542 } else 01543 p->deferlogoff = 1; 01544 } 01545 break; 01546 } 01547 } 01548 AST_LIST_UNLOCK(&agents); 01549 01550 return ret; 01551 }
| static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1553 of file chan_agent.c.
References agent_pvt::agent, agent_logoff(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_agent_logoff_cmd(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.
01554 { 01555 int ret; 01556 const char *agent; 01557 01558 switch (cmd) { 01559 case CLI_INIT: 01560 e->command = "agent logoff"; 01561 e->usage = 01562 "Usage: agent logoff <channel> [soft]\n" 01563 " Sets an agent as no longer logged in.\n" 01564 " If 'soft' is specified, do not hangup existing calls.\n"; 01565 return NULL; 01566 case CLI_GENERATE: 01567 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01568 } 01569 01570 if (a->argc < 3 || a->argc > 4) 01571 return CLI_SHOWUSAGE; 01572 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01573 return CLI_SHOWUSAGE; 01574 01575 agent = a->argv[2] + 6; 01576 ret = agent_logoff(agent, a->argc == 4); 01577 if (ret == 0) 01578 ast_cli(a->fd, "Logging out %s\n", agent); 01579 01580 return CLI_SUCCESS; 01581 }
| static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
| int | state, | |||
| const char * | linkedid | |||
| ) | [static, read] |
Create new agent channel.
Definition at line 989 of file chan_agent.c.
References agent_pvt::agent, agent_tech, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_alloc, ast_channel_release(), ast_cond_signal(), AST_CONTROL_UNHOLD, ast_copy_string(), AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.
Referenced by agent_request(), and check_availability().
00990 { 00991 struct ast_channel *tmp; 00992 int alreadylocked; 00993 #if 0 00994 if (!p->chan) { 00995 ast_log(LOG_WARNING, "No channel? :(\n"); 00996 return NULL; 00997 } 00998 #endif 00999 if (p->pending) 01000 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff); 01001 else 01002 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent); 01003 if (!tmp) { 01004 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01005 return NULL; 01006 } 01007 01008 tmp->tech = &agent_tech; 01009 if (p->chan) { 01010 tmp->nativeformats = p->chan->nativeformats; 01011 tmp->writeformat = p->chan->writeformat; 01012 tmp->rawwriteformat = p->chan->writeformat; 01013 tmp->readformat = p->chan->readformat; 01014 tmp->rawreadformat = p->chan->readformat; 01015 ast_string_field_set(tmp, language, p->chan->language); 01016 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01017 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01018 /* XXX Is this really all we copy form the originating channel?? */ 01019 } else { 01020 tmp->nativeformats = AST_FORMAT_SLINEAR; 01021 tmp->writeformat = AST_FORMAT_SLINEAR; 01022 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01023 tmp->readformat = AST_FORMAT_SLINEAR; 01024 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01025 } 01026 /* Safe, agentlock already held */ 01027 tmp->tech_pvt = p; 01028 p->owner = tmp; 01029 tmp->priority = 1; 01030 /* Wake up and wait for other applications (by definition the login app) 01031 * to release this channel). Takes ownership of the agent channel 01032 * to this thread only. 01033 * For signalling the other thread, ast_queue_frame is used until we 01034 * can safely use signals for this purpose. The pselect() needs to be 01035 * implemented in the kernel for this. 01036 */ 01037 p->app_sleep_cond = 0; 01038 01039 alreadylocked = p->app_lock_flag; 01040 p->app_lock_flag = 1; 01041 01042 if (alreadylocked) { 01043 if (p->chan) { 01044 ast_queue_frame(p->chan, &ast_null_frame); 01045 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01046 p->app_lock_flag = 1; 01047 ast_mutex_lock(&p->lock); 01048 } else { 01049 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01050 p->owner = NULL; 01051 tmp->tech_pvt = NULL; 01052 p->app_sleep_cond = 1; 01053 tmp = ast_channel_release(tmp); 01054 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01055 p->app_lock_flag = 0; 01056 ast_cond_signal(&p->app_complete_cond); 01057 return NULL; 01058 } 01059 } 01060 if (p->chan) 01061 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01062 return tmp; 01063 }
| static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 528 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff(), agent_start_monitoring(), AST_AGENT_FD, AST_CONTROL_ANSWER, ast_copy_flags, ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), AST_STATE_UP, AST_TIMING_FD, ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, agent_pvt::enddtmf, f, ast_channel::fdno, ast_frame::frametype, agent_pvt::lock, LOG_NOTICE, ast_channel::name, agent_pvt::name, agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.
00529 { 00530 struct agent_pvt *p = ast->tech_pvt; 00531 struct ast_frame *f = NULL; 00532 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00533 int cur_time = time(NULL); 00534 ast_mutex_lock(&p->lock); 00535 CHECK_FORMATS(ast, p); 00536 if (!p->start) { 00537 p->start = cur_time; 00538 } 00539 if (p->chan) { 00540 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00541 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00542 f = ast_read(p->chan); 00543 } else 00544 f = &ast_null_frame; 00545 if (!f) { 00546 /* If there's a channel, make it NULL */ 00547 if (p->chan) { 00548 p->chan->_bridge = NULL; 00549 p->chan = NULL; 00550 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00551 p->acknowledged = 0; 00552 } 00553 } else { 00554 /* if acknowledgement is not required, and the channel is up, we may have missed 00555 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00556 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00557 p->acknowledged = 1; 00558 } 00559 00560 if (!p->acknowledged) { 00561 int howlong = cur_time - p->start; 00562 if (p->autologoff && (howlong >= p->autologoff)) { 00563 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00564 agent_logoff(p->agent, 0); 00565 } 00566 } 00567 switch (f->frametype) { 00568 case AST_FRAME_CONTROL: 00569 if (f->subclass == AST_CONTROL_ANSWER) { 00570 if (p->ackcall) { 00571 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); 00572 /* Don't pass answer along */ 00573 ast_frfree(f); 00574 f = &ast_null_frame; 00575 } else { 00576 p->acknowledged = 1; 00577 /* Use the builtin answer frame for the 00578 recording start check below. */ 00579 ast_frfree(f); 00580 f = &answer_frame; 00581 } 00582 } 00583 break; 00584 case AST_FRAME_DTMF_BEGIN: 00585 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00586 if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){ 00587 ast_frfree(f); 00588 f = &ast_null_frame; 00589 } 00590 break; 00591 case AST_FRAME_DTMF_END: 00592 if (!p->acknowledged && (f->subclass == p->acceptdtmf)) { 00593 ast_verb(3, "%s acknowledged\n", p->chan->name); 00594 p->acknowledged = 1; 00595 ast_frfree(f); 00596 f = &answer_frame; 00597 } else if (f->subclass == p->enddtmf && endcall) { 00598 /* terminates call */ 00599 ast_frfree(f); 00600 f = NULL; 00601 } 00602 break; 00603 case AST_FRAME_VOICE: 00604 case AST_FRAME_VIDEO: 00605 /* don't pass voice or video until the call is acknowledged */ 00606 if (!p->acknowledged) { 00607 ast_frfree(f); 00608 f = &ast_null_frame; 00609 } 00610 default: 00611 /* pass everything else on through */ 00612 break; 00613 } 00614 } 00615 00616 CLEANUP(ast,p); 00617 if (p->chan && !p->chan->_bridge) { 00618 if (strcasecmp(p->chan->tech->type, "Local")) { 00619 p->chan->_bridge = ast; 00620 if (p->chan) 00621 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00622 } 00623 } 00624 ast_mutex_unlock(&p->lock); 00625 if (recordagentcalls && f == &answer_frame) 00626 agent_start_monitoring(ast,0); 00627 return f; 00628 }
| static struct ast_channel * agent_request | ( | const char * | type, | |
| int | format, | |||
| const struct ast_channel * | requestor, | |||
| void * | data, | |||
| int * | cause | |||
| ) | [static, read] |
Part of the Asterisk PBX interface.
Definition at line 1337 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), AST_STATE_DOWN, ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, ast_channel::linkedid, agent_pvt::lock, LOG_WARNING, agent_pvt::owner, agent_pvt::pending, and s.
01338 { 01339 struct agent_pvt *p; 01340 struct ast_channel *chan = NULL; 01341 char *s; 01342 ast_group_t groupmatch; 01343 int groupoff; 01344 int waitforagent=0; 01345 int hasagent = 0; 01346 struct timeval now; 01347 01348 s = data; 01349 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01350 groupmatch = (1 << groupoff); 01351 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01352 groupmatch = (1 << groupoff); 01353 waitforagent = 1; 01354 } else 01355 groupmatch = 0; 01356 01357 /* Check actual logged in agents first */ 01358 AST_LIST_LOCK(&agents); 01359 AST_LIST_TRAVERSE(&agents, p, list) { 01360 ast_mutex_lock(&p->lock); 01361 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01362 if (p->chan) 01363 hasagent++; 01364 now = ast_tvnow(); 01365 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01366 p->lastdisc = ast_tv(0, 0); 01367 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01368 if (!p->owner && p->chan) { 01369 /* Fixed agent */ 01370 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01371 } 01372 if (chan) { 01373 ast_mutex_unlock(&p->lock); 01374 break; 01375 } 01376 } 01377 } 01378 ast_mutex_unlock(&p->lock); 01379 } 01380 if (!p) { 01381 AST_LIST_TRAVERSE(&agents, p, list) { 01382 ast_mutex_lock(&p->lock); 01383 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01384 if (p->chan) { 01385 hasagent++; 01386 } 01387 now = ast_tvnow(); 01388 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01389 p->lastdisc = ast_tv(0, 0); 01390 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01391 if (!p->owner && p->chan) { 01392 /* Could still get a fixed agent */ 01393 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01394 } 01395 if (chan) { 01396 ast_mutex_unlock(&p->lock); 01397 break; 01398 } 01399 } 01400 } 01401 ast_mutex_unlock(&p->lock); 01402 } 01403 } 01404 01405 if (!chan && waitforagent) { 01406 /* No agent available -- but we're requesting to wait for one. 01407 Allocate a place holder */ 01408 if (hasagent) { 01409 ast_debug(1, "Creating place holder for '%s'\n", s); 01410 p = add_agent(data, 1); 01411 p->group = groupmatch; 01412 chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL); 01413 if (!chan) 01414 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01415 } else { 01416 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01417 } 01418 } 01419 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01420 AST_LIST_UNLOCK(&agents); 01421 return chan; 01422 }
| static int agent_sendhtml | ( | struct ast_channel * | ast, | |
| int | subclass, | |||
| const char * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 630 of file chan_agent.c.
References ast_channel_sendhtml(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00631 { 00632 struct agent_pvt *p = ast->tech_pvt; 00633 int res = -1; 00634 ast_mutex_lock(&p->lock); 00635 if (p->chan) 00636 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00637 ast_mutex_unlock(&p->lock); 00638 return res; 00639 }
| static int agent_sendtext | ( | struct ast_channel * | ast, | |
| const char * | text | |||
| ) | [static] |
Definition at line 641 of file chan_agent.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_sendtext(), agent_pvt::chan, agent_pvt::lock, and ast_channel::tech_pvt.
00642 { 00643 struct agent_pvt *p = ast->tech_pvt; 00644 int res = -1; 00645 ast_mutex_lock(&p->lock); 00646 if (p->chan) 00647 res = ast_sendtext(p->chan, text); 00648 ast_mutex_unlock(&p->lock); 00649 return res; 00650 }
| int agent_set_base_channel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | base | |||
| ) | [static] |
Definition at line 814 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.
00815 { 00816 struct agent_pvt *p = NULL; 00817 00818 if (!chan || !base) { 00819 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00820 return -1; 00821 } 00822 p = chan->tech_pvt; 00823 if (!p) { 00824 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00825 return -1; 00826 } 00827 p->chan = base; 00828 return 0; 00829 }
| static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
| int | needlock | |||
| ) | [static] |
Definition at line 523 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00524 { 00525 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00526 }
| static int agent_write | ( | struct ast_channel * | ast, | |
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 652 of file chan_agent.c.
References ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock(), ast_mutex_unlock(), ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame::frametype, agent_pvt::lock, ast_channel::name, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.
00653 { 00654 struct agent_pvt *p = ast->tech_pvt; 00655 int res = -1; 00656 CHECK_FORMATS(ast, p); 00657 ast_mutex_lock(&p->lock); 00658 if (!p->chan) 00659 res = 0; 00660 else { 00661 if ((f->frametype != AST_FRAME_VOICE) || 00662 (f->frametype != AST_FRAME_VIDEO) || 00663 (f->subclass == p->chan->writeformat)) { 00664 res = ast_write(p->chan, f); 00665 } else { 00666 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00667 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00668 ast->name, p->chan->name); 00669 res = 0; 00670 } 00671 } 00672 CLEANUP(ast, p); 00673 ast_mutex_unlock(&p->lock); 00674 return res; 00675 }
| static int agentmonitoroutgoing_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Called by the AgentMonitorOutgoing application (from the dial plan).
| chan | ||
| data |
Definition at line 2117 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, GETAGENTBYCALLERID, LOG_WARNING, and pbx_builtin_getvar_helper().
Referenced by load_module().
02118 { 02119 int exitifnoagentid = 0; 02120 int nowarnings = 0; 02121 int changeoutgoing = 0; 02122 int res = 0; 02123 char agent[AST_MAX_AGENT]; 02124 02125 if (data) { 02126 if (strchr(data, 'd')) 02127 exitifnoagentid = 1; 02128 if (strchr(data, 'n')) 02129 nowarnings = 1; 02130 if (strchr(data, 'c')) 02131 changeoutgoing = 1; 02132 } 02133 if (chan->cid.cid_num) { 02134 const char *tmp; 02135 char agentvar[AST_MAX_BUF]; 02136 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02137 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02138 struct agent_pvt *p; 02139 ast_copy_string(agent, tmp, sizeof(agent)); 02140 AST_LIST_LOCK(&agents); 02141 AST_LIST_TRAVERSE(&agents, p, list) { 02142 if (!strcasecmp(p->agent, tmp)) { 02143 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02144 __agent_start_monitoring(chan, p, 1); 02145 break; 02146 } 02147 } 02148 AST_LIST_UNLOCK(&agents); 02149 02150 } else { 02151 res = -1; 02152 if (!nowarnings) 02153 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); 02154 } 02155 } else { 02156 res = -1; 02157 if (!nowarnings) 02158 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"); 02159 } 02160 if (res) { 02161 if (exitifnoagentid) 02162 return res; 02163 } 02164 return 0; 02165 }
| static char* agents_show | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Show agents in cli.
< Number of agents configured
< Number of online agents
< Number of offline agents
Definition at line 1640 of file chan_agent.c.
References agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::group, agent_pvt::lock, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.
01641 { 01642 struct agent_pvt *p; 01643 char username[AST_MAX_BUF]; 01644 char location[AST_MAX_BUF] = ""; 01645 char talkingto[AST_MAX_BUF] = ""; 01646 char music[AST_MAX_BUF]; 01647 int count_agents = 0; /*!< Number of agents configured */ 01648 int online_agents = 0; /*!< Number of online agents */ 01649 int offline_agents = 0; /*!< Number of offline agents */ 01650 01651 switch (cmd) { 01652 case CLI_INIT: 01653 e->command = "agent show"; 01654 e->usage = 01655 "Usage: agent show\n" 01656 " Provides summary information on agents.\n"; 01657 return NULL; 01658 case CLI_GENERATE: 01659 return NULL; 01660 } 01661 01662 if (a->argc != 2) 01663 return CLI_SHOWUSAGE; 01664 01665 AST_LIST_LOCK(&agents); 01666 AST_LIST_TRAVERSE(&agents, p, list) { 01667 ast_mutex_lock(&p->lock); 01668 if (p->pending) { 01669 if (p->group) 01670 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01671 else 01672 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01673 } else { 01674 if (!ast_strlen_zero(p->name)) 01675 snprintf(username, sizeof(username), "(%s) ", p->name); 01676 else 01677 username[0] = '\0'; 01678 if (p->chan) { 01679 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01680 if (p->owner && ast_bridged_channel(p->owner)) 01681 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01682 else 01683 strcpy(talkingto, " is idle"); 01684 online_agents++; 01685 } else { 01686 strcpy(location, "not logged in"); 01687 talkingto[0] = '\0'; 01688 offline_agents++; 01689 } 01690 if (!ast_strlen_zero(p->moh)) 01691 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01692 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01693 username, location, talkingto, music); 01694 count_agents++; 01695 } 01696 ast_mutex_unlock(&p->lock); 01697 } 01698 AST_LIST_UNLOCK(&agents); 01699 if ( !count_agents ) 01700 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01701 else 01702 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01703 ast_cli(a->fd, "\n"); 01704 01705 return CLI_SUCCESS; 01706 }
| static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1709 of file chan_agent.c.
References agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::lock, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.
01710 { 01711 struct agent_pvt *p; 01712 char username[AST_MAX_BUF]; 01713 char location[AST_MAX_BUF] = ""; 01714 char talkingto[AST_MAX_BUF] = ""; 01715 char music[AST_MAX_BUF]; 01716 int count_agents = 0; /* Number of agents configured */ 01717 int online_agents = 0; /* Number of online agents */ 01718 int agent_status = 0; /* 0 means offline, 1 means online */ 01719 01720 switch (cmd) { 01721 case CLI_INIT: 01722 e->command = "agent show online"; 01723 e->usage = 01724 "Usage: agent show online\n" 01725 " Provides a list of all online agents.\n"; 01726 return NULL; 01727 case CLI_GENERATE: 01728 return NULL; 01729 } 01730 01731 if (a->argc != 3) 01732 return CLI_SHOWUSAGE; 01733 01734 AST_LIST_LOCK(&agents); 01735 AST_LIST_TRAVERSE(&agents, p, list) { 01736 agent_status = 0; /* reset it to offline */ 01737 ast_mutex_lock(&p->lock); 01738 if (!ast_strlen_zero(p->name)) 01739 snprintf(username, sizeof(username), "(%s) ", p->name); 01740 else 01741 username[0] = '\0'; 01742 if (p->chan) { 01743 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01744 if (p->owner && ast_bridged_channel(p->owner)) 01745 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01746 else 01747 strcpy(talkingto, " is idle"); 01748 agent_status = 1; 01749 online_agents++; 01750 } 01751 if (!ast_strlen_zero(p->moh)) 01752 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01753 if (agent_status) 01754 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01755 count_agents++; 01756 ast_mutex_unlock(&p->lock); 01757 } 01758 AST_LIST_UNLOCK(&agents); 01759 if (!count_agents) 01760 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01761 else 01762 ast_cli(a->fd, "%d agents online\n", online_agents); 01763 ast_cli(a->fd, "\n"); 01764 return CLI_SUCCESS; 01765 }
| static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
| int | needlock | |||
| ) | [static] |
Definition at line 1235 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), ast_copy_string(), ast_debug, AST_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, ast_channel::language, ast_channel::linkedid, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01236 { 01237 struct ast_channel *chan=NULL, *parent=NULL; 01238 struct agent_pvt *p; 01239 int res; 01240 01241 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01242 if (needlock) 01243 AST_LIST_LOCK(&agents); 01244 AST_LIST_TRAVERSE(&agents, p, list) { 01245 if (p == newlyavailable) { 01246 continue; 01247 } 01248 ast_mutex_lock(&p->lock); 01249 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01250 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01251 /* We found a pending call, time to merge */ 01252 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL); 01253 parent = p->owner; 01254 p->abouttograb = 1; 01255 ast_mutex_unlock(&p->lock); 01256 break; 01257 } 01258 ast_mutex_unlock(&p->lock); 01259 } 01260 if (needlock) 01261 AST_LIST_UNLOCK(&agents); 01262 if (parent && chan) { 01263 if (newlyavailable->ackcall) { 01264 /* Don't do beep here */ 01265 res = 0; 01266 } else { 01267 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01268 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01269 ast_debug(3, "Played beep, result '%d'\n", res); 01270 if (!res) { 01271 res = ast_waitstream(newlyavailable->chan, ""); 01272 ast_debug(1, "Waited for stream, result '%d'\n", res); 01273 } 01274 } 01275 if (!res) { 01276 /* Note -- parent may have disappeared */ 01277 if (p->abouttograb) { 01278 newlyavailable->acknowledged = 1; 01279 /* Safe -- agent lock already held */ 01280 ast_setstate(parent, AST_STATE_UP); 01281 ast_setstate(chan, AST_STATE_UP); 01282 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01283 /* Go ahead and mark the channel as a zombie so that masquerade will 01284 destroy it for us, and we need not call ast_hangup */ 01285 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01286 ast_channel_masquerade(parent, chan); 01287 p->abouttograb = 0; 01288 } else { 01289 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01290 agent_cleanup(newlyavailable); 01291 } 01292 } else { 01293 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01294 agent_cleanup(newlyavailable); 01295 } 01296 } 01297 return 0; 01298 }
| static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
| int | needlock | |||
| ) | [static] |
Definition at line 1300 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::agent, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, ast_channel::language, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01301 { 01302 struct agent_pvt *p; 01303 int res=0; 01304 01305 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01306 if (needlock) 01307 AST_LIST_LOCK(&agents); 01308 AST_LIST_TRAVERSE(&agents, p, list) { 01309 if (p == newlyavailable) { 01310 continue; 01311 } 01312 ast_mutex_lock(&p->lock); 01313 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01314 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01315 ast_mutex_unlock(&p->lock); 01316 break; 01317 } 01318 ast_mutex_unlock(&p->lock); 01319 } 01320 if (needlock) 01321 AST_LIST_UNLOCK(&agents); 01322 if (p) { 01323 ast_mutex_unlock(&newlyavailable->lock); 01324 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01325 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01326 ast_debug(1, "Played beep, result '%d'\n", res); 01327 if (!res) { 01328 res = ast_waitstream(newlyavailable->chan, ""); 01329 ast_debug(1, "Waited for stream, result '%d'\n", res); 01330 } 01331 ast_mutex_lock(&newlyavailable->lock); 01332 } 01333 return res; 01334 }
| static char * complete_agent_logoff_cmd | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 1613 of file chan_agent.c.
References agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_AGENT, ast_strdup, len(), agent_pvt::loginstart, and agent_pvt::name.
Referenced by agent_logoff_cmd().
01614 { 01615 char *ret = NULL; 01616 01617 if (pos == 2) { 01618 struct agent_pvt *p; 01619 char name[AST_MAX_AGENT]; 01620 int which = 0, len = strlen(word); 01621 01622 AST_LIST_LOCK(&agents); 01623 AST_LIST_TRAVERSE(&agents, p, list) { 01624 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01625 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01626 ret = ast_strdup(name); 01627 break; 01628 } 01629 } 01630 AST_LIST_UNLOCK(&agents); 01631 } else if (pos == 3 && state == 0) 01632 return ast_strdup("soft"); 01633 01634 return ret; 01635 }
| static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static, read] |
Definition at line 2215 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02216 { 02217 struct agent_pvt *cur; 02218 02219 AST_LIST_TRAVERSE(&agents, cur, list) { 02220 if (!strcmp(cur->agent, agentid)) 02221 break; 02222 } 02223 02224 return cur; 02225 }
| static int function_agent | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 2227 of file chan_agent.c.
References agent_pvt::agent, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::chan, find_agent(), LOG_WARNING, agent_pvt::moh, ast_channel::name, agent_pvt::name, parse(), agent_pvt::password, and status.
02228 { 02229 char *parse; 02230 AST_DECLARE_APP_ARGS(args, 02231 AST_APP_ARG(agentid); 02232 AST_APP_ARG(item); 02233 ); 02234 char *tmp; 02235 struct agent_pvt *agent; 02236 02237 buf[0] = '\0'; 02238 02239 if (ast_strlen_zero(data)) { 02240 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02241 return -1; 02242 } 02243 02244 parse = ast_strdupa(data); 02245 02246 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02247 if (!args.item) 02248 args.item = "status"; 02249 02250 AST_LIST_LOCK(&agents); 02251 02252 if (!(agent = find_agent(args.agentid))) { 02253 AST_LIST_UNLOCK(&agents); 02254 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02255 return -1; 02256 } 02257 02258 if (!strcasecmp(args.item, "status")) { 02259 char *status = "LOGGEDOUT"; 02260 if (agent->chan) { 02261 status = "LOGGEDIN"; 02262 } 02263 ast_copy_string(buf, status, len); 02264 } else if (!strcasecmp(args.item, "password")) 02265 ast_copy_string(buf, agent->password, len); 02266 else if (!strcasecmp(args.item, "name")) 02267 ast_copy_string(buf, agent->name, len); 02268 else if (!strcasecmp(args.item, "mohclass")) 02269 ast_copy_string(buf, agent->moh, len); 02270 else if (!strcasecmp(args.item, "channel")) { 02271 if (agent->chan) { 02272 ast_copy_string(buf, agent->chan->name, len); 02273 tmp = strrchr(buf, '-'); 02274 if (tmp) 02275 *tmp = '\0'; 02276 } 02277 } else if (!strcasecmp(args.item, "exten")) { 02278 buf[0] = '\0'; 02279 } 02280 02281 AST_LIST_UNLOCK(&agents); 02282 02283 return 0; 02284 }
| static int load_module | ( | void | ) | [static] |
Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.
Definition at line 2299 of file chan_agent.c.
References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), and read_agent_config().
02300 { 02301 /* Make sure we can register our agent channel type */ 02302 if (ast_channel_register(&agent_tech)) { 02303 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02304 return AST_MODULE_LOAD_FAILURE; 02305 } 02306 /* Read in the config */ 02307 if (!read_agent_config(0)) 02308 return AST_MODULE_LOAD_DECLINE; 02309 /* Dialplan applications */ 02310 ast_register_application_xml(app, login_exec); 02311 ast_register_application_xml(app3, agentmonitoroutgoing_exec); 02312 02313 /* Manager commands */ 02314 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents); 02315 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff); 02316 02317 /* CLI Commands */ 02318 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02319 02320 /* Dialplan Functions */ 02321 ast_custom_function_register(&agent_function); 02322 02323 return AST_MODULE_LOAD_SUCCESS; 02324 }
| static int login_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Log in agent application.
Called by the AgentLogin application (from the dial plan).
| chan | ||
| data |
Definition at line 1788 of file chan_agent.c.
References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_wait(), AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::name, ast_channel::nativeformats, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, ast_channel::readformat, S_OR, ast_channel::uniqueid, update_cdr, agent_pvt::wrapuptime, and ast_channel::writeformat.
Referenced by load_module().
01789 { 01790 int res=0; 01791 int tries = 0; 01792 int max_login_tries = maxlogintries; 01793 struct agent_pvt *p; 01794 struct ast_module_user *u; 01795 int login_state = 0; 01796 char user[AST_MAX_AGENT] = ""; 01797 char pass[AST_MAX_AGENT]; 01798 char agent[AST_MAX_AGENT] = ""; 01799 char xpass[AST_MAX_AGENT] = ""; 01800 char *errmsg; 01801 char *parse; 01802 AST_DECLARE_APP_ARGS(args, 01803 AST_APP_ARG(agent_id); 01804 AST_APP_ARG(options); 01805 AST_APP_ARG(extension); 01806 ); 01807 const char *tmpoptions = NULL; 01808 int play_announcement = 1; 01809 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01810 int update_cdr = updatecdr; 01811 char *filename = "agent-loginok"; 01812 01813 u = ast_module_user_add(chan); 01814 01815 parse = ast_strdupa(data); 01816 01817 AST_STANDARD_APP_ARGS(args, parse); 01818 01819 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01820 01821 ast_channel_lock(chan); 01822 /* Set Channel Specific Login Overrides */ 01823 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01824 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01825 if (max_login_tries < 0) 01826 max_login_tries = 0; 01827 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01828 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 01829 } 01830 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01831 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01832 update_cdr = 1; 01833 else 01834 update_cdr = 0; 01835 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01836 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 01837 } 01838 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01839 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01840 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01841 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 01842 } 01843 ast_channel_unlock(chan); 01844 /* End Channel Specific Login Overrides */ 01845 01846 if (!ast_strlen_zero(args.options)) { 01847 if (strchr(args.options, 's')) { 01848 play_announcement = 0; 01849 } 01850 } 01851 01852 if (chan->_state != AST_STATE_UP) 01853 res = ast_answer(chan); 01854 if (!res) { 01855 if (!ast_strlen_zero(args.agent_id)) 01856 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01857 else 01858 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 01859 } 01860 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 01861 tries++; 01862 /* Check for password */ 01863 AST_LIST_LOCK(&agents); 01864 AST_LIST_TRAVERSE(&agents, p, list) { 01865 if (!strcmp(p->agent, user) && !p->pending) 01866 ast_copy_string(xpass, p->password, sizeof(xpass)); 01867 } 01868 AST_LIST_UNLOCK(&agents); 01869 if (!res) { 01870 if (!ast_strlen_zero(xpass)) 01871 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 01872 else 01873 pass[0] = '\0'; 01874 } 01875 errmsg = "agent-incorrect"; 01876 01877 #if 0 01878 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 01879 #endif 01880 01881 /* Check again for accuracy */ 01882 AST_LIST_LOCK(&agents); 01883 AST_LIST_TRAVERSE(&agents, p, list) { 01884 int unlock_channel = 1; 01885 ast_channel_lock(chan); 01886 ast_mutex_lock(&p->lock); 01887 if (!strcmp(p->agent, user) && 01888 !strcmp(p->password, pass) && !p->pending) { 01889 login_state = 1; /* Successful Login */ 01890 01891 /* Ensure we can't be gotten until we're done */ 01892 p->lastdisc = ast_tvnow(); 01893 p->lastdisc.tv_sec++; 01894 01895 /* Set Channel Specific Agent Overrides */ 01896 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01897 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 01898 p->ackcall = 1; 01899 } else { 01900 p->ackcall = 0; 01901 } 01902 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 01903 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 01904 ast_set_flag(p, AGENT_FLAG_ACKCALL); 01905 } else { 01906 p->ackcall = ackcall; 01907 } 01908 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 01909 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 01910 if (p->autologoff < 0) 01911 p->autologoff = 0; 01912 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 01913 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 01914 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 01915 } else { 01916 p->autologoff = autologoff; 01917 } 01918 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 01919 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 01920 if (p->wrapuptime < 0) 01921 p->wrapuptime = 0; 01922 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 01923 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 01924 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 01925 } else { 01926 p->wrapuptime = wrapuptime; 01927 } 01928 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF"); 01929 if (!ast_strlen_zero(tmpoptions)) { 01930 p->acceptdtmf = *tmpoptions; 01931 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 01932 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 01933 } 01934 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 01935 if (!ast_strlen_zero(tmpoptions)) { 01936 p->enddtmf = *tmpoptions; 01937 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 01938 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 01939 } 01940 ast_channel_unlock(chan); 01941 unlock_channel = 0; 01942 /* End Channel Specific Agent Overrides */ 01943 if (!p->chan) { 01944 long logintime; 01945 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01946 01947 p->logincallerid[0] = '\0'; 01948 p->acknowledged = 0; 01949 01950 ast_mutex_unlock(&p->lock); 01951 AST_LIST_UNLOCK(&agents); 01952 if( !res && play_announcement==1 ) 01953 res = ast_streamfile(chan, filename, chan->language); 01954 if (!res) 01955 ast_waitstream(chan, ""); 01956 AST_LIST_LOCK(&agents); 01957 ast_mutex_lock(&p->lock); 01958 if (!res) { 01959 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 01960 if (res) 01961 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 01962 } 01963 if (!res) { 01964 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 01965 if (res) 01966 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 01967 } 01968 /* Check once more just in case */ 01969 if (p->chan) 01970 res = -1; 01971 if (!res) { 01972 ast_indicate_data(chan, AST_CONTROL_HOLD, 01973 S_OR(p->moh, NULL), 01974 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 01975 if (p->loginstart == 0) 01976 time(&p->loginstart); 01977 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 01978 "Agent: %s\r\n" 01979 "Channel: %s\r\n" 01980 "Uniqueid: %s\r\n", 01981 p->agent, chan->name, chan->uniqueid); 01982 if (update_cdr && chan->cdr) 01983 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 01984 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 01985 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 01986 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 01987 /* Login this channel and wait for it to go away */ 01988 p->chan = chan; 01989 if (p->ackcall) { 01990 check_beep(p, 0); 01991 } else { 01992 check_availability(p, 0); 01993 } 01994 ast_mutex_unlock(&p->lock); 01995 AST_LIST_UNLOCK(&agents); 01996 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 01997 while (res >= 0) { 01998 ast_mutex_lock(&p->lock); 01999 if (p->deferlogoff && p->chan) { 02000 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02001 p->deferlogoff = 0; 02002 } 02003 if (p->chan != chan) 02004 res = -1; 02005 ast_mutex_unlock(&p->lock); 02006 /* Yield here so other interested threads can kick in. */ 02007 sched_yield(); 02008 if (res) 02009 break; 02010 02011 AST_LIST_LOCK(&agents); 02012 ast_mutex_lock(&p->lock); 02013 if (p->lastdisc.tv_sec) { 02014 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02015 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02016 p->lastdisc = ast_tv(0, 0); 02017 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02018 if (p->ackcall) { 02019 check_beep(p, 0); 02020 } else { 02021 check_availability(p, 0); 02022 } 02023 } 02024 } 02025 ast_mutex_unlock(&p->lock); 02026 AST_LIST_UNLOCK(&agents); 02027 /* Synchronize channel ownership between call to agent and itself. */ 02028 ast_mutex_lock(&p->app_lock); 02029 if (p->app_lock_flag == 1) { 02030 ast_cond_wait(&p->app_complete_cond, &p->app_lock); 02031 } 02032 ast_mutex_unlock(&p->app_lock); 02033 ast_mutex_lock(&p->lock); 02034 ast_mutex_unlock(&p->lock); 02035 if (p->ackcall) { 02036 res = agent_ack_sleep(p); 02037 } else { 02038 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02039 } 02040 if (p->ackcall && (res == 1)) { 02041 AST_LIST_LOCK(&agents); 02042 ast_mutex_lock(&p->lock); 02043 check_availability(p, 0); 02044 ast_mutex_unlock(&p->lock); 02045 AST_LIST_UNLOCK(&agents); 02046 res = 0; 02047 } 02048 sched_yield(); 02049 } 02050 ast_mutex_lock(&p->lock); 02051 if (res && p->owner) 02052 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02053 /* Log us off if appropriate */ 02054 if (p->chan == chan) { 02055 p->chan = NULL; 02056 } 02057 p->acknowledged = 0; 02058 logintime = time(NULL) - p->loginstart; 02059 p->loginstart = 0; 02060 ast_mutex_unlock(&p->lock); 02061 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02062 "Agent: %s\r\n" 02063 "Logintime: %ld\r\n" 02064 "Uniqueid: %s\r\n", 02065 p->agent, logintime, chan->uniqueid); 02066 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02067 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02068 /* If there is no owner, go ahead and kill it now */ 02069 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02070 if (p->dead && !p->owner) { 02071 ast_mutex_destroy(&p->lock); 02072 ast_mutex_destroy(&p->app_lock); 02073 ast_cond_destroy(&p->app_complete_cond); 02074 ast_free(p); 02075 } 02076 } 02077 else { 02078 ast_mutex_unlock(&p->lock); 02079 p = NULL; 02080 } 02081 res = -1; 02082 } else { 02083 ast_mutex_unlock(&p->lock); 02084 errmsg = "agent-alreadyon"; 02085 p = NULL; 02086 } 02087 break; 02088 } 02089 ast_mutex_unlock(&p->lock); 02090 if (unlock_channel) { 02091 ast_channel_unlock(chan); 02092 } 02093 } 02094 if (!p) 02095 AST_LIST_UNLOCK(&agents); 02096 02097 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02098 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02099 } 02100 02101 if (!res) 02102 res = ast_safe_sleep(chan, 500); 02103 02104 ast_module_user_remove(u); 02105 02106 return -1; 02107 }
| static force_inline int powerof | ( | unsigned int | d | ) | [static] |
Definition at line 1424 of file chan_agent.c.
Referenced by __ast_register_translator(), agents_show(), ast_translate_available_formats(), ast_translate_path_steps(), and ast_translator_build_path().
| static int read_agent_config | ( | int | reload | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1071 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, agent_pvt::app_lock, ast_category_browse(), ast_cond_destroy(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_get_group(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), agent_pvt::chan, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, agent_pvt::dead, agent_pvt::lock, LOG_ERROR, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01072 { 01073 struct ast_config *cfg; 01074 struct ast_config *ucfg; 01075 struct ast_variable *v; 01076 struct agent_pvt *p; 01077 const char *catname; 01078 const char *hasagent; 01079 int genhasagent; 01080 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01081 01082 group = 0; 01083 autologoff = 0; 01084 wrapuptime = 0; 01085 ackcall = 0; 01086 endcall = 1; 01087 cfg = ast_config_load(config, config_flags); 01088 if (!cfg) { 01089 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01090 return 0; 01091 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 01092 return -1; 01093 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 01094 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config); 01095 return 0; 01096 } 01097 if ((ucfg = ast_config_load("users.conf", config_flags))) { 01098 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { 01099 ucfg = NULL; 01100 } else if (ucfg == CONFIG_STATUS_FILEINVALID) { 01101 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n"); 01102 return 0; 01103 } 01104 } 01105 01106 AST_LIST_LOCK(&agents); 01107 AST_LIST_TRAVERSE(&agents, p, list) { 01108 p->dead = 1; 01109 } 01110 strcpy(moh, "default"); 01111 /* set the default recording values */ 01112 recordagentcalls = 0; 01113 strcpy(recordformat, "wav"); 01114 strcpy(recordformatext, "wav"); 01115 urlprefix[0] = '\0'; 01116 savecallsin[0] = '\0'; 01117 01118 /* Read in [general] section for persistence */ 01119 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01120 01121 /* Read in the [agents] section */ 01122 v = ast_variable_browse(cfg, "agents"); 01123 while(v) { 01124 /* Create the interface list */ 01125 if (!strcasecmp(v->name, "agent")) { 01126 add_agent(v->value, 0); 01127 } else if (!strcasecmp(v->name, "group")) { 01128 group = ast_get_group(v->value); 01129 } else if (!strcasecmp(v->name, "autologoff")) { 01130 autologoff = atoi(v->value); 01131 if (autologoff < 0) 01132 autologoff = 0; 01133 } else if (!strcasecmp(v->name, "ackcall")) { 01134 if (ast_true(v->value) || !strcasecmp(v->value, "always")) { 01135 ackcall = 1; 01136 } 01137 } else if (!strcasecmp(v->name, "endcall")) { 01138 endcall = ast_true(v->value); 01139 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01140 acceptdtmf = *(v->value); 01141 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01142 } else if (!strcasecmp(v->name, "enddtmf")) { 01143 enddtmf = *(v->value); 01144 } else if (!strcasecmp(v->name, "wrapuptime")) { 01145 wrapuptime = atoi(v->value); 01146 if (wrapuptime < 0) 01147 wrapuptime = 0; 01148 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01149 maxlogintries = atoi(v->value); 01150 if (maxlogintries < 0) 01151 maxlogintries = 0; 01152 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01153 strcpy(agentgoodbye,v->value); 01154 } else if (!strcasecmp(v->name, "musiconhold")) { 01155 ast_copy_string(moh, v->value, sizeof(moh)); 01156 } else if (!strcasecmp(v->name, "updatecdr")) { 01157 if (ast_true(v->value)) 01158 updatecdr = 1; 01159 else 01160 updatecdr = 0; 01161 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01162 if (ast_true(v->value)) 01163 autologoffunavail = 1; 01164 else 01165 autologoffunavail = 0; 01166 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01167 recordagentcalls = ast_true(v->value); 01168 } else if (!strcasecmp(v->name, "recordformat")) { 01169 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01170 if (!strcasecmp(v->value, "wav49")) 01171 strcpy(recordformatext, "WAV"); 01172 else 01173 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01174 } else if (!strcasecmp(v->name, "urlprefix")) { 01175 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01176 if (urlprefix[strlen(urlprefix) - 1] != '/') 01177 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01178 } else if (!strcasecmp(v->name, "savecallsin")) { 01179 if (v->value[0] == '/') 01180 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01181 else 01182 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01183 if (savecallsin[strlen(savecallsin) - 1] != '/') 01184 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01185 } else if (!strcasecmp(v->name, "custom_beep")) { 01186 ast_copy_string(beep, v->value, sizeof(beep)); 01187 } 01188 v = v->next; 01189 } 01190 if (ucfg) { 01191 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01192 catname = ast_category_browse(ucfg, NULL); 01193 while(catname) { 01194 if (strcasecmp(catname, "general")) { 01195 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01196 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01197 char tmp[256]; 01198 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01199 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01200 if (!fullname) 01201 fullname = ""; 01202 if (!secret) 01203 secret = ""; 01204 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01205 add_agent(tmp, 0); 01206 } 01207 } 01208 catname = ast_category_browse(ucfg, catname); 01209 } 01210 ast_config_destroy(ucfg); 01211 } 01212 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01213 if (p->dead) { 01214 AST_LIST_REMOVE_CURRENT(list); 01215 /* Destroy if appropriate */ 01216 if (!p->owner) { 01217 if (!p->chan) { 01218 ast_mutex_destroy(&p->lock); 01219 ast_mutex_destroy(&p->app_lock); 01220 ast_cond_destroy(&p->app_complete_cond); 01221 ast_free(p); 01222 } else { 01223 /* Cause them to hang up */ 01224 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01225 } 01226 } 01227 } 01228 } 01229 AST_LIST_TRAVERSE_SAFE_END; 01230 AST_LIST_UNLOCK(&agents); 01231 ast_config_destroy(cfg); 01232 return 1; 01233 }
| static int reload | ( | void | ) | [static] |
Definition at line 2326 of file chan_agent.c.
References read_agent_config().
02327 { 02328 return read_agent_config(1); 02329 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 2331 of file chan_agent.c.
References agent_function, agent_tech, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), cli_agents, and agent_pvt::owner.
02332 { 02333 struct agent_pvt *p; 02334 /* First, take us out of the channel loop */ 02335 ast_channel_unregister(&agent_tech); 02336 /* Unregister dialplan functions */ 02337 ast_custom_function_unregister(&agent_function); 02338 /* Unregister CLI commands */ 02339 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02340 /* Unregister dialplan applications */ 02341 ast_unregister_application(app); 02342 ast_unregister_application(app3); 02343 /* Unregister manager command */ 02344 ast_manager_unregister("Agents"); 02345 ast_manager_unregister("AgentLogoff"); 02346 /* Unregister channel */ 02347 AST_LIST_LOCK(&agents); 02348 /* Hangup all interfaces if they have an owner */ 02349 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02350 if (p->owner) 02351 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02352 ast_free(p); 02353 } 02354 AST_LIST_UNLOCK(&agents); 02355 return 0; 02356 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 2362 of file chan_agent.c.
char acceptdtmf = DEFAULT_ACCEPTDTMF [static] |
int ackcall [static] |
Definition at line 218 of file chan_agent.c.
struct ast_custom_function agent_function [static] |
Initial value:
{
.name = "AGENT",
.read = function_agent,
}
Definition at line 2286 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char agent_logoff_usage[] [static] |
Initial value:
"Usage: agent logoff <channel> [soft]\n" " Sets an agent as no longer logged in.\n" " If 'soft' is specified, do not hangup existing calls.\n"
Definition at line 1767 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 333 of file chan_agent.c.
Referenced by agent_new(), load_module(), and unload_module().
char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye" [static] |
Definition at line 226 of file chan_agent.c.
const char app[] = "AgentLogin" [static] |
Definition at line 200 of file chan_agent.c.
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 201 of file chan_agent.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2362 of file chan_agent.c.
int autologoff [static] |
Definition at line 216 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 221 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 234 of file chan_agent.c.
struct ast_cli_entry cli_agents[] [static] |
Initial value:
{
AST_CLI_DEFINE(agents_show, "Show status of agents"),
AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
}
Definition at line 1772 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char config[] = "agents.conf" [static] |
Definition at line 198 of file chan_agent.c.
int endcall [static] |
Definition at line 219 of file chan_agent.c.
char enddtmf = DEFAULT_ENDDTMF [static] |
Definition at line 223 of file chan_agent.c.
ast_group_t group [static] |
Definition at line 215 of file chan_agent.c.
int maxlogintries = 3 [static] |
Definition at line 225 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 203 of file chan_agent.c.
Referenced by dial_exec_full(), get_mohbyname(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().
int multiplelogin = 1 [static] |
Definition at line 220 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 209 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 228 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 229 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 230 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 232 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 197 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 233 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
int wrapuptime [static] |
Definition at line 217 of file chan_agent.c.
1.5.6