#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"
#include "asterisk/data.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 | DATA_EXPORT_AGENT(MEMBER) |
| #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, const char *dest, int timeout) |
| static int | agent_cleanup (struct agent_pvt *p) |
| static int | agent_cont_sleep (void *data) |
| static int | agent_devicestate (const char *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 struct ast_channel * | agent_lock_owner (struct agent_pvt *pvt) |
| Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed. | |
| 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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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 int | agents_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root) |
| 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) |
| AST_DATA_STRUCTURE (agent_pvt, DATA_EXPORT_AGENT) | |
| 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_LOAD_ORDER , .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, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } |
| 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 struct ast_data_handler | agents_data_provider |
| static struct ast_data_entry | agents_data_providers [] |
| 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 211 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().
| #define AST_MAX_BUF 256 |
Definition at line 212 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 321 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
| #define DATA_EXPORT_AGENT | ( | MEMBER | ) |
Definition at line 284 of file chan_agent.c.
| #define DEFAULT_ACCEPTDTMF '#' |
Definition at line 218 of file chan_agent.c.
| #define DEFAULT_ENDDTMF '*' |
Definition at line 219 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 216 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 244 of file chan_agent.c.
00244 { 00245 AGENT_FLAG_ACKCALL = (1 << 0), 00246 AGENT_FLAG_AUTOLOGOFF = (1 << 1), 00247 AGENT_FLAG_WRAPUPTIME = (1 << 2), 00248 AGENT_FLAG_ACCEPTDTMF = (1 << 3), 00249 AGENT_FLAG_ENDDTMF = (1 << 4), 00250 };
| static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
| struct agent_pvt * | p, | |||
| int | needlock | |||
| ) | [static] |
Definition at line 554 of file chan_agent.c.
References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_channel_uniqueid(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose, ast_channel::cdr, LOG_ERROR, ast_channel::monitor, X_REC_IN, and X_REC_OUT.
Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().
00555 { 00556 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00557 char filename[AST_MAX_BUF]; 00558 int res = -1; 00559 if (!p) 00560 return -1; 00561 if (!ast->monitor) { 00562 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast_channel_uniqueid(ast)); 00563 /* substitute . for - */ 00564 if ((pointer = strchr(filename, '.'))) 00565 *pointer = '-'; 00566 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00567 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT); 00568 ast_monitor_setjoinfiles(ast, 1); 00569 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00570 #if 0 00571 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00572 #endif 00573 if (!ast->cdr) 00574 ast->cdr = ast_cdr_alloc(); 00575 ast_cdr_setuserfield(ast, tmp2); 00576 res = 0; 00577 } else 00578 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00579 return res; 00580 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2625 of file chan_agent.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2625 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 1714 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().
01715 { 01716 const char *agent = astman_get_header(m, "Agent"); 01717 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01718 int soft; 01719 int ret; /* return value of agent_logoff */ 01720 01721 if (ast_strlen_zero(agent)) { 01722 astman_send_error(s, m, "No agent specified"); 01723 return 0; 01724 } 01725 01726 soft = ast_true(soft_s) ? 1 : 0; 01727 ret = agent_logoff(agent, soft); 01728 if (ret == 0) 01729 astman_send_ack(s, m, "Agent logged out"); 01730 else 01731 astman_send_error(s, m, "No such agent"); 01732 01733 return 0; 01734 }
| 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. This function locks both the pvt and the channel that owns it for a while, but does not keep these locks.
| s | ||
| m |
Definition at line 1555 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::agent, agent_lock_owner(), ast_bridged_channel(), ast_channel_name(), ast_channel_unlock, ast_channel_unref, 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(), ast_channel::bridge, ast_channel::caller, agent_pvt::chan, ast_party_caller::id, agent_pvt::lock, agent_pvt::loginstart, agent_pvt::name, ast_party_id::number, agent_pvt::owner, S_COR, S_OR, status, ast_party_number::str, and ast_party_number::valid.
Referenced by load_module().
01556 { 01557 const char *id = astman_get_header(m,"ActionID"); 01558 char idText[256] = ""; 01559 struct agent_pvt *p; 01560 char *username = NULL; 01561 char *loginChan = NULL; 01562 char *talkingto = NULL; 01563 char *talkingtoChan = NULL; 01564 char *status = NULL; 01565 struct ast_channel *bridge; 01566 01567 if (!ast_strlen_zero(id)) 01568 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01569 astman_send_ack(s, m, "Agents will follow"); 01570 AST_LIST_LOCK(&agents); 01571 AST_LIST_TRAVERSE(&agents, p, list) { 01572 struct ast_channel *owner; 01573 ast_mutex_lock(&p->lock); 01574 owner = agent_lock_owner(p); 01575 01576 /* Status Values: 01577 AGENT_LOGGEDOFF - Agent isn't logged in 01578 AGENT_IDLE - Agent is logged in, and waiting for call 01579 AGENT_ONCALL - Agent is logged in, and on a call 01580 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01581 01582 username = S_OR(p->name, "None"); 01583 01584 /* Set a default status. It 'should' get changed. */ 01585 status = "AGENT_UNKNOWN"; 01586 01587 if (p->chan) { 01588 loginChan = ast_strdupa(ast_channel_name(p->chan)); 01589 if (owner && owner->_bridge) { 01590 talkingto = S_COR(p->chan->caller.id.number.valid, 01591 p->chan->caller.id.number.str, "n/a"); 01592 if ((bridge = ast_bridged_channel(owner))) { 01593 talkingtoChan = ast_strdupa(ast_channel_name(bridge)); 01594 } else { 01595 talkingtoChan = "n/a"; 01596 } 01597 status = "AGENT_ONCALL"; 01598 } else { 01599 talkingto = "n/a"; 01600 talkingtoChan = "n/a"; 01601 status = "AGENT_IDLE"; 01602 } 01603 } else { 01604 loginChan = "n/a"; 01605 talkingto = "n/a"; 01606 talkingtoChan = "n/a"; 01607 status = "AGENT_LOGGEDOFF"; 01608 } 01609 01610 if (owner) { 01611 ast_channel_unlock(owner); 01612 owner = ast_channel_unref(owner); 01613 } 01614 01615 astman_append(s, "Event: Agents\r\n" 01616 "Agent: %s\r\n" 01617 "Name: %s\r\n" 01618 "Status: %s\r\n" 01619 "LoggedInChan: %s\r\n" 01620 "LoggedInTime: %d\r\n" 01621 "TalkingTo: %s\r\n" 01622 "TalkingToChan: %s\r\n" 01623 "%s" 01624 "\r\n", 01625 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01626 ast_mutex_unlock(&p->lock); 01627 } 01628 AST_LIST_UNLOCK(&agents); 01629 astman_append(s, "Event: AgentsComplete\r\n" 01630 "%s" 01631 "\r\n",idText); 01632 return 0; 01633 }
| 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 421 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_flag, agent_pvt::app_sleep_cond, args, 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::login_wait_cond, 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().
00422 { 00423 char *parse; 00424 AST_DECLARE_APP_ARGS(args, 00425 AST_APP_ARG(agt); 00426 AST_APP_ARG(password); 00427 AST_APP_ARG(name); 00428 ); 00429 char *password = NULL; 00430 char *name = NULL; 00431 char *agt = NULL; 00432 struct agent_pvt *p; 00433 00434 parse = ast_strdupa(agent); 00435 00436 /* Extract username (agt), password and name from agent (args). */ 00437 AST_STANDARD_APP_ARGS(args, parse); 00438 00439 if(args.argc == 0) { 00440 ast_log(LOG_WARNING, "A blank agent line!\n"); 00441 return NULL; 00442 } 00443 00444 if(ast_strlen_zero(args.agt) ) { 00445 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00446 return NULL; 00447 } else 00448 agt = args.agt; 00449 00450 if(!ast_strlen_zero(args.password)) { 00451 password = args.password; 00452 while (*password && *password < 33) password++; 00453 } 00454 if(!ast_strlen_zero(args.name)) { 00455 name = args.name; 00456 while (*name && *name < 33) name++; 00457 } 00458 00459 /* Are we searching for the agent here ? To see if it exists already ? */ 00460 AST_LIST_TRAVERSE(&agents, p, list) { 00461 if (!pending && !strcmp(p->agent, agt)) 00462 break; 00463 } 00464 if (!p) { 00465 // Build the agent. 00466 if (!(p = ast_calloc(1, sizeof(*p)))) 00467 return NULL; 00468 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00469 ast_mutex_init(&p->lock); 00470 ast_cond_init(&p->app_complete_cond, NULL); 00471 ast_cond_init(&p->login_wait_cond, NULL); 00472 p->app_lock_flag = 0; 00473 p->app_sleep_cond = 1; 00474 p->group = group; 00475 p->pending = pending; 00476 AST_LIST_INSERT_TAIL(&agents, p, list); 00477 } 00478 00479 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00480 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00481 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00482 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) { 00483 p->ackcall = ackcall; 00484 } 00485 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) { 00486 p->autologoff = autologoff; 00487 } 00488 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) { 00489 p->acceptdtmf = acceptdtmf; 00490 } 00491 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) { 00492 p->enddtmf = enddtmf; 00493 } 00494 00495 /* If someone reduces the wrapuptime and reloads, we want it 00496 * to change the wrapuptime immediately on all calls */ 00497 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) { 00498 struct timeval now = ast_tvnow(); 00499 /* XXX check what is this exactly */ 00500 00501 /* We won't be pedantic and check the tv_usec val */ 00502 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00503 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00504 p->lastdisc.tv_usec = now.tv_usec; 00505 } 00506 } 00507 p->wrapuptime = wrapuptime; 00508 00509 if (pending) 00510 p->dead = 1; 00511 else 00512 p->dead = 0; 00513 return p; 00514 }
| static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 1038 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, ast_frame_subclass::integer, agent_pvt::lock, and ast_frame::subclass.
Referenced by login_exec().
01039 { 01040 struct agent_pvt *p; 01041 int res=0; 01042 int to = 1000; 01043 struct ast_frame *f; 01044 01045 /* Wait a second and look for something */ 01046 01047 p = (struct agent_pvt *) data; 01048 if (!p->chan) 01049 return -1; 01050 01051 for(;;) { 01052 to = ast_waitfor(p->chan, to); 01053 if (to < 0) 01054 return -1; 01055 if (!to) 01056 return 0; 01057 f = ast_read(p->chan); 01058 if (!f) 01059 return -1; 01060 if (f->frametype == AST_FRAME_DTMF) 01061 res = f->subclass.integer; 01062 else 01063 res = 0; 01064 ast_frfree(f); 01065 ast_mutex_lock(&p->lock); 01066 if (!p->app_sleep_cond) { 01067 ast_mutex_unlock(&p->lock); 01068 return 0; 01069 } else if (res == p->acceptdtmf) { 01070 ast_mutex_unlock(&p->lock); 01071 return 1; 01072 } 01073 ast_mutex_unlock(&p->lock); 01074 res = 0; 01075 } 01076 return res; 01077 }
| static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 548 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00549 { 00550 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00551 return -1; 00552 }
| static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | bridge | |||
| ) | [static, read] |
Definition at line 1079 of file chan_agent.c.
References ast_channel::_bridge, ast_channel_name(), ast_debug, agent_pvt::chan, and ast_channel::tech_pvt.
01080 { 01081 struct agent_pvt *p = bridge->tech_pvt; 01082 struct ast_channel *ret = NULL; 01083 01084 if (p) { 01085 if (chan == p->chan) 01086 ret = bridge->_bridge; 01087 else if (chan == bridge->_bridge) 01088 ret = p->chan; 01089 } 01090 01091 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", ast_channel_name(chan), ast_channel_name(bridge), ret ? ast_channel_name(ret) : "<none>"); 01092 return ret; 01093 }
| static int agent_call | ( | struct ast_channel * | ast, | |
| const char * | dest, | |||
| int | timeout | |||
| ) | [static] |
Definition at line 819 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_channel_language(), ast_channel_name(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set_read_format_from_cap(), ast_set_write_format_from_cap(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_verb, ast_waitstream(), agent_pvt::chan, CLEANUP, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.
00820 { 00821 struct agent_pvt *p = ast->tech_pvt; 00822 int res = -1; 00823 int newstate=0; 00824 struct ast_channel *chan; 00825 00826 ast_mutex_lock(&p->lock); 00827 p->acknowledged = 0; 00828 00829 if (p->pending) { 00830 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n"); 00831 ast_mutex_unlock(&p->lock); 00832 ast_setstate(ast, AST_STATE_DIALING); 00833 return 0; 00834 } 00835 00836 if (!p->chan) { 00837 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 00838 ast_mutex_unlock(&p->lock); 00839 return res; 00840 } 00841 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, ast_channel_name(p->chan)); 00842 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(p->chan)); 00843 00844 chan = p->chan; 00845 ast_mutex_unlock(&p->lock); 00846 00847 res = ast_streamfile(chan, beep, ast_channel_language(chan)); 00848 ast_debug(3, "Played beep, result '%d'\n", res); 00849 if (!res) { 00850 res = ast_waitstream(chan, ""); 00851 ast_debug(3, "Waited for stream, result '%d'\n", res); 00852 } 00853 00854 ast_mutex_lock(&p->lock); 00855 if (!p->chan) { 00856 /* chan went away while we were streaming, this shouldn't be possible */ 00857 res = -1; 00858 } 00859 00860 if (!res) { 00861 struct ast_format tmpfmt; 00862 res = ast_set_read_format_from_cap(p->chan, p->chan->nativeformats); 00863 ast_debug(3, "Set read format, result '%d'\n", res); 00864 if (res) 00865 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt)); 00866 } else { 00867 /* Agent hung-up */ 00868 p->chan = NULL; 00869 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00870 } 00871 00872 if (!res) { 00873 struct ast_format tmpfmt; 00874 res = ast_set_write_format_from_cap(p->chan, p->chan->nativeformats); 00875 ast_debug(3, "Set write format, result '%d'\n", res); 00876 if (res) 00877 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt)); 00878 } 00879 if(!res) { 00880 /* Call is immediately up, or might need ack */ 00881 if (p->ackcall) { 00882 newstate = AST_STATE_RINGING; 00883 } else { 00884 newstate = AST_STATE_UP; 00885 if (recordagentcalls) 00886 agent_start_monitoring(ast, 0); 00887 p->acknowledged = 1; 00888 } 00889 res = 0; 00890 } 00891 CLEANUP(ast, p); 00892 ast_mutex_unlock(&p->lock); 00893 if (newstate) 00894 ast_setstate(ast, newstate); 00895 return res; 00896 }
| 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 522 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_release(), ast_cond_destroy, ast_cond_signal, ast_free, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::login_wait_cond, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00523 { 00524 struct ast_channel *chan = NULL; 00525 ast_mutex_lock(&p->lock); 00526 chan = p->owner; 00527 p->owner = NULL; 00528 chan->tech_pvt = NULL; 00529 /* Release ownership of the agent to other threads (presumably running the login app). */ 00530 p->app_sleep_cond = 1; 00531 p->app_lock_flag = 0; 00532 ast_cond_signal(&p->app_complete_cond); 00533 if (chan) { 00534 chan = ast_channel_release(chan); 00535 } 00536 if (p->dead) { 00537 ast_mutex_unlock(&p->lock); 00538 ast_mutex_destroy(&p->lock); 00539 ast_cond_destroy(&p->app_complete_cond); 00540 ast_cond_destroy(&p->login_wait_cond); 00541 ast_free(p); 00542 } 00543 return 0; 00544 }
| static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 1017 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().
01018 { 01019 struct agent_pvt *p; 01020 int res; 01021 01022 p = (struct agent_pvt *)data; 01023 01024 ast_mutex_lock(&p->lock); 01025 res = p->app_sleep_cond; 01026 if (p->lastdisc.tv_sec) { 01027 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 01028 res = 1; 01029 } 01030 ast_mutex_unlock(&p->lock); 01031 01032 if (!res) 01033 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 01034 01035 return res; 01036 }
| static int agent_devicestate | ( | const char * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2322 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, and agent_pvt::pending.
02323 { 02324 struct agent_pvt *p; 02325 const char *s; 02326 ast_group_t groupmatch; 02327 int groupoff; 02328 int res = AST_DEVICE_INVALID; 02329 02330 s = data; 02331 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) 02332 groupmatch = (1 << groupoff); 02333 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02334 groupmatch = (1 << groupoff); 02335 } else 02336 groupmatch = 0; 02337 02338 /* Check actual logged in agents first */ 02339 AST_LIST_LOCK(&agents); 02340 AST_LIST_TRAVERSE(&agents, p, list) { 02341 ast_mutex_lock(&p->lock); 02342 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02343 if (p->owner) { 02344 if (res != AST_DEVICE_INUSE) 02345 res = AST_DEVICE_BUSY; 02346 } else { 02347 if (res == AST_DEVICE_BUSY) 02348 res = AST_DEVICE_INUSE; 02349 if (p->chan) { 02350 if (res == AST_DEVICE_INVALID) 02351 res = AST_DEVICE_UNKNOWN; 02352 } else if (res == AST_DEVICE_INVALID) 02353 res = AST_DEVICE_UNAVAILABLE; 02354 } 02355 if (!strcmp(data, p->agent)) { 02356 ast_mutex_unlock(&p->lock); 02357 break; 02358 } 02359 } 02360 ast_mutex_unlock(&p->lock); 02361 } 02362 AST_LIST_UNLOCK(&agents); 02363 return res; 02364 }
| static int agent_digit_begin | ( | struct ast_channel * | ast, | |
| char | digit | |||
| ) | [static] |
Definition at line 797 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.
00798 { 00799 struct agent_pvt *p = ast->tech_pvt; 00800 ast_mutex_lock(&p->lock); 00801 if (p->chan) { 00802 ast_senddigit_begin(p->chan, digit); 00803 } 00804 ast_mutex_unlock(&p->lock); 00805 return 0; 00806 }
| static int agent_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 808 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.
00809 { 00810 struct agent_pvt *p = ast->tech_pvt; 00811 ast_mutex_lock(&p->lock); 00812 if (p->chan) { 00813 ast_senddigit_end(p->chan, digit, duration); 00814 } 00815 ast_mutex_unlock(&p->lock); 00816 return 0; 00817 }
| static int agent_fixup | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
Definition at line 759 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.
00760 { 00761 struct agent_pvt *p = newchan->tech_pvt; 00762 ast_mutex_lock(&p->lock); 00763 if (p->owner != oldchan) { 00764 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00765 ast_mutex_unlock(&p->lock); 00766 return -1; 00767 } 00768 p->owner = newchan; 00769 ast_mutex_unlock(&p->lock); 00770 return 0; 00771 }
| 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 899 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00900 { 00901 struct agent_pvt *p = NULL; 00902 struct ast_channel *base = chan; 00903 00904 /* chan is locked by the calling function */ 00905 if (!chan || !chan->tech_pvt) { 00906 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); 00907 return NULL; 00908 } 00909 p = chan->tech_pvt; 00910 if (p->chan) 00911 base = p->chan; 00912 return base; 00913 }
| static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 932 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_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, 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_UP, ast_strdupa, ast_strlen_zero(), ast_tvadd(), ast_tvnow(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::login_wait_cond, 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.
Referenced by agent_request().
00933 { 00934 struct agent_pvt *p = ast->tech_pvt; 00935 struct ast_channel *indicate_chan = NULL; 00936 char *tmp_moh; /* moh buffer for indicating after unlocking p */ 00937 00938 if (p->pending) { 00939 AST_LIST_LOCK(&agents); 00940 AST_LIST_REMOVE(&agents, p, list); 00941 AST_LIST_UNLOCK(&agents); 00942 } 00943 00944 ast_mutex_lock(&p->lock); 00945 p->owner = NULL; 00946 ast->tech_pvt = NULL; 00947 p->app_sleep_cond = 1; 00948 p->acknowledged = 0; 00949 00950 /* Release ownership of the agent to other threads (presumably running the login app). */ 00951 p->app_lock_flag = 0; 00952 ast_cond_signal(&p->app_complete_cond); 00953 00954 /* if they really are hung up then set start to 0 so the test 00955 * later if we're called on an already downed channel 00956 * doesn't cause an agent to be logged out like when 00957 * agent_request() is followed immediately by agent_hangup() 00958 * as in apps/app_chanisavail.c:chanavail_exec() 00959 */ 00960 00961 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00962 if (p->start && (ast->_state != AST_STATE_UP)) { 00963 p->start = 0; 00964 } else 00965 p->start = 0; 00966 if (p->chan) { 00967 p->chan->_bridge = NULL; 00968 /* If they're dead, go ahead and hang up on the agent now */ 00969 if (p->dead) { 00970 ast_channel_lock(p->chan); 00971 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00972 ast_channel_unlock(p->chan); 00973 } else if (p->loginstart) { 00974 indicate_chan = ast_channel_ref(p->chan); 00975 tmp_moh = ast_strdupa(p->moh); 00976 } 00977 } 00978 ast_mutex_unlock(&p->lock); 00979 00980 if (indicate_chan) { 00981 ast_channel_lock(indicate_chan); 00982 ast_indicate_data(indicate_chan, AST_CONTROL_HOLD, 00983 S_OR(tmp_moh, NULL), 00984 !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0); 00985 ast_channel_unlock(indicate_chan); 00986 indicate_chan = ast_channel_unref(indicate_chan); 00987 } 00988 00989 /* Only register a device state change if the agent is still logged in */ 00990 if (!p->loginstart) { 00991 p->logincallerid[0] = '\0'; 00992 } else { 00993 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00994 } 00995 00996 if (p->abouttograb) { 00997 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00998 kill it later */ 00999 p->abouttograb = 0; 01000 } else if (p->dead) { 01001 ast_mutex_destroy(&p->lock); 01002 ast_cond_destroy(&p->app_complete_cond); 01003 ast_cond_destroy(&p->login_wait_cond); 01004 ast_free(p); 01005 } else { 01006 if (p->chan) { 01007 /* Not dead -- check availability now */ 01008 ast_mutex_lock(&p->lock); 01009 /* Store last disconnect time */ 01010 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 01011 ast_mutex_unlock(&p->lock); 01012 } 01013 } 01014 return 0; 01015 }
| static int agent_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 773 of file chan_agent.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_log(), ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, LOG_ERROR, ast_channel::tech, and ast_channel::tech_pvt.
00774 { 00775 struct agent_pvt *p = ast->tech_pvt; 00776 int res = -1; 00777 ast_mutex_lock(&p->lock); 00778 if (p->chan && !ast_check_hangup(p->chan)) { 00779 while (ast_channel_trylock(p->chan)) { 00780 int res; 00781 if ((res = ast_channel_unlock(ast))) { 00782 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res)); 00783 ast_mutex_unlock(&p->lock); 00784 return -1; 00785 } 00786 usleep(1); 00787 ast_channel_lock(ast); 00788 } 00789 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00790 ast_channel_unlock(p->chan); 00791 } else 00792 res = 0; 00793 ast_mutex_unlock(&p->lock); 00794 return res; 00795 }
| static struct ast_channel* agent_lock_owner | ( | struct agent_pvt * | pvt | ) | [static, read] |
Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed.
| pvt | Pointer to the LOCKED agent_pvt for which the owner is needed locked channel which owns the pvt at the time of completion. NULL if not available. |
Definition at line 386 of file chan_agent.c.
References ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, ast_mutex_lock, ast_mutex_unlock, agent_pvt::lock, and agent_pvt::owner.
Referenced by action_agents(), agent_logoff(), agent_read(), agents_data_provider_get(), agents_show(), and agents_show_online().
00387 { 00388 struct ast_channel *owner; 00389 00390 for (;;) { 00391 if (!pvt->owner) { /* No owner. Nothing to do. */ 00392 return NULL; 00393 } 00394 00395 /* If we don't ref the owner, it could be killed when we unlock the pvt. */ 00396 owner = ast_channel_ref(pvt->owner); 00397 00398 /* Locking order requires us to lock channel, then pvt. */ 00399 ast_mutex_unlock(&pvt->lock); 00400 ast_channel_lock(owner); 00401 ast_mutex_lock(&pvt->lock); 00402 00403 /* Check if owner changed during pvt unlock period */ 00404 if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */ 00405 ast_channel_unlock(owner); 00406 owner = ast_channel_unref(owner); 00407 } else { /* Channel stayed the same. Return it. */ 00408 return owner; 00409 } 00410 } 00411 }
| static int agent_logoff | ( | const char * | agent, | |
| int | soft | |||
| ) | [static] |
Definition at line 1635 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_channel_trylock, ast_channel_unlock, ast_channel_unref, 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(), and agent_logoff_cmd().
01636 { 01637 struct agent_pvt *p; 01638 int ret = -1; /* Return -1 if no agent if found */ 01639 01640 AST_LIST_LOCK(&agents); 01641 AST_LIST_TRAVERSE(&agents, p, list) { 01642 if (!strcasecmp(p->agent, agent)) { 01643 ret = 0; 01644 if (p->owner || p->chan) { 01645 if (!soft) { 01646 struct ast_channel *owner; 01647 ast_mutex_lock(&p->lock); 01648 owner = agent_lock_owner(p); 01649 01650 if (owner) { 01651 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT); 01652 ast_channel_unlock(owner); 01653 owner = ast_channel_unref(owner); 01654 } 01655 01656 while (p->chan && ast_channel_trylock(p->chan)) { 01657 DEADLOCK_AVOIDANCE(&p->lock); 01658 } 01659 if (p->chan) { 01660 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01661 ast_channel_unlock(p->chan); 01662 } 01663 01664 ast_mutex_unlock(&p->lock); 01665 } else 01666 p->deferlogoff = 1; 01667 } 01668 break; 01669 } 01670 } 01671 AST_LIST_UNLOCK(&agents); 01672 01673 return ret; 01674 }
| static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1676 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.
01677 { 01678 int ret; 01679 const char *agent; 01680 01681 switch (cmd) { 01682 case CLI_INIT: 01683 e->command = "agent logoff"; 01684 e->usage = 01685 "Usage: agent logoff <channel> [soft]\n" 01686 " Sets an agent as no longer logged in.\n" 01687 " If 'soft' is specified, do not hangup existing calls.\n"; 01688 return NULL; 01689 case CLI_GENERATE: 01690 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01691 } 01692 01693 if (a->argc < 3 || a->argc > 4) 01694 return CLI_SHOWUSAGE; 01695 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01696 return CLI_SHOWUSAGE; 01697 01698 agent = a->argv[2] + 6; 01699 ret = agent_logoff(agent, a->argc == 4); 01700 if (ret == 0) 01701 ast_cli(a->fd, "Logging out %s\n", agent); 01702 01703 return CLI_SUCCESS; 01704 }
| static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
| int | state, | |||
| const char * | linkedid | |||
| ) | [static, read] |
Create new agent channel.
Definition at line 1096 of file chan_agent.c.
References agent_pvt::agent, agent_tech, ast_channel_alloc, ast_channel_language(), ast_copy_string(), ast_format_cap_add(), ast_format_cap_copy(), ast_format_copy(), ast_format_set(), AST_FORMAT_SLINEAR, ast_log(), ast_random(), agent_pvt::chan, ast_channel::context, ast_channel::exten, 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().
01097 { 01098 struct ast_channel *tmp; 01099 #if 0 01100 if (!p->chan) { 01101 ast_log(LOG_WARNING, "No channel? :(\n"); 01102 return NULL; 01103 } 01104 #endif 01105 if (p->pending) 01106 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); 01107 else 01108 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent); 01109 if (!tmp) { 01110 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01111 return NULL; 01112 } 01113 01114 tmp->tech = &agent_tech; 01115 if (p->chan) { 01116 ast_format_cap_copy(tmp->nativeformats, p->chan->nativeformats); 01117 ast_format_copy(&tmp->writeformat, &p->chan->writeformat); 01118 ast_format_copy(&tmp->rawwriteformat, &p->chan->writeformat); 01119 ast_format_copy(&tmp->readformat, &p->chan->readformat); 01120 ast_format_copy(&tmp->rawreadformat, &p->chan->readformat); 01121 ast_channel_language_set(tmp, ast_channel_language(p->chan)); 01122 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01123 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01124 /* XXX Is this really all we copy form the originating channel?? */ 01125 } else { 01126 ast_format_set(&tmp->writeformat, AST_FORMAT_SLINEAR, 0); 01127 ast_format_set(&tmp->rawwriteformat, AST_FORMAT_SLINEAR, 0); 01128 ast_format_set(&tmp->readformat, AST_FORMAT_SLINEAR, 0); 01129 ast_format_set(&tmp->rawreadformat, AST_FORMAT_SLINEAR, 0); 01130 ast_format_cap_add(tmp->nativeformats, &tmp->writeformat); 01131 } 01132 /* Safe, agentlock already held */ 01133 tmp->tech_pvt = p; 01134 p->owner = tmp; 01135 tmp->priority = 1; 01136 return tmp; 01137 }
| static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 587 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_lock_owner(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_name(), ast_channel_trylock, ast_channel_unlock, ast_channel_unref, 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_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, AST_TIMING_FD, ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, agent_pvt::enddtmf, f, ast_channel::fdno, ast_frame::frametype, ast_frame_subclass::integer, agent_pvt::lock, LOG_NOTICE, agent_pvt::name, agent_pvt::owner, agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.
00588 { 00589 struct agent_pvt *p = ast->tech_pvt; 00590 struct ast_frame *f = NULL; 00591 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } }; 00592 int cur_time = time(NULL); 00593 struct ast_channel *owner; 00594 00595 ast_mutex_lock(&p->lock); 00596 owner = agent_lock_owner(p); 00597 00598 CHECK_FORMATS(ast, p); 00599 if (!p->start) { 00600 p->start = cur_time; 00601 } 00602 if (p->chan) { 00603 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00604 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00605 f = ast_read(p->chan); 00606 } else 00607 f = &ast_null_frame; 00608 if (!f) { 00609 /* If there's a channel, make it NULL */ 00610 if (p->chan) { 00611 p->chan->_bridge = NULL; 00612 p->chan = NULL; 00613 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00614 p->acknowledged = 0; 00615 } 00616 } else { 00617 /* if acknowledgement is not required, and the channel is up, we may have missed 00618 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00619 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00620 p->acknowledged = 1; 00621 } 00622 00623 if (!p->acknowledged) { 00624 int howlong = cur_time - p->start; 00625 if (p->autologoff && (howlong >= p->autologoff)) { 00626 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00627 if (owner || p->chan) { 00628 if (owner) { 00629 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT); 00630 ast_channel_unlock(owner); 00631 owner = ast_channel_unref(owner); 00632 } 00633 00634 while (p->chan && ast_channel_trylock(p->chan)) { 00635 DEADLOCK_AVOIDANCE(&p->lock); 00636 } 00637 if (p->chan) { 00638 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00639 ast_channel_unlock(p->chan); 00640 } 00641 } 00642 } 00643 } 00644 switch (f->frametype) { 00645 case AST_FRAME_CONTROL: 00646 if (f->subclass.integer == AST_CONTROL_ANSWER) { 00647 if (p->ackcall) { 00648 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", ast_channel_name(p->chan), p->acceptdtmf); 00649 /* Don't pass answer along */ 00650 ast_frfree(f); 00651 f = &ast_null_frame; 00652 } else { 00653 p->acknowledged = 1; 00654 /* Use the builtin answer frame for the 00655 recording start check below. */ 00656 ast_frfree(f); 00657 f = &answer_frame; 00658 } 00659 } 00660 break; 00661 case AST_FRAME_DTMF_BEGIN: 00662 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00663 if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){ 00664 ast_frfree(f); 00665 f = &ast_null_frame; 00666 } 00667 break; 00668 case AST_FRAME_DTMF_END: 00669 if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) { 00670 ast_verb(3, "%s acknowledged\n", ast_channel_name(p->chan)); 00671 p->acknowledged = 1; 00672 ast_frfree(f); 00673 f = &answer_frame; 00674 } else if (f->subclass.integer == p->enddtmf && endcall) { 00675 /* terminates call */ 00676 ast_frfree(f); 00677 f = NULL; 00678 } 00679 break; 00680 case AST_FRAME_VOICE: 00681 case AST_FRAME_VIDEO: 00682 /* don't pass voice or video until the call is acknowledged */ 00683 if (!p->acknowledged) { 00684 ast_frfree(f); 00685 f = &ast_null_frame; 00686 } 00687 default: 00688 /* pass everything else on through */ 00689 break; 00690 } 00691 } 00692 00693 if (owner) { 00694 ast_channel_unlock(owner); 00695 owner = ast_channel_unref(owner); 00696 } 00697 00698 CLEANUP(ast,p); 00699 if (p->chan && !p->chan->_bridge) { 00700 if (strcasecmp(p->chan->tech->type, "Local")) { 00701 p->chan->_bridge = ast; 00702 if (p->chan) 00703 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", ast_channel_name(p->chan), ast_channel_name(p->chan->_bridge)); 00704 } 00705 } 00706 ast_mutex_unlock(&p->lock); 00707 if (recordagentcalls && f == &answer_frame) 00708 agent_start_monitoring(ast,0); 00709 return f; 00710 }
| static struct ast_channel * agent_request | ( | const char * | type, | |
| struct ast_format_cap * | cap, | |||
| const struct ast_channel * | requestor, | |||
| const char * | data, | |||
| int * | cause | |||
| ) | [static, read] |
Part of the Asterisk PBX interface.
Definition at line 1409 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_hangup(), agent_new(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_channel_linkedid(), ast_cond_signal, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, ast_indicate(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), AST_STATE_DOWN, ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::owner, and agent_pvt::pending.
01410 { 01411 struct agent_pvt *p; 01412 struct ast_channel *chan = NULL; 01413 const char *s; 01414 ast_group_t groupmatch; 01415 int groupoff; 01416 int waitforagent=0; 01417 int hasagent = 0; 01418 struct timeval now; 01419 01420 s = data; 01421 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01422 groupmatch = (1 << groupoff); 01423 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01424 groupmatch = (1 << groupoff); 01425 waitforagent = 1; 01426 } else 01427 groupmatch = 0; 01428 01429 /* Check actual logged in agents first */ 01430 AST_LIST_LOCK(&agents); 01431 AST_LIST_TRAVERSE(&agents, p, list) { 01432 ast_mutex_lock(&p->lock); 01433 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01434 if (p->chan) 01435 hasagent++; 01436 now = ast_tvnow(); 01437 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01438 p->lastdisc = ast_tv(0, 0); 01439 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01440 if (!p->owner && p->chan) { 01441 /* Fixed agent */ 01442 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL); 01443 } 01444 if (chan) { 01445 ast_mutex_unlock(&p->lock); 01446 break; 01447 } 01448 } 01449 } 01450 ast_mutex_unlock(&p->lock); 01451 } 01452 if (!p) { 01453 AST_LIST_TRAVERSE(&agents, p, list) { 01454 ast_mutex_lock(&p->lock); 01455 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01456 if (p->chan) { 01457 hasagent++; 01458 } 01459 now = ast_tvnow(); 01460 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01461 p->lastdisc = ast_tv(0, 0); 01462 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01463 if (!p->owner && p->chan) { 01464 /* Could still get a fixed agent */ 01465 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL); 01466 } 01467 if (chan) { 01468 ast_mutex_unlock(&p->lock); 01469 break; 01470 } 01471 } 01472 } 01473 ast_mutex_unlock(&p->lock); 01474 } 01475 } 01476 01477 if (!chan && waitforagent) { 01478 /* No agent available -- but we're requesting to wait for one. 01479 Allocate a place holder */ 01480 if (hasagent) { 01481 ast_debug(1, "Creating place holder for '%s'\n", s); 01482 p = add_agent(data, 1); 01483 p->group = groupmatch; 01484 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL); 01485 if (!chan) 01486 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01487 } else { 01488 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01489 } 01490 } 01491 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01492 AST_LIST_UNLOCK(&agents); 01493 01494 if (chan) { 01495 ast_mutex_lock(&p->lock); 01496 if (p->pending) { 01497 ast_mutex_unlock(&p->lock); 01498 return chan; 01499 } 01500 01501 if (!p->chan) { 01502 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 01503 *cause = AST_CAUSE_UNREGISTERED; 01504 ast_mutex_unlock(&p->lock); 01505 agent_hangup(chan); 01506 return NULL; 01507 } 01508 01509 /* we need to take control of the channel from the login app 01510 * thread */ 01511 p->app_sleep_cond = 0; 01512 p->app_lock_flag = 1; 01513 01514 ast_queue_frame(p->chan, &ast_null_frame); 01515 ast_cond_wait(&p->login_wait_cond, &p->lock); 01516 01517 if (!p->chan) { 01518 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n"); 01519 p->app_sleep_cond = 1; 01520 p->app_lock_flag = 0; 01521 ast_cond_signal(&p->app_complete_cond); 01522 ast_mutex_unlock(&p->lock); 01523 *cause = AST_CAUSE_UNREGISTERED; 01524 agent_hangup(chan); 01525 return NULL; 01526 } 01527 01528 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01529 ast_mutex_unlock(&p->lock); 01530 } 01531 01532 return chan; 01533 }
| static int agent_sendhtml | ( | struct ast_channel * | ast, | |
| int | subclass, | |||
| const char * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 712 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.
00713 { 00714 struct agent_pvt *p = ast->tech_pvt; 00715 int res = -1; 00716 ast_mutex_lock(&p->lock); 00717 if (p->chan) 00718 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00719 ast_mutex_unlock(&p->lock); 00720 return res; 00721 }
| static int agent_sendtext | ( | struct ast_channel * | ast, | |
| const char * | text | |||
| ) | [static] |
Definition at line 723 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.
00724 { 00725 struct agent_pvt *p = ast->tech_pvt; 00726 int res = -1; 00727 ast_mutex_lock(&p->lock); 00728 if (p->chan) 00729 res = ast_sendtext(p->chan, text); 00730 ast_mutex_unlock(&p->lock); 00731 return res; 00732 }
| int agent_set_base_channel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | base | |||
| ) | [static] |
Definition at line 915 of file chan_agent.c.
References ast_channel_name(), ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00916 { 00917 struct agent_pvt *p = NULL; 00918 00919 if (!chan || !base) { 00920 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00921 return -1; 00922 } 00923 p = chan->tech_pvt; 00924 if (!p) { 00925 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", ast_channel_name(chan)); 00926 return -1; 00927 } 00928 p->chan = base; 00929 return 0; 00930 }
| static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
| int | needlock | |||
| ) | [static] |
Definition at line 582 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00583 { 00584 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00585 }
| static int agent_write | ( | struct ast_channel * | ast, | |
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 734 of file chan_agent.c.
References ast_channel_name(), ast_debug, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock, ast_mutex_unlock, ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame_subclass::format, ast_frame::frametype, agent_pvt::lock, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.
00735 { 00736 struct agent_pvt *p = ast->tech_pvt; 00737 int res = -1; 00738 CHECK_FORMATS(ast, p); 00739 ast_mutex_lock(&p->lock); 00740 if (!p->chan) 00741 res = 0; 00742 else { 00743 if ((f->frametype != AST_FRAME_VOICE) || 00744 (f->frametype != AST_FRAME_VIDEO) || 00745 (ast_format_cmp(&f->subclass.format, &p->chan->writeformat) != AST_FORMAT_CMP_NOT_EQUAL)) { 00746 res = ast_write(p->chan, f); 00747 } else { 00748 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00749 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00750 ast_channel_name(ast), ast_channel_name(p->chan)); 00751 res = 0; 00752 } 00753 } 00754 CLEANUP(ast, p); 00755 ast_mutex_unlock(&p->lock); 00756 return res; 00757 }
| 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 2269 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_strlen_zero(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, GETAGENTBYCALLERID, ast_party_caller::id, LOG_WARNING, ast_party_id::number, pbx_builtin_getvar_helper(), ast_party_number::str, and ast_party_number::valid.
Referenced by load_module().
02270 { 02271 int exitifnoagentid = 0; 02272 int nowarnings = 0; 02273 int changeoutgoing = 0; 02274 int res = 0; 02275 char agent[AST_MAX_AGENT]; 02276 02277 if (data) { 02278 if (strchr(data, 'd')) 02279 exitifnoagentid = 1; 02280 if (strchr(data, 'n')) 02281 nowarnings = 1; 02282 if (strchr(data, 'c')) 02283 changeoutgoing = 1; 02284 } 02285 if (chan->caller.id.number.valid 02286 && !ast_strlen_zero(chan->caller.id.number.str)) { 02287 const char *tmp; 02288 char agentvar[AST_MAX_BUF]; 02289 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, 02290 chan->caller.id.number.str); 02291 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02292 struct agent_pvt *p; 02293 ast_copy_string(agent, tmp, sizeof(agent)); 02294 AST_LIST_LOCK(&agents); 02295 AST_LIST_TRAVERSE(&agents, p, list) { 02296 if (!strcasecmp(p->agent, tmp)) { 02297 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02298 __agent_start_monitoring(chan, p, 1); 02299 break; 02300 } 02301 } 02302 AST_LIST_UNLOCK(&agents); 02303 02304 } else { 02305 res = -1; 02306 if (!nowarnings) 02307 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); 02308 } 02309 } else { 02310 res = -1; 02311 if (!nowarnings) 02312 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"); 02313 } 02314 if (res) { 02315 if (exitifnoagentid) 02316 return res; 02317 } 02318 return 0; 02319 }
| static int agents_data_provider_get | ( | const struct ast_data_search * | search, | |
| struct ast_data * | data_root | |||
| ) | [static] |
Definition at line 2460 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_bridged_channel(), ast_channel_data_add_structure(), ast_channel_unlock, ast_channel_unref, ast_data_add_bool(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::lock, agent_pvt::moh, agent_pvt::owner, and agent_pvt::pending.
02462 { 02463 struct agent_pvt *p; 02464 struct ast_data *data_agent, *data_channel, *data_talkingto; 02465 02466 AST_LIST_LOCK(&agents); 02467 AST_LIST_TRAVERSE(&agents, p, list) { 02468 struct ast_channel *owner; 02469 02470 data_agent = ast_data_add_node(data_root, "agent"); 02471 if (!data_agent) { 02472 continue; 02473 } 02474 02475 ast_mutex_lock(&p->lock); 02476 owner = agent_lock_owner(p); 02477 02478 if (!(p->pending)) { 02479 ast_data_add_str(data_agent, "id", p->agent); 02480 ast_data_add_structure(agent_pvt, data_agent, p); 02481 02482 ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0); 02483 if (p->chan) { 02484 data_channel = ast_data_add_node(data_agent, "loggedon"); 02485 if (!data_channel) { 02486 ast_mutex_unlock(&p->lock); 02487 ast_data_remove_node(data_root, data_agent); 02488 if (owner) { 02489 ast_channel_unlock(owner); 02490 owner = ast_channel_unref(owner); 02491 } 02492 continue; 02493 } 02494 ast_channel_data_add_structure(data_channel, p->chan, 0); 02495 if (owner && ast_bridged_channel(owner)) { 02496 data_talkingto = ast_data_add_node(data_agent, "talkingto"); 02497 if (!data_talkingto) { 02498 ast_mutex_unlock(&p->lock); 02499 ast_data_remove_node(data_root, data_agent); 02500 if (owner) { 02501 ast_channel_unlock(owner); 02502 owner = ast_channel_unref(owner); 02503 } 02504 continue; 02505 } 02506 ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0); 02507 } 02508 } else { 02509 ast_data_add_node(data_agent, "talkingto"); 02510 ast_data_add_node(data_agent, "loggedon"); 02511 } 02512 ast_data_add_str(data_agent, "musiconhold", p->moh); 02513 } 02514 02515 if (owner) { 02516 ast_channel_unlock(owner); 02517 owner = ast_channel_unref(owner); 02518 } 02519 02520 ast_mutex_unlock(&p->lock); 02521 02522 /* if this agent doesn't match remove the added agent. */ 02523 if (!ast_data_search_match(search, data_agent)) { 02524 ast_data_remove_node(data_root, data_agent); 02525 } 02526 } 02527 AST_LIST_UNLOCK(&agents); 02528 02529 return 0; 02530 }
| 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 1763 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_name(), ast_channel_unlock, ast_channel_unref, 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, count_agents(), ast_cli_args::fd, agent_pvt::group, agent_pvt::lock, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.
01764 { 01765 struct agent_pvt *p; 01766 char username[AST_MAX_BUF]; 01767 char location[AST_MAX_BUF] = ""; 01768 char talkingto[AST_MAX_BUF] = ""; 01769 char music[AST_MAX_BUF]; 01770 int count_agents = 0; /*!< Number of agents configured */ 01771 int online_agents = 0; /*!< Number of online agents */ 01772 int offline_agents = 0; /*!< Number of offline agents */ 01773 01774 switch (cmd) { 01775 case CLI_INIT: 01776 e->command = "agent show"; 01777 e->usage = 01778 "Usage: agent show\n" 01779 " Provides summary information on agents.\n"; 01780 return NULL; 01781 case CLI_GENERATE: 01782 return NULL; 01783 } 01784 01785 if (a->argc != 2) 01786 return CLI_SHOWUSAGE; 01787 01788 AST_LIST_LOCK(&agents); 01789 AST_LIST_TRAVERSE(&agents, p, list) { 01790 struct ast_channel *owner; 01791 ast_mutex_lock(&p->lock); 01792 owner = agent_lock_owner(p); 01793 if (p->pending) { 01794 if (p->group) 01795 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01796 else 01797 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01798 } else { 01799 if (!ast_strlen_zero(p->name)) 01800 snprintf(username, sizeof(username), "(%s) ", p->name); 01801 else 01802 username[0] = '\0'; 01803 if (p->chan) { 01804 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan)); 01805 if (owner && ast_bridged_channel(owner)) { 01806 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner))); 01807 } else { 01808 strcpy(talkingto, " is idle"); 01809 } 01810 online_agents++; 01811 } else { 01812 strcpy(location, "not logged in"); 01813 talkingto[0] = '\0'; 01814 offline_agents++; 01815 } 01816 if (!ast_strlen_zero(p->moh)) 01817 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01818 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01819 username, location, talkingto, music); 01820 count_agents++; 01821 } 01822 01823 if (owner) { 01824 ast_channel_unlock(owner); 01825 owner = ast_channel_unref(owner); 01826 } 01827 ast_mutex_unlock(&p->lock); 01828 } 01829 AST_LIST_UNLOCK(&agents); 01830 if ( !count_agents ) 01831 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01832 else 01833 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01834 ast_cli(a->fd, "\n"); 01835 01836 return CLI_SUCCESS; 01837 }
| static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1840 of file chan_agent.c.
References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_name(), ast_channel_unlock, ast_channel_unref, 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, count_agents(), ast_cli_args::fd, agent_pvt::lock, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.
01841 { 01842 struct agent_pvt *p; 01843 char username[AST_MAX_BUF]; 01844 char location[AST_MAX_BUF] = ""; 01845 char talkingto[AST_MAX_BUF] = ""; 01846 char music[AST_MAX_BUF]; 01847 int count_agents = 0; /* Number of agents configured */ 01848 int online_agents = 0; /* Number of online agents */ 01849 int agent_status = 0; /* 0 means offline, 1 means online */ 01850 01851 switch (cmd) { 01852 case CLI_INIT: 01853 e->command = "agent show online"; 01854 e->usage = 01855 "Usage: agent show online\n" 01856 " Provides a list of all online agents.\n"; 01857 return NULL; 01858 case CLI_GENERATE: 01859 return NULL; 01860 } 01861 01862 if (a->argc != 3) 01863 return CLI_SHOWUSAGE; 01864 01865 AST_LIST_LOCK(&agents); 01866 AST_LIST_TRAVERSE(&agents, p, list) { 01867 struct ast_channel *owner; 01868 01869 agent_status = 0; /* reset it to offline */ 01870 ast_mutex_lock(&p->lock); 01871 owner = agent_lock_owner(p); 01872 01873 if (!ast_strlen_zero(p->name)) 01874 snprintf(username, sizeof(username), "(%s) ", p->name); 01875 else 01876 username[0] = '\0'; 01877 if (p->chan) { 01878 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan)); 01879 if (p->owner && ast_bridged_channel(p->owner)) { 01880 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner))); 01881 } else { 01882 strcpy(talkingto, " is idle"); 01883 } 01884 agent_status = 1; 01885 online_agents++; 01886 } 01887 01888 if (owner) { 01889 ast_channel_unlock(owner); 01890 owner = ast_channel_unref(owner); 01891 } 01892 01893 if (!ast_strlen_zero(p->moh)) 01894 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01895 if (agent_status) 01896 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01897 count_agents++; 01898 ast_mutex_unlock(&p->lock); 01899 } 01900 AST_LIST_UNLOCK(&agents); 01901 if (!count_agents) 01902 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01903 else 01904 ast_cli(a->fd, "%d agents online\n", online_agents); 01905 ast_cli(a->fd, "\n"); 01906 return CLI_SUCCESS; 01907 }
| AST_DATA_STRUCTURE | ( | agent_pvt | , | |
| DATA_EXPORT_AGENT | ||||
| ) |
| static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
| int | needlock | |||
| ) | [static] |
Definition at line 1309 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_language(), ast_channel_linkedid(), ast_channel_masquerade(), ast_channel_name(), ast_copy_string(), ast_debug, ast_hangup(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01310 { 01311 struct ast_channel *chan=NULL, *parent=NULL; 01312 struct agent_pvt *p; 01313 int res; 01314 01315 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01316 if (needlock) 01317 AST_LIST_LOCK(&agents); 01318 AST_LIST_TRAVERSE(&agents, p, list) { 01319 if (p == newlyavailable) { 01320 continue; 01321 } 01322 ast_mutex_lock(&p->lock); 01323 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01324 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent); 01325 /* We found a pending call, time to merge */ 01326 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? ast_channel_linkedid(p->owner) : NULL); 01327 parent = p->owner; 01328 p->abouttograb = 1; 01329 ast_mutex_unlock(&p->lock); 01330 break; 01331 } 01332 ast_mutex_unlock(&p->lock); 01333 } 01334 if (needlock) 01335 AST_LIST_UNLOCK(&agents); 01336 if (parent && chan) { 01337 if (newlyavailable->ackcall) { 01338 /* Don't do beep here */ 01339 res = 0; 01340 } else { 01341 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan)); 01342 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan)); 01343 ast_debug(3, "Played beep, result '%d'\n", res); 01344 if (!res) { 01345 res = ast_waitstream(newlyavailable->chan, ""); 01346 ast_debug(1, "Waited for stream, result '%d'\n", res); 01347 } 01348 } 01349 if (!res) { 01350 /* Note -- parent may have disappeared */ 01351 if (p->abouttograb) { 01352 newlyavailable->acknowledged = 1; 01353 /* Safe -- agent lock already held */ 01354 ast_setstate(parent, AST_STATE_UP); 01355 ast_setstate(chan, AST_STATE_UP); 01356 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01357 ast_channel_masquerade(parent, chan); 01358 ast_hangup(chan); 01359 p->abouttograb = 0; 01360 } else { 01361 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01362 agent_cleanup(newlyavailable); 01363 } 01364 } else { 01365 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01366 agent_cleanup(newlyavailable); 01367 } 01368 } 01369 return 0; 01370 }
| static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
| int | needlock | |||
| ) | [static] |
Definition at line 1372 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::agent, ast_channel_language(), ast_channel_name(), 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, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01373 { 01374 struct agent_pvt *p; 01375 int res=0; 01376 01377 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01378 if (needlock) 01379 AST_LIST_LOCK(&agents); 01380 AST_LIST_TRAVERSE(&agents, p, list) { 01381 if (p == newlyavailable) { 01382 continue; 01383 } 01384 ast_mutex_lock(&p->lock); 01385 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01386 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent); 01387 ast_mutex_unlock(&p->lock); 01388 break; 01389 } 01390 ast_mutex_unlock(&p->lock); 01391 } 01392 if (needlock) 01393 AST_LIST_UNLOCK(&agents); 01394 if (p) { 01395 ast_mutex_unlock(&newlyavailable->lock); 01396 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan)); 01397 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan)); 01398 ast_debug(1, "Played beep, result '%d'\n", res); 01399 if (!res) { 01400 res = ast_waitstream(newlyavailable->chan, ""); 01401 ast_debug(1, "Waited for stream, result '%d'\n", res); 01402 } 01403 ast_mutex_lock(&newlyavailable->lock); 01404 } 01405 return res; 01406 }
| static char * complete_agent_logoff_cmd | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 1736 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().
01737 { 01738 char *ret = NULL; 01739 01740 if (pos == 2) { 01741 struct agent_pvt *p; 01742 char name[AST_MAX_AGENT]; 01743 int which = 0, len = strlen(word); 01744 01745 AST_LIST_LOCK(&agents); 01746 AST_LIST_TRAVERSE(&agents, p, list) { 01747 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01748 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01749 ret = ast_strdup(name); 01750 break; 01751 } 01752 } 01753 AST_LIST_UNLOCK(&agents); 01754 } else if (pos == 3 && state == 0) 01755 return ast_strdup("soft"); 01756 01757 return ret; 01758 }
| static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static, read] |
Definition at line 2369 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02370 { 02371 struct agent_pvt *cur; 02372 02373 AST_LIST_TRAVERSE(&agents, cur, list) { 02374 if (!strcmp(cur->agent, agentid)) 02375 break; 02376 } 02377 02378 return cur; 02379 }
| static int function_agent | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 2381 of file chan_agent.c.
References agent_pvt::agent, args, AST_APP_ARG, ast_channel_lock, ast_channel_name(), ast_channel_unlock, 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, agent_pvt::name, parse(), agent_pvt::password, and status.
02382 { 02383 char *parse; 02384 AST_DECLARE_APP_ARGS(args, 02385 AST_APP_ARG(agentid); 02386 AST_APP_ARG(item); 02387 ); 02388 char *tmp; 02389 struct agent_pvt *agent; 02390 02391 buf[0] = '\0'; 02392 02393 if (ast_strlen_zero(data)) { 02394 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02395 return -1; 02396 } 02397 02398 parse = ast_strdupa(data); 02399 02400 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02401 if (!args.item) 02402 args.item = "status"; 02403 02404 AST_LIST_LOCK(&agents); 02405 02406 if (!(agent = find_agent(args.agentid))) { 02407 AST_LIST_UNLOCK(&agents); 02408 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02409 return -1; 02410 } 02411 02412 if (!strcasecmp(args.item, "status")) { 02413 char *status = "LOGGEDOUT"; 02414 if (agent->chan) { 02415 status = "LOGGEDIN"; 02416 } 02417 ast_copy_string(buf, status, len); 02418 } else if (!strcasecmp(args.item, "password")) 02419 ast_copy_string(buf, agent->password, len); 02420 else if (!strcasecmp(args.item, "name")) 02421 ast_copy_string(buf, agent->name, len); 02422 else if (!strcasecmp(args.item, "mohclass")) 02423 ast_copy_string(buf, agent->moh, len); 02424 else if (!strcasecmp(args.item, "channel")) { 02425 if (agent->chan) { 02426 ast_channel_lock(agent->chan); 02427 ast_copy_string(buf, ast_channel_name(agent->chan), len); 02428 ast_channel_unlock(agent->chan); 02429 tmp = strrchr(buf, '-'); 02430 if (tmp) 02431 *tmp = '\0'; 02432 } 02433 } else if (!strcasecmp(args.item, "fullchannel")) { 02434 if (agent->chan) { 02435 ast_channel_lock(agent->chan); 02436 ast_copy_string(buf, ast_channel_name(agent->chan), len); 02437 ast_channel_unlock(agent->chan); 02438 } 02439 } else if (!strcasecmp(args.item, "exten")) { 02440 buf[0] = '\0'; 02441 } 02442 02443 AST_LIST_UNLOCK(&agents); 02444 02445 return 0; 02446 }
| 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 2548 of file chan_agent.c.
References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), agents_data_providers, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_format_cap_add_all(), ast_format_cap_alloc(), ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, ast_channel_tech::capabilities, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), and read_agent_config().
02549 { 02550 if (!(agent_tech.capabilities = ast_format_cap_alloc())) { 02551 ast_log(LOG_ERROR, "ast_format_cap_alloc_nolock fail.\n"); 02552 return AST_MODULE_LOAD_FAILURE; 02553 } 02554 ast_format_cap_add_all(agent_tech.capabilities); 02555 /* Make sure we can register our agent channel type */ 02556 if (ast_channel_register(&agent_tech)) { 02557 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02558 return AST_MODULE_LOAD_FAILURE; 02559 } 02560 /* Read in the config */ 02561 if (!read_agent_config(0)) 02562 return AST_MODULE_LOAD_DECLINE; 02563 /* Dialplan applications */ 02564 ast_register_application_xml(app, login_exec); 02565 ast_register_application_xml(app3, agentmonitoroutgoing_exec); 02566 02567 /* data tree */ 02568 ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers)); 02569 02570 /* Manager commands */ 02571 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents); 02572 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff); 02573 02574 /* CLI Commands */ 02575 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02576 02577 /* Dialplan Functions */ 02578 ast_custom_function_register(&agent_function); 02579 02580 return AST_MODULE_LOAD_SUCCESS; 02581 }
| 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 1930 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_flag, args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, ast_cond_destroy, ast_cond_signal, 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_from_cap(), ast_set_write_format_from_cap(), 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, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::logincallerid, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::nativeformats, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, ast_channel::readformat, S_OR, update_cdr, agent_pvt::wrapuptime, and ast_channel::writeformat.
Referenced by load_module().
01931 { 01932 int res=0; 01933 int tries = 0; 01934 int max_login_tries = maxlogintries; 01935 struct agent_pvt *p; 01936 struct ast_module_user *u; 01937 char user[AST_MAX_AGENT] = ""; 01938 char pass[AST_MAX_AGENT]; 01939 char agent[AST_MAX_AGENT] = ""; 01940 char xpass[AST_MAX_AGENT] = ""; 01941 char *errmsg; 01942 char *parse; 01943 AST_DECLARE_APP_ARGS(args, 01944 AST_APP_ARG(agent_id); 01945 AST_APP_ARG(options); 01946 AST_APP_ARG(extension); 01947 ); 01948 const char *tmpoptions = NULL; 01949 int play_announcement = 1; 01950 char agent_goodbye[AST_MAX_FILENAME_LEN]; 01951 int update_cdr = updatecdr; 01952 char *filename = "agent-loginok"; 01953 01954 u = ast_module_user_add(chan); 01955 01956 parse = ast_strdupa(data); 01957 01958 AST_STANDARD_APP_ARGS(args, parse); 01959 01960 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 01961 01962 ast_channel_lock(chan); 01963 /* Set Channel Specific Login Overrides */ 01964 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 01965 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 01966 if (max_login_tries < 0) 01967 max_login_tries = 0; 01968 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 01969 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,ast_channel_name(chan)); 01970 } 01971 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 01972 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 01973 update_cdr = 1; 01974 else 01975 update_cdr = 0; 01976 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 01977 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,ast_channel_name(chan)); 01978 } 01979 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 01980 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 01981 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 01982 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,ast_channel_name(chan)); 01983 } 01984 ast_channel_unlock(chan); 01985 /* End Channel Specific Login Overrides */ 01986 01987 if (!ast_strlen_zero(args.options)) { 01988 if (strchr(args.options, 's')) { 01989 play_announcement = 0; 01990 } 01991 } 01992 01993 if (chan->_state != AST_STATE_UP) 01994 res = ast_answer(chan); 01995 if (!res) { 01996 if (!ast_strlen_zero(args.agent_id)) 01997 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 01998 else 01999 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 02000 } 02001 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 02002 tries++; 02003 /* Check for password */ 02004 AST_LIST_LOCK(&agents); 02005 AST_LIST_TRAVERSE(&agents, p, list) { 02006 if (!strcmp(p->agent, user) && !p->pending) 02007 ast_copy_string(xpass, p->password, sizeof(xpass)); 02008 } 02009 AST_LIST_UNLOCK(&agents); 02010 if (!res) { 02011 if (!ast_strlen_zero(xpass)) 02012 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 02013 else 02014 pass[0] = '\0'; 02015 } 02016 errmsg = "agent-incorrect"; 02017 02018 #if 0 02019 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 02020 #endif 02021 02022 /* Check again for accuracy */ 02023 AST_LIST_LOCK(&agents); 02024 AST_LIST_TRAVERSE(&agents, p, list) { 02025 int unlock_channel = 1; 02026 ast_channel_lock(chan); 02027 ast_mutex_lock(&p->lock); 02028 if (!strcmp(p->agent, user) && 02029 !strcmp(p->password, pass) && !p->pending) { 02030 02031 /* Ensure we can't be gotten until we're done */ 02032 p->lastdisc = ast_tvnow(); 02033 p->lastdisc.tv_sec++; 02034 02035 /* Set Channel Specific Agent Overrides */ 02036 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02037 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02038 p->ackcall = 1; 02039 } else { 02040 p->ackcall = 0; 02041 } 02042 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02043 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 02044 ast_set_flag(p, AGENT_FLAG_ACKCALL); 02045 } else { 02046 p->ackcall = ackcall; 02047 } 02048 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02049 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02050 if (p->autologoff < 0) 02051 p->autologoff = 0; 02052 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02053 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 02054 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 02055 } else { 02056 p->autologoff = autologoff; 02057 } 02058 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02059 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02060 if (p->wrapuptime < 0) 02061 p->wrapuptime = 0; 02062 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02063 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 02064 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 02065 } else { 02066 p->wrapuptime = wrapuptime; 02067 } 02068 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF"); 02069 if (!ast_strlen_zero(tmpoptions)) { 02070 p->acceptdtmf = *tmpoptions; 02071 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 02072 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 02073 } 02074 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 02075 if (!ast_strlen_zero(tmpoptions)) { 02076 p->enddtmf = *tmpoptions; 02077 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 02078 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 02079 } 02080 ast_channel_unlock(chan); 02081 unlock_channel = 0; 02082 /* End Channel Specific Agent Overrides */ 02083 if (!p->chan) { 02084 long logintime; 02085 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02086 02087 p->logincallerid[0] = '\0'; 02088 p->acknowledged = 0; 02089 02090 ast_mutex_unlock(&p->lock); 02091 AST_LIST_UNLOCK(&agents); 02092 if( !res && play_announcement==1 ) 02093 res = ast_streamfile(chan, filename, ast_channel_language(chan)); 02094 if (!res) 02095 ast_waitstream(chan, ""); 02096 AST_LIST_LOCK(&agents); 02097 ast_mutex_lock(&p->lock); 02098 if (!res) { 02099 struct ast_format tmpfmt; 02100 res = ast_set_read_format_from_cap(chan, chan->nativeformats); 02101 if (res) { 02102 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt)); 02103 } 02104 } 02105 if (!res) { 02106 struct ast_format tmpfmt; 02107 res = ast_set_write_format_from_cap(chan, chan->nativeformats); 02108 if (res) { 02109 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt)); 02110 } 02111 } 02112 /* Check once more just in case */ 02113 if (p->chan) 02114 res = -1; 02115 if (!res) { 02116 ast_indicate_data(chan, AST_CONTROL_HOLD, 02117 S_OR(p->moh, NULL), 02118 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02119 if (p->loginstart == 0) 02120 time(&p->loginstart); 02121 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02122 "Agent: %s\r\n" 02123 "Channel: %s\r\n" 02124 "Uniqueid: %s\r\n", 02125 p->agent, ast_channel_name(chan), ast_channel_uniqueid(chan)); 02126 if (update_cdr && chan->cdr) 02127 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02128 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGIN", "%s", ast_channel_name(chan)); 02129 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 02130 ast_getformatname(&chan->readformat), ast_getformatname(&chan->writeformat)); 02131 /* Login this channel and wait for it to go away */ 02132 p->chan = chan; 02133 if (p->ackcall) { 02134 check_beep(p, 0); 02135 } else { 02136 check_availability(p, 0); 02137 } 02138 ast_mutex_unlock(&p->lock); 02139 AST_LIST_UNLOCK(&agents); 02140 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02141 while (res >= 0) { 02142 ast_mutex_lock(&p->lock); 02143 if (p->deferlogoff && p->chan) { 02144 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02145 p->deferlogoff = 0; 02146 } 02147 if (p->chan != chan) 02148 res = -1; 02149 ast_mutex_unlock(&p->lock); 02150 /* Yield here so other interested threads can kick in. */ 02151 sched_yield(); 02152 if (res) 02153 break; 02154 02155 AST_LIST_LOCK(&agents); 02156 ast_mutex_lock(&p->lock); 02157 if (p->lastdisc.tv_sec) { 02158 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02159 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02160 p->lastdisc = ast_tv(0, 0); 02161 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02162 if (p->ackcall) { 02163 check_beep(p, 0); 02164 } else { 02165 check_availability(p, 0); 02166 } 02167 } 02168 } 02169 ast_mutex_unlock(&p->lock); 02170 AST_LIST_UNLOCK(&agents); 02171 02172 /* Synchronize channel ownership between call to agent and itself. */ 02173 ast_mutex_lock(&p->lock); 02174 if (p->app_lock_flag == 1) { 02175 ast_cond_signal(&p->login_wait_cond); 02176 ast_cond_wait(&p->app_complete_cond, &p->lock); 02177 } 02178 ast_mutex_unlock(&p->lock); 02179 if (p->ackcall) { 02180 res = agent_ack_sleep(p); 02181 } else { 02182 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02183 } 02184 if (p->ackcall && (res == 1)) { 02185 AST_LIST_LOCK(&agents); 02186 ast_mutex_lock(&p->lock); 02187 check_availability(p, 0); 02188 ast_mutex_unlock(&p->lock); 02189 AST_LIST_UNLOCK(&agents); 02190 res = 0; 02191 } 02192 sched_yield(); 02193 } 02194 ast_mutex_lock(&p->lock); 02195 /* Log us off if appropriate */ 02196 if (p->chan == chan) { 02197 p->chan = NULL; 02198 } 02199 02200 /* Synchronize channel ownership between call to agent and itself. */ 02201 if (p->app_lock_flag == 1) { 02202 ast_cond_signal(&p->login_wait_cond); 02203 ast_cond_wait(&p->app_complete_cond, &p->lock); 02204 } 02205 02206 if (res && p->owner) 02207 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02208 02209 p->acknowledged = 0; 02210 logintime = time(NULL) - p->loginstart; 02211 p->loginstart = 0; 02212 ast_mutex_unlock(&p->lock); 02213 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02214 "Agent: %s\r\n" 02215 "Logintime: %ld\r\n" 02216 "Uniqueid: %s\r\n", 02217 p->agent, logintime, ast_channel_uniqueid(chan)); 02218 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime); 02219 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02220 /* If there is no owner, go ahead and kill it now */ 02221 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02222 if (p->dead && !p->owner) { 02223 ast_mutex_destroy(&p->lock); 02224 ast_cond_destroy(&p->app_complete_cond); 02225 ast_cond_destroy(&p->login_wait_cond); 02226 ast_free(p); 02227 } 02228 } 02229 else { 02230 ast_mutex_unlock(&p->lock); 02231 p = NULL; 02232 } 02233 res = -1; 02234 } else { 02235 ast_mutex_unlock(&p->lock); 02236 errmsg = "agent-alreadyon"; 02237 p = NULL; 02238 } 02239 break; 02240 } 02241 ast_mutex_unlock(&p->lock); 02242 if (unlock_channel) { 02243 ast_channel_unlock(chan); 02244 } 02245 } 02246 if (!p) 02247 AST_LIST_UNLOCK(&agents); 02248 02249 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02250 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02251 } 02252 02253 if (!res) 02254 res = ast_safe_sleep(chan, 500); 02255 02256 ast_module_user_remove(u); 02257 02258 return -1; 02259 }
| static force_inline int powerof | ( | unsigned int | d | ) | [static] |
| static int read_agent_config | ( | int | reload | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1145 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, 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, agent_pvt::login_wait_cond, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01146 { 01147 struct ast_config *cfg; 01148 struct ast_config *ucfg; 01149 struct ast_variable *v; 01150 struct agent_pvt *p; 01151 const char *catname; 01152 const char *hasagent; 01153 int genhasagent; 01154 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01155 01156 group = 0; 01157 autologoff = 0; 01158 wrapuptime = 0; 01159 ackcall = 0; 01160 endcall = 1; 01161 cfg = ast_config_load(config, config_flags); 01162 if (!cfg) { 01163 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01164 return 0; 01165 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 01166 return -1; 01167 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 01168 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config); 01169 return 0; 01170 } 01171 if ((ucfg = ast_config_load("users.conf", config_flags))) { 01172 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { 01173 ucfg = NULL; 01174 } else if (ucfg == CONFIG_STATUS_FILEINVALID) { 01175 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n"); 01176 return 0; 01177 } 01178 } 01179 01180 AST_LIST_LOCK(&agents); 01181 AST_LIST_TRAVERSE(&agents, p, list) { 01182 p->dead = 1; 01183 } 01184 strcpy(moh, "default"); 01185 /* set the default recording values */ 01186 recordagentcalls = 0; 01187 strcpy(recordformat, "wav"); 01188 strcpy(recordformatext, "wav"); 01189 urlprefix[0] = '\0'; 01190 savecallsin[0] = '\0'; 01191 01192 /* Read in [general] section for persistence */ 01193 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01194 01195 /* Read in the [agents] section */ 01196 v = ast_variable_browse(cfg, "agents"); 01197 while(v) { 01198 /* Create the interface list */ 01199 if (!strcasecmp(v->name, "agent")) { 01200 add_agent(v->value, 0); 01201 } else if (!strcasecmp(v->name, "group")) { 01202 group = ast_get_group(v->value); 01203 } else if (!strcasecmp(v->name, "autologoff")) { 01204 autologoff = atoi(v->value); 01205 if (autologoff < 0) 01206 autologoff = 0; 01207 } else if (!strcasecmp(v->name, "ackcall")) { 01208 if (ast_true(v->value) || !strcasecmp(v->value, "always")) { 01209 ackcall = 1; 01210 } 01211 } else if (!strcasecmp(v->name, "endcall")) { 01212 endcall = ast_true(v->value); 01213 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01214 acceptdtmf = *(v->value); 01215 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01216 } else if (!strcasecmp(v->name, "enddtmf")) { 01217 enddtmf = *(v->value); 01218 } else if (!strcasecmp(v->name, "wrapuptime")) { 01219 wrapuptime = atoi(v->value); 01220 if (wrapuptime < 0) 01221 wrapuptime = 0; 01222 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01223 maxlogintries = atoi(v->value); 01224 if (maxlogintries < 0) 01225 maxlogintries = 0; 01226 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01227 strcpy(agentgoodbye,v->value); 01228 } else if (!strcasecmp(v->name, "musiconhold")) { 01229 ast_copy_string(moh, v->value, sizeof(moh)); 01230 } else if (!strcasecmp(v->name, "updatecdr")) { 01231 if (ast_true(v->value)) 01232 updatecdr = 1; 01233 else 01234 updatecdr = 0; 01235 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01236 if (ast_true(v->value)) 01237 autologoffunavail = 1; 01238 else 01239 autologoffunavail = 0; 01240 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01241 recordagentcalls = ast_true(v->value); 01242 } else if (!strcasecmp(v->name, "recordformat")) { 01243 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01244 if (!strcasecmp(v->value, "wav49")) 01245 strcpy(recordformatext, "WAV"); 01246 else 01247 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01248 } else if (!strcasecmp(v->name, "urlprefix")) { 01249 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01250 if (urlprefix[strlen(urlprefix) - 1] != '/') 01251 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01252 } else if (!strcasecmp(v->name, "savecallsin")) { 01253 if (v->value[0] == '/') 01254 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01255 else 01256 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01257 if (savecallsin[strlen(savecallsin) - 1] != '/') 01258 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01259 } else if (!strcasecmp(v->name, "custom_beep")) { 01260 ast_copy_string(beep, v->value, sizeof(beep)); 01261 } 01262 v = v->next; 01263 } 01264 if (ucfg) { 01265 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01266 catname = ast_category_browse(ucfg, NULL); 01267 while(catname) { 01268 if (strcasecmp(catname, "general")) { 01269 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01270 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01271 char tmp[256]; 01272 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01273 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01274 if (!fullname) 01275 fullname = ""; 01276 if (!secret) 01277 secret = ""; 01278 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01279 add_agent(tmp, 0); 01280 } 01281 } 01282 catname = ast_category_browse(ucfg, catname); 01283 } 01284 ast_config_destroy(ucfg); 01285 } 01286 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01287 if (p->dead) { 01288 AST_LIST_REMOVE_CURRENT(list); 01289 /* Destroy if appropriate */ 01290 if (!p->owner) { 01291 if (!p->chan) { 01292 ast_mutex_destroy(&p->lock); 01293 ast_cond_destroy(&p->app_complete_cond); 01294 ast_cond_destroy(&p->login_wait_cond); 01295 ast_free(p); 01296 } else { 01297 /* Cause them to hang up */ 01298 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01299 } 01300 } 01301 } 01302 } 01303 AST_LIST_TRAVERSE_SAFE_END; 01304 AST_LIST_UNLOCK(&agents); 01305 ast_config_destroy(cfg); 01306 return 1; 01307 }
| static int reload | ( | void | ) | [static] |
Definition at line 2583 of file chan_agent.c.
References read_agent_config().
02584 { 02585 return read_agent_config(1); 02586 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 2588 of file chan_agent.c.
References agent_function, agent_tech, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_data_unregister, ast_format_cap_destroy(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), ast_channel_tech::capabilities, cli_agents, and agent_pvt::owner.
02589 { 02590 struct agent_pvt *p; 02591 /* First, take us out of the channel loop */ 02592 ast_channel_unregister(&agent_tech); 02593 /* Unregister dialplan functions */ 02594 ast_custom_function_unregister(&agent_function); 02595 /* Unregister CLI commands */ 02596 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02597 /* Unregister dialplan applications */ 02598 ast_unregister_application(app); 02599 ast_unregister_application(app3); 02600 /* Unregister manager command */ 02601 ast_manager_unregister("Agents"); 02602 ast_manager_unregister("AgentLogoff"); 02603 /* Unregister the data tree */ 02604 ast_data_unregister(NULL); 02605 /* Unregister channel */ 02606 AST_LIST_LOCK(&agents); 02607 /* Hangup all interfaces if they have an owner */ 02608 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02609 if (p->owner) 02610 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02611 ast_free(p); 02612 } 02613 AST_LIST_UNLOCK(&agents); 02614 02615 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities); 02616 return 0; 02617 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } [static] |
Definition at line 2625 of file chan_agent.c.
char acceptdtmf = DEFAULT_ACCEPTDTMF [static] |
int ackcall [static] |
Definition at line 224 of file chan_agent.c.
struct ast_custom_function agent_function [static] |
Initial value:
{
.name = "AGENT",
.read = function_agent,
}
Definition at line 2448 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 1909 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 353 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 232 of file chan_agent.c.
struct ast_data_handler agents_data_provider [static] |
Initial value:
{
.version = AST_DATA_HANDLER_VERSION,
.get = agents_data_provider_get
}
Definition at line 2532 of file chan_agent.c.
struct ast_data_entry agents_data_providers[] [static] |
Initial value:
{
AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
}
Definition at line 2537 of file chan_agent.c.
Referenced by load_module().
const char app[] = "AgentLogin" [static] |
Definition at line 206 of file chan_agent.c.
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 207 of file chan_agent.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2625 of file chan_agent.c.
int autologoff [static] |
Definition at line 222 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 227 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 240 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 1914 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char config[] = "agents.conf" [static] |
Definition at line 204 of file chan_agent.c.
int endcall [static] |
Definition at line 225 of file chan_agent.c.
char enddtmf = DEFAULT_ENDDTMF [static] |
Definition at line 229 of file chan_agent.c.
ast_group_t group [static] |
Definition at line 221 of file chan_agent.c.
int maxlogintries = 3 [static] |
Definition at line 231 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 209 of file chan_agent.c.
Referenced by _get_mohbyname(), dial_exec_full(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().
int multiplelogin = 1 [static] |
Definition at line 226 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 215 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 234 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 235 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 236 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 238 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 203 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 239 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
int wrapuptime [static] |
Definition at line 223 of file chan_agent.c.
1.5.6