Implementation of Agents (proxy channel). More...
#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/rtp.h"#include "asterisk/acl.h"#include "asterisk/callerid.h"#include "asterisk/file.h"#include "asterisk/cli.h"#include "asterisk/app.h"#include "asterisk/musiconhold.h"#include "asterisk/manager.h"#include "asterisk/features.h"#include "asterisk/utils.h"#include "asterisk/causes.h"#include "asterisk/astdb.h"#include "asterisk/devicestate.h"#include "asterisk/monitor.h"#include "asterisk/stringfields.h"#include "asterisk/event.h"
Go to the source code of this file.
Data Structures | |
| struct | agent_pvt |
| Structure representing an agent. More... | |
| struct | agents |
Defines | |
| #define | AST_MAX_AGENT 80 |
| #define | AST_MAX_BUF 256 |
| #define | AST_MAX_FILENAME_LEN 256 |
| #define | CHECK_FORMATS(ast, p) |
| #define | CLEANUP(ast, p) |
| Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX. | |
| #define | DEFAULT_ACCEPTDTMF '#' |
| #define | DEFAULT_ENDDTMF '*' |
| #define | GETAGENTBYCALLERID "AGENTBYCALLERID" |
| #define | PA_MAX_LEN 2048 |
Enumerations | |
| enum | { AGENT_FLAG_ACKCALL = (1 << 0), AGENT_FLAG_AUTOLOGOFF = (1 << 1), AGENT_FLAG_WRAPUPTIME = (1 << 2), AGENT_FLAG_ACCEPTDTMF = (1 << 3), AGENT_FLAG_ENDDTMF = (1 << 4) } |
Functions | |
| static int | __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock) |
| static void | __reg_module (void) |
| static void | __unreg_module (void) |
| static int | action_agent_logoff (struct mansession *s, const struct message *m) |
| static int | action_agents (struct mansession *s, const struct message *m) |
| static struct agent_pvt * | add_agent (const char *agent, int pending) |
| static int | agent_ack_sleep (void *data) |
| static int | agent_answer (struct ast_channel *ast) |
| static struct ast_channel * | agent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge) |
| static int | agent_call (struct ast_channel *ast, char *dest, int timeout) |
| static int | agent_cleanup (struct agent_pvt *p) |
| static int | agent_cont_sleep (void *data) |
| static int | agent_devicestate (void *data) |
| Part of PBX channel interface. | |
| static int | agent_digit_begin (struct ast_channel *ast, char digit) |
| static int | agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration) |
| static int | agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan) |
| static struct ast_channel * | agent_get_base_channel (struct ast_channel *chan) |
| return the channel or base channel if one exists. This function assumes the channel it is called on is already locked | |
| static int | agent_hangup (struct ast_channel *ast) |
| static int | agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen) |
| static int | agent_logoff (const char *agent, int soft) |
| static char * | agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static void | agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand) |
| static struct ast_channel * | agent_new (struct agent_pvt *p, int state) |
| Create new agent channel. | |
| static struct ast_frame * | agent_read (struct ast_channel *ast) |
| static struct ast_channel * | agent_request (const char *type, int format, void *data, int *cause) |
| Part of the Asterisk PBX interface. | |
| static int | agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen) |
| static int | agent_sendtext (struct ast_channel *ast, const char *text) |
| static int | agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base) |
| static int | agent_start_monitoring (struct ast_channel *ast, int needlock) |
| static int | agent_write (struct ast_channel *ast, struct ast_frame *f) |
| static int | agentmonitoroutgoing_exec (struct ast_channel *chan, void *data) |
| Called by the AgentMonitorOutgoing application (from the dial plan). | |
| static char * | agents_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static char * | agents_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
| static int | check_availability (struct agent_pvt *newlyavailable, int needlock) |
| static int | check_beep (struct agent_pvt *newlyavailable, int needlock) |
| static char * | complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state) |
| static void | dump_agents (void) |
| Dump AgentCallbackLogin agents to the ASTdb database for persistence. | |
| 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, void *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 void | reload_agents (void) |
| Reload the persistent agents from astdb. | |
| static void | set_agentbycallerid (const char *callerid, const char *agent) |
| store/clear the global variable that stores agentid based on the callerid | |
| static int | unload_module (void) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static char | acceptdtmf = DEFAULT_ACCEPTDTMF |
| static int | ackcall |
| struct ast_custom_function | agent_function |
| static const char | agent_logoff_usage [] |
| static struct ast_channel_tech | agent_tech |
| Channel interface description for PBX integration. | |
| static char | agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye" |
| static const char | app [] = "AgentLogin" |
| static const char | app3 [] = "AgentMonitorOutgoing" |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static int | autologoff |
| static int | autologoffunavail = 0 |
| static char | beep [AST_MAX_BUF] = "beep" |
| static struct ast_cli_entry | cli_agents [] |
| static const char | config [] = "agents.conf" |
| static int | endcall |
| static char | enddtmf = DEFAULT_ENDDTMF |
| static ast_group_t | group |
| static const char | mandescr_agent_logoff [] |
| static const char | mandescr_agents [] |
| static int | maxlogintries = 3 |
| static char | moh [80] = "default" |
| static int | multiplelogin = 1 |
| static const char | pa_family [] = "Agents" |
| static int | persistent_agents = 0 |
| 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 |
Implementation of Agents (proxy channel).
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 191 of file chan_agent.c.
Referenced by agent_logoff_maintenance(), agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().
| #define AST_MAX_BUF 256 |
Definition at line 192 of file chan_agent.c.
Referenced by __agent_start_monitoring(), agentmonitoroutgoing_exec(), agents_show(), agents_show_online(), and set_agentbycallerid().
| #define AST_MAX_FILENAME_LEN 256 |
Definition at line 193 of file chan_agent.c.
Referenced by login_exec().
| #define CHECK_FORMATS | ( | ast, | |||
| p | ) |
Definition at line 270 of file chan_agent.c.
Referenced by agent_read(), and agent_write().
| #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 291 of file chan_agent.c.
Referenced by agent_call(), agent_read(), and agent_write().
| #define DEFAULT_ACCEPTDTMF '#' |
Definition at line 201 of file chan_agent.c.
| #define DEFAULT_ENDDTMF '*' |
Definition at line 202 of file chan_agent.c.
| #define GETAGENTBYCALLERID "AGENTBYCALLERID" |
Definition at line 225 of file chan_agent.c.
Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().
| #define PA_MAX_LEN 2048 |
The maximum length of each persistent member agent database entry
Definition at line 196 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 227 of file chan_agent.c.
00227 { 00228 AGENT_FLAG_ACKCALL = (1 << 0), 00229 AGENT_FLAG_AUTOLOGOFF = (1 << 1), 00230 AGENT_FLAG_WRAPUPTIME = (1 << 2), 00231 AGENT_FLAG_ACCEPTDTMF = (1 << 3), 00232 AGENT_FLAG_ENDDTMF = (1 << 4), 00233 };
| static int __agent_start_monitoring | ( | struct ast_channel * | ast, | |
| struct agent_pvt * | p, | |||
| int | needlock | |||
| ) | [static] |
Definition at line 486 of file chan_agent.c.
References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose, ast_channel::cdr, LOG_ERROR, ast_channel::monitor, ast_channel::uniqueid, X_REC_IN, and X_REC_OUT.
Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().
00487 { 00488 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer; 00489 char filename[AST_MAX_BUF]; 00490 int res = -1; 00491 if (!p) 00492 return -1; 00493 if (!ast->monitor) { 00494 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid); 00495 /* substitute . for - */ 00496 if ((pointer = strchr(filename, '.'))) 00497 *pointer = '-'; 00498 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename); 00499 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT); 00500 ast_monitor_setjoinfiles(ast, 1); 00501 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext); 00502 #if 0 00503 ast_verbose("name is %s, link is %s\n",tmp, tmp2); 00504 #endif 00505 if (!ast->cdr) 00506 ast->cdr = ast_cdr_alloc(); 00507 ast_cdr_setuserfield(ast, tmp2); 00508 res = 0; 00509 } else 00510 ast_log(LOG_ERROR, "Recording already started on that call.\n"); 00511 return res; 00512 }
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2636 of file chan_agent.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2636 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 1768 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().
01769 { 01770 const char *agent = astman_get_header(m, "Agent"); 01771 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */ 01772 int soft; 01773 int ret; /* return value of agent_logoff */ 01774 01775 if (ast_strlen_zero(agent)) { 01776 astman_send_error(s, m, "No agent specified"); 01777 return 0; 01778 } 01779 01780 soft = ast_true(soft_s) ? 1 : 0; 01781 ret = agent_logoff(agent, soft); 01782 if (ret == 0) 01783 astman_send_ack(s, m, "Agent logged out"); 01784 else 01785 astman_send_error(s, m, "No such agent"); 01786 01787 return 0; 01788 }
| static int action_agents | ( | struct mansession * | s, | |
| const struct message * | m | |||
| ) | [static] |
Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.
| s | ||
| m |
Definition at line 1565 of file chan_agent.c.
References ast_channel::_bridge, agent_pvt::acknowledged, agent_pvt::agent, ast_bridged_channel(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, S_OR, and status.
Referenced by load_module().
01566 { 01567 const char *id = astman_get_header(m,"ActionID"); 01568 char idText[256] = ""; 01569 char chanbuf[256]; 01570 struct agent_pvt *p; 01571 char *username = NULL; 01572 char *loginChan = NULL; 01573 char *talkingto = NULL; 01574 char *talkingtoChan = NULL; 01575 char *status = NULL; 01576 01577 if (!ast_strlen_zero(id)) 01578 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id); 01579 astman_send_ack(s, m, "Agents will follow"); 01580 AST_LIST_LOCK(&agents); 01581 AST_LIST_TRAVERSE(&agents, p, list) { 01582 ast_mutex_lock(&p->lock); 01583 01584 /* Status Values: 01585 AGENT_LOGGEDOFF - Agent isn't logged in 01586 AGENT_IDLE - Agent is logged in, and waiting for call 01587 AGENT_ONCALL - Agent is logged in, and on a call 01588 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */ 01589 01590 username = S_OR(p->name, "None"); 01591 01592 /* Set a default status. It 'should' get changed. */ 01593 status = "AGENT_UNKNOWN"; 01594 01595 if (!ast_strlen_zero(p->loginchan) && !p->chan) { 01596 loginChan = p->loginchan; 01597 talkingto = "n/a"; 01598 talkingtoChan = "n/a"; 01599 status = "AGENT_IDLE"; 01600 if (p->acknowledged) { 01601 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan); 01602 loginChan = chanbuf; 01603 } 01604 } else if (p->chan) { 01605 loginChan = ast_strdupa(p->chan->name); 01606 if (p->owner && p->owner->_bridge) { 01607 talkingto = p->chan->cid.cid_num; 01608 if (ast_bridged_channel(p->owner)) 01609 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name); 01610 else 01611 talkingtoChan = "n/a"; 01612 status = "AGENT_ONCALL"; 01613 } else { 01614 talkingto = "n/a"; 01615 talkingtoChan = "n/a"; 01616 status = "AGENT_IDLE"; 01617 } 01618 } else { 01619 loginChan = "n/a"; 01620 talkingto = "n/a"; 01621 talkingtoChan = "n/a"; 01622 status = "AGENT_LOGGEDOFF"; 01623 } 01624 01625 astman_append(s, "Event: Agents\r\n" 01626 "Agent: %s\r\n" 01627 "Name: %s\r\n" 01628 "Status: %s\r\n" 01629 "LoggedInChan: %s\r\n" 01630 "LoggedInTime: %d\r\n" 01631 "TalkingTo: %s\r\n" 01632 "TalkingToChan: %s\r\n" 01633 "%s" 01634 "\r\n", 01635 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText); 01636 ast_mutex_unlock(&p->lock); 01637 } 01638 AST_LIST_UNLOCK(&agents); 01639 astman_append(s, "Event: AgentsComplete\r\n" 01640 "%s" 01641 "\r\n",idText); 01642 return 0; 01643 }
| 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 357 of file chan_agent.c.
References agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::agent, AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_APP_ARG, ast_calloc, ast_cond_init(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_STANDARD_APP_ARGS, ast_strlen_zero(), ast_test_flag, ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::enddtmf, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.
Referenced by agent_request(), and read_agent_config().
00358 { 00359 char *parse; 00360 AST_DECLARE_APP_ARGS(args, 00361 AST_APP_ARG(agt); 00362 AST_APP_ARG(password); 00363 AST_APP_ARG(name); 00364 ); 00365 char *password = NULL; 00366 char *name = NULL; 00367 char *agt = NULL; 00368 struct agent_pvt *p; 00369 00370 parse = ast_strdupa(agent); 00371 00372 /* Extract username (agt), password and name from agent (args). */ 00373 AST_STANDARD_APP_ARGS(args, parse); 00374 00375 if(args.argc == 0) { 00376 ast_log(LOG_WARNING, "A blank agent line!\n"); 00377 return NULL; 00378 } 00379 00380 if(ast_strlen_zero(args.agt) ) { 00381 ast_log(LOG_WARNING, "An agent line with no agentid!\n"); 00382 return NULL; 00383 } else 00384 agt = args.agt; 00385 00386 if(!ast_strlen_zero(args.password)) { 00387 password = args.password; 00388 while (*password && *password < 33) password++; 00389 } 00390 if(!ast_strlen_zero(args.name)) { 00391 name = args.name; 00392 while (*name && *name < 33) name++; 00393 } 00394 00395 /* Are we searching for the agent here ? To see if it exists already ? */ 00396 AST_LIST_TRAVERSE(&agents, p, list) { 00397 if (!pending && !strcmp(p->agent, agt)) 00398 break; 00399 } 00400 if (!p) { 00401 // Build the agent. 00402 if (!(p = ast_calloc(1, sizeof(*p)))) 00403 return NULL; 00404 ast_copy_string(p->agent, agt, sizeof(p->agent)); 00405 ast_mutex_init(&p->lock); 00406 ast_mutex_init(&p->app_lock); 00407 ast_cond_init(&p->app_complete_cond, NULL); 00408 p->app_lock_flag = 0; 00409 p->app_sleep_cond = 1; 00410 p->group = group; 00411 p->pending = pending; 00412 AST_LIST_INSERT_TAIL(&agents, p, list); 00413 } 00414 00415 ast_copy_string(p->password, password ? password : "", sizeof(p->password)); 00416 ast_copy_string(p->name, name ? name : "", sizeof(p->name)); 00417 ast_copy_string(p->moh, moh, sizeof(p->moh)); 00418 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) { 00419 p->ackcall = ackcall; 00420 } 00421 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) { 00422 p->autologoff = autologoff; 00423 } 00424 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) { 00425 p->acceptdtmf = acceptdtmf; 00426 } 00427 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) { 00428 p->enddtmf = enddtmf; 00429 } 00430 00431 /* If someone reduces the wrapuptime and reloads, we want it 00432 * to change the wrapuptime immediately on all calls */ 00433 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) { 00434 struct timeval now = ast_tvnow(); 00435 /* XXX check what is this exactly */ 00436 00437 /* We won't be pedantic and check the tv_usec val */ 00438 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) { 00439 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000; 00440 p->lastdisc.tv_usec = now.tv_usec; 00441 } 00442 } 00443 p->wrapuptime = wrapuptime; 00444 00445 if (pending) 00446 p->dead = 1; 00447 else 00448 p->dead = 0; 00449 return p; 00450 }
| static int agent_ack_sleep | ( | void * | data | ) | [static] |
Definition at line 1028 of file chan_agent.c.
References agent_pvt::acceptdtmf, agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, f, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.
Referenced by login_exec().
01029 { 01030 struct agent_pvt *p; 01031 int res=0; 01032 int to = 1000; 01033 struct ast_frame *f; 01034 01035 /* Wait a second and look for something */ 01036 01037 p = (struct agent_pvt *) data; 01038 if (!p->chan) 01039 return -1; 01040 01041 for(;;) { 01042 to = ast_waitfor(p->chan, to); 01043 if (to < 0) 01044 return -1; 01045 if (!to) 01046 return 0; 01047 f = ast_read(p->chan); 01048 if (!f) 01049 return -1; 01050 if (f->frametype == AST_FRAME_DTMF) 01051 res = f->subclass; 01052 else 01053 res = 0; 01054 ast_frfree(f); 01055 ast_mutex_lock(&p->lock); 01056 if (!p->app_sleep_cond) { 01057 ast_mutex_unlock(&p->lock); 01058 return 0; 01059 } else if (res == p->acceptdtmf) { 01060 ast_mutex_unlock(&p->lock); 01061 return 1; 01062 } 01063 ast_mutex_unlock(&p->lock); 01064 res = 0; 01065 } 01066 return res; 01067 }
| static int agent_answer | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 480 of file chan_agent.c.
References ast_log(), and LOG_WARNING.
00481 { 00482 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n"); 00483 return -1; 00484 }
| static struct ast_channel * agent_bridgedchannel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | bridge | |||
| ) | [static, read] |
Definition at line 1069 of file chan_agent.c.
References ast_channel::_bridge, ast_debug, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.
01070 { 01071 struct agent_pvt *p = bridge->tech_pvt; 01072 struct ast_channel *ret = NULL; 01073 01074 if (p) { 01075 if (chan == p->chan) 01076 ret = bridge->_bridge; 01077 else if (chan == bridge->_bridge) 01078 ret = p->chan; 01079 } 01080 01081 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>"); 01082 return ret; 01083 }
| static int agent_call | ( | struct ast_channel * | ast, | |
| char * | dest, | |||
| int | timeout | |||
| ) | [static] |
Definition at line 770 of file chan_agent.c.
References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_best_codec(), ast_call(), ast_channel_inherit_variables(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_callerid(), ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verb, ast_waitstream(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLEANUP, ast_channel::language, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, ast_channel::name, ast_channel::nativeformats, agent_pvt::pending, agent_pvt::start, and ast_channel::tech_pvt.
00771 { 00772 struct agent_pvt *p = ast->tech_pvt; 00773 int res = -1; 00774 int newstate=0; 00775 ast_mutex_lock(&p->lock); 00776 p->acknowledged = 0; 00777 if (!p->chan) { 00778 if (p->pending) { 00779 ast_debug(1, "Pretending to dial on pending agent\n"); 00780 newstate = AST_STATE_DIALING; 00781 res = 0; 00782 } else { 00783 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n"); 00784 res = -1; 00785 } 00786 ast_mutex_unlock(&p->lock); 00787 if (newstate) 00788 ast_setstate(ast, newstate); 00789 return res; 00790 } else if (!ast_strlen_zero(p->loginchan)) { 00791 time(&p->start); 00792 /* Call on this agent */ 00793 ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name); 00794 ast_set_callerid(p->chan, 00795 ast->cid.cid_num, ast->cid.cid_name, NULL); 00796 ast_channel_inherit_variables(ast, p->chan); 00797 res = ast_call(p->chan, p->loginchan, 0); 00798 CLEANUP(ast,p); 00799 ast_mutex_unlock(&p->lock); 00800 return res; 00801 } 00802 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name); 00803 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language); 00804 res = ast_streamfile(p->chan, beep, p->chan->language); 00805 ast_debug(3, "Played beep, result '%d'\n", res); 00806 if (!res) { 00807 res = ast_waitstream(p->chan, ""); 00808 ast_debug(3, "Waited for stream, result '%d'\n", res); 00809 } 00810 if (!res) { 00811 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00812 ast_debug(3, "Set read format, result '%d'\n", res); 00813 if (res) 00814 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00815 } else { 00816 /* Agent hung-up */ 00817 p->chan = NULL; 00818 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00819 } 00820 00821 if (!res) { 00822 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats)); 00823 ast_debug(3, "Set write format, result '%d'\n", res); 00824 if (res) 00825 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats))); 00826 } 00827 if(!res) { 00828 /* Call is immediately up, or might need ack */ 00829 if (p->ackcall > 1) 00830 newstate = AST_STATE_RINGING; 00831 else { 00832 newstate = AST_STATE_UP; 00833 if (recordagentcalls) 00834 agent_start_monitoring(ast, 0); 00835 p->acknowledged = 1; 00836 } 00837 res = 0; 00838 } 00839 CLEANUP(ast, p); 00840 ast_mutex_unlock(&p->lock); 00841 if (newstate) 00842 ast_setstate(ast, newstate); 00843 return res; 00844 }
| 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 458 of file chan_agent.c.
References agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_free(), ast_cond_destroy(), ast_cond_signal(), ast_free, ast_mutex_destroy(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.
Referenced by check_availability().
00459 { 00460 struct ast_channel *chan = p->owner; 00461 p->owner = NULL; 00462 chan->tech_pvt = NULL; 00463 p->app_sleep_cond = 1; 00464 /* Release ownership of the agent to other threads (presumably running the login app). */ 00465 p->app_lock_flag = 0; 00466 ast_cond_signal(&p->app_complete_cond); 00467 if (chan) 00468 ast_channel_free(chan); 00469 if (p->dead) { 00470 ast_mutex_destroy(&p->lock); 00471 ast_mutex_destroy(&p->app_lock); 00472 ast_cond_destroy(&p->app_complete_cond); 00473 ast_free(p); 00474 } 00475 return 0; 00476 }
| static int agent_cont_sleep | ( | void * | data | ) | [static] |
Definition at line 1007 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().
01008 { 01009 struct agent_pvt *p; 01010 int res; 01011 01012 p = (struct agent_pvt *)data; 01013 01014 ast_mutex_lock(&p->lock); 01015 res = p->app_sleep_cond; 01016 if (p->lastdisc.tv_sec) { 01017 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 01018 res = 1; 01019 } 01020 ast_mutex_unlock(&p->lock); 01021 01022 if (!res) 01023 ast_debug(5, "agent_cont_sleep() returning %d\n", res ); 01024 01025 return res; 01026 }
| static int agent_devicestate | ( | void * | data | ) | [static] |
Part of PBX channel interface.
Definition at line 2438 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(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
02439 { 02440 struct agent_pvt *p; 02441 char *s; 02442 ast_group_t groupmatch; 02443 int groupoff; 02444 int res = AST_DEVICE_INVALID; 02445 02446 s = data; 02447 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) 02448 groupmatch = (1 << groupoff); 02449 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 02450 groupmatch = (1 << groupoff); 02451 } else 02452 groupmatch = 0; 02453 02454 /* Check actual logged in agents first */ 02455 AST_LIST_LOCK(&agents); 02456 AST_LIST_TRAVERSE(&agents, p, list) { 02457 ast_mutex_lock(&p->lock); 02458 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 02459 if (p->owner) { 02460 if (res != AST_DEVICE_INUSE) 02461 res = AST_DEVICE_BUSY; 02462 } else { 02463 if (res == AST_DEVICE_BUSY) 02464 res = AST_DEVICE_INUSE; 02465 if (p->chan || !ast_strlen_zero(p->loginchan)) { 02466 if (res == AST_DEVICE_INVALID) 02467 res = AST_DEVICE_UNKNOWN; 02468 } else if (res == AST_DEVICE_INVALID) 02469 res = AST_DEVICE_UNAVAILABLE; 02470 } 02471 if (!strcmp(data, p->agent)) { 02472 ast_mutex_unlock(&p->lock); 02473 break; 02474 } 02475 } 02476 ast_mutex_unlock(&p->lock); 02477 } 02478 AST_LIST_UNLOCK(&agents); 02479 return res; 02480 }
| static int agent_digit_begin | ( | struct ast_channel * | ast, | |
| char | digit | |||
| ) | [static] |
Definition at line 748 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.
00749 { 00750 struct agent_pvt *p = ast->tech_pvt; 00751 ast_mutex_lock(&p->lock); 00752 if (p->chan) { 00753 ast_senddigit_begin(p->chan, digit); 00754 } 00755 ast_mutex_unlock(&p->lock); 00756 return 0; 00757 }
| static int agent_digit_end | ( | struct ast_channel * | ast, | |
| char | digit, | |||
| unsigned int | duration | |||
| ) | [static] |
Definition at line 759 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.
00760 { 00761 struct agent_pvt *p = ast->tech_pvt; 00762 ast_mutex_lock(&p->lock); 00763 if (p->chan) { 00764 ast_senddigit_end(p->chan, digit, duration); 00765 } 00766 ast_mutex_unlock(&p->lock); 00767 return 0; 00768 }
| static int agent_fixup | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) | [static] |
Definition at line 715 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.
00716 { 00717 struct agent_pvt *p = newchan->tech_pvt; 00718 ast_mutex_lock(&p->lock); 00719 if (p->owner != oldchan) { 00720 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner); 00721 ast_mutex_unlock(&p->lock); 00722 return -1; 00723 } 00724 p->owner = newchan; 00725 ast_mutex_unlock(&p->lock); 00726 return 0; 00727 }
| 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 860 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.
00861 { 00862 struct agent_pvt *p = NULL; 00863 struct ast_channel *base = chan; 00864 00865 /* chan is locked by the calling function */ 00866 if (!chan || !chan->tech_pvt) { 00867 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); 00868 return NULL; 00869 } 00870 p = chan->tech_pvt; 00871 if (p->chan) 00872 base = p->chan; 00873 return base; 00874 }
| static int agent_hangup | ( | struct ast_channel * | ast | ) | [static] |
Definition at line 893 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), AST_CONTROL_HOLD, ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_hangup(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, status, ast_channel::tech_pvt, ast_channel::uniqueid, and agent_pvt::wrapuptime.
00894 { 00895 struct agent_pvt *p = ast->tech_pvt; 00896 int howlong = 0; 00897 const char *status; 00898 ast_mutex_lock(&p->lock); 00899 p->owner = NULL; 00900 ast->tech_pvt = NULL; 00901 p->app_sleep_cond = 1; 00902 p->acknowledged = 0; 00903 00904 /* if they really are hung up then set start to 0 so the test 00905 * later if we're called on an already downed channel 00906 * doesn't cause an agent to be logged out like when 00907 * agent_request() is followed immediately by agent_hangup() 00908 * as in apps/app_chanisavail.c:chanavail_exec() 00909 */ 00910 00911 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state)); 00912 if (p->start && (ast->_state != AST_STATE_UP)) { 00913 howlong = time(NULL) - p->start; 00914 p->start = 0; 00915 } else if (ast->_state == AST_STATE_RESERVED) 00916 howlong = 0; 00917 else 00918 p->start = 0; 00919 if (p->chan) { 00920 p->chan->_bridge = NULL; 00921 /* If they're dead, go ahead and hang up on the agent now */ 00922 if (!ast_strlen_zero(p->loginchan)) { 00923 /* Store last disconnect time */ 00924 if (p->wrapuptime) 00925 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00926 else 00927 p->lastdisc = ast_tv(0,0); 00928 if (p->chan) { 00929 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00930 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00931 long logintime = time(NULL) - p->loginstart; 00932 p->loginstart = 0; 00933 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name); 00934 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00935 } 00936 /* Recognize the hangup and pass it along immediately */ 00937 ast_hangup(p->chan); 00938 p->chan = NULL; 00939 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00940 } 00941 ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff); 00942 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) { 00943 long logintime = time(NULL) - p->loginstart; 00944 p->loginstart = 0; 00945 if (!p->deferlogoff) 00946 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00947 p->deferlogoff = 0; 00948 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff"); 00949 if (persistent_agents) 00950 dump_agents(); 00951 } 00952 } else if (p->dead) { 00953 ast_channel_lock(p->chan); 00954 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00955 ast_channel_unlock(p->chan); 00956 } else if (p->loginstart) { 00957 ast_channel_lock(p->chan); 00958 ast_indicate_data(p->chan, AST_CONTROL_HOLD, 00959 S_OR(p->moh, NULL), 00960 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 00961 ast_channel_unlock(p->chan); 00962 } 00963 } 00964 ast_mutex_unlock(&p->lock); 00965 00966 /* Only register a device state change if the agent is still logged in */ 00967 if (!p->loginstart) { 00968 p->loginchan[0] = '\0'; 00969 p->logincallerid[0] = '\0'; 00970 if (persistent_agents) 00971 dump_agents(); 00972 } else { 00973 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 00974 } 00975 00976 if (p->pending) { 00977 AST_LIST_LOCK(&agents); 00978 AST_LIST_REMOVE(&agents, p, list); 00979 AST_LIST_UNLOCK(&agents); 00980 } 00981 if (p->abouttograb) { 00982 /* Let the "about to grab" thread know this isn't valid anymore, and let it 00983 kill it later */ 00984 p->abouttograb = 0; 00985 } else if (p->dead) { 00986 ast_mutex_destroy(&p->lock); 00987 ast_mutex_destroy(&p->app_lock); 00988 ast_cond_destroy(&p->app_complete_cond); 00989 ast_free(p); 00990 } else { 00991 if (p->chan) { 00992 /* Not dead -- check availability now */ 00993 ast_mutex_lock(&p->lock); 00994 /* Store last disconnect time */ 00995 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00996 ast_mutex_unlock(&p->lock); 00997 } 00998 /* Release ownership of the agent to other threads (presumably running the login app). */ 00999 if (ast_strlen_zero(p->loginchan)) { 01000 p->app_lock_flag = 0; 01001 ast_cond_signal(&p->app_complete_cond); 01002 } 01003 } 01004 return 0; 01005 }
| static int agent_indicate | ( | struct ast_channel * | ast, | |
| int | condition, | |||
| const void * | data, | |||
| size_t | datalen | |||
| ) | [static] |
Definition at line 729 of file chan_agent.c.
References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, ast_channel::tech, and ast_channel::tech_pvt.
00730 { 00731 struct agent_pvt *p = ast->tech_pvt; 00732 int res = -1; 00733 ast_mutex_lock(&p->lock); 00734 if (p->chan && !ast_check_hangup(p->chan)) { 00735 while (ast_channel_trylock(p->chan)) { 00736 ast_channel_unlock(ast); 00737 usleep(1); 00738 ast_channel_lock(ast); 00739 } 00740 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1; 00741 ast_channel_unlock(p->chan); 00742 } else 00743 res = 0; 00744 ast_mutex_unlock(&p->lock); 00745 return res; 00746 }
| static int agent_logoff | ( | const char * | agent, | |
| int | soft | |||
| ) | [static] |
Definition at line 1684 of file chan_agent.c.
References agent_pvt::agent, agent_logoff_maintenance(), ast_channel_trylock, ast_channel_unlock, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, DEADLOCK_AVOIDANCE, agent_pvt::deferlogoff, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.
Referenced by action_agent_logoff(), and agent_logoff_cmd().
01685 { 01686 struct agent_pvt *p; 01687 long logintime; 01688 int ret = -1; /* Return -1 if no agent if found */ 01689 01690 AST_LIST_LOCK(&agents); 01691 AST_LIST_TRAVERSE(&agents, p, list) { 01692 if (!strcasecmp(p->agent, agent)) { 01693 ret = 0; 01694 if (p->owner || p->chan) { 01695 if (!soft) { 01696 ast_mutex_lock(&p->lock); 01697 01698 while (p->owner && ast_channel_trylock(p->owner)) { 01699 DEADLOCK_AVOIDANCE(&p->lock); 01700 } 01701 if (p->owner) { 01702 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 01703 ast_channel_unlock(p->owner); 01704 } 01705 01706 while (p->chan && ast_channel_trylock(p->chan)) { 01707 DEADLOCK_AVOIDANCE(&p->lock); 01708 } 01709 if (p->chan) { 01710 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01711 ast_channel_unlock(p->chan); 01712 } 01713 01714 ast_mutex_unlock(&p->lock); 01715 } else 01716 p->deferlogoff = 1; 01717 } else { 01718 logintime = time(NULL) - p->loginstart; 01719 p->loginstart = 0; 01720 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 01721 } 01722 break; 01723 } 01724 } 01725 AST_LIST_UNLOCK(&agents); 01726 01727 return ret; 01728 }
| static char* agent_logoff_cmd | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1730 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.
01731 { 01732 int ret; 01733 char *agent; 01734 01735 switch (cmd) { 01736 case CLI_INIT: 01737 e->command = "agent logoff"; 01738 e->usage = 01739 "Usage: agent logoff <channel> [soft]\n" 01740 " Sets an agent as no longer logged in.\n" 01741 " If 'soft' is specified, do not hangup existing calls.\n"; 01742 return NULL; 01743 case CLI_GENERATE: 01744 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 01745 } 01746 01747 if (a->argc < 3 || a->argc > 4) 01748 return CLI_SHOWUSAGE; 01749 if (a->argc == 4 && strcasecmp(a->argv[3], "soft")) 01750 return CLI_SHOWUSAGE; 01751 01752 agent = a->argv[2] + 6; 01753 ret = agent_logoff(agent, a->argc == 4); 01754 if (ret == 0) 01755 ast_cli(a->fd, "Logging out %s\n", agent); 01756 01757 return CLI_SUCCESS; 01758 }
| static void agent_logoff_maintenance | ( | struct agent_pvt * | p, | |
| char * | loginchan, | |||
| long | logintime, | |||
| const char * | uniqueid, | |||
| char * | logcommand | |||
| ) | [static] |
Definition at line 1645 of file chan_agent.c.
References agent_pvt::agent, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_MAX_AGENT, ast_queue_log(), ast_strlen_zero(), dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event, and set_agentbycallerid().
Referenced by agent_hangup(), agent_logoff(), and agent_read().
01646 { 01647 char *tmp = NULL; 01648 char agent[AST_MAX_AGENT]; 01649 01650 if (!ast_strlen_zero(logcommand)) 01651 tmp = logcommand; 01652 else 01653 tmp = ast_strdupa(""); 01654 01655 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 01656 01657 if (!ast_strlen_zero(uniqueid)) { 01658 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01659 "Agent: %s\r\n" 01660 "Reason: %s\r\n" 01661 "Loginchan: %s\r\n" 01662 "Logintime: %ld\r\n" 01663 "Uniqueid: %s\r\n", 01664 p->agent, tmp, loginchan, logintime, uniqueid); 01665 } else { 01666 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff", 01667 "Agent: %s\r\n" 01668 "Reason: %s\r\n" 01669 "Loginchan: %s\r\n" 01670 "Logintime: %ld\r\n", 01671 p->agent, tmp, loginchan, logintime); 01672 } 01673 01674 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp); 01675 set_agentbycallerid(p->logincallerid, NULL); 01676 p->loginchan[0] ='\0'; 01677 p->logincallerid[0] = '\0'; 01678 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 01679 if (persistent_agents) 01680 dump_agents(); 01681 01682 }
| static struct ast_channel* agent_new | ( | struct agent_pvt * | p, | |
| int | state | |||
| ) | [static, read] |
Create new agent channel.
Definition at line 1086 of file chan_agent.c.
References agent_pvt::agent, agent_tech, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_alloc, ast_channel_free(), ast_cond_signal(), AST_CONTROL_UNHOLD, ast_copy_string(), AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, ast_strlen_zero(), agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, agent_pvt::loginchan, 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().
01087 { 01088 struct ast_channel *tmp; 01089 int alreadylocked; 01090 #if 0 01091 if (!p->chan) { 01092 ast_log(LOG_WARNING, "No channel? :(\n"); 01093 return NULL; 01094 } 01095 #endif 01096 if (p->pending) 01097 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff); 01098 else 01099 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent); 01100 if (!tmp) { 01101 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n"); 01102 return NULL; 01103 } 01104 01105 tmp->tech = &agent_tech; 01106 if (p->chan) { 01107 tmp->nativeformats = p->chan->nativeformats; 01108 tmp->writeformat = p->chan->writeformat; 01109 tmp->rawwriteformat = p->chan->writeformat; 01110 tmp->readformat = p->chan->readformat; 01111 tmp->rawreadformat = p->chan->readformat; 01112 ast_string_field_set(tmp, language, p->chan->language); 01113 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context)); 01114 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten)); 01115 /* XXX Is this really all we copy form the originating channel?? */ 01116 } else { 01117 tmp->nativeformats = AST_FORMAT_SLINEAR; 01118 tmp->writeformat = AST_FORMAT_SLINEAR; 01119 tmp->rawwriteformat = AST_FORMAT_SLINEAR; 01120 tmp->readformat = AST_FORMAT_SLINEAR; 01121 tmp->rawreadformat = AST_FORMAT_SLINEAR; 01122 } 01123 /* Safe, agentlock already held */ 01124 tmp->tech_pvt = p; 01125 p->owner = tmp; 01126 tmp->priority = 1; 01127 /* Wake up and wait for other applications (by definition the login app) 01128 * to release this channel). Takes ownership of the agent channel 01129 * to this thread only. 01130 * For signalling the other thread, ast_queue_frame is used until we 01131 * can safely use signals for this purpose. The pselect() needs to be 01132 * implemented in the kernel for this. 01133 */ 01134 p->app_sleep_cond = 0; 01135 01136 alreadylocked = p->app_lock_flag; 01137 p->app_lock_flag = 1; 01138 01139 if(ast_strlen_zero(p->loginchan) && alreadylocked) { 01140 if (p->chan) { 01141 ast_queue_frame(p->chan, &ast_null_frame); 01142 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01143 p->app_lock_flag = 1; 01144 ast_mutex_lock(&p->lock); 01145 } else { 01146 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01147 p->owner = NULL; 01148 tmp->tech_pvt = NULL; 01149 p->app_sleep_cond = 1; 01150 ast_channel_free( tmp ); 01151 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01152 p->app_lock_flag = 0; 01153 ast_cond_signal(&p->app_complete_cond); 01154 return NULL; 01155 } 01156 } else if (!ast_strlen_zero(p->loginchan)) { 01157 if (p->chan) 01158 ast_queue_frame(p->chan, &ast_null_frame); 01159 if (!p->chan) { 01160 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n"); 01161 p->owner = NULL; 01162 tmp->tech_pvt = NULL; 01163 p->app_sleep_cond = 1; 01164 ast_channel_free( tmp ); 01165 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */ 01166 return NULL; 01167 } 01168 } 01169 if (p->chan) 01170 ast_indicate(p->chan, AST_CONTROL_UNHOLD); 01171 return tmp; 01172 }
| static struct ast_frame * agent_read | ( | struct ast_channel * | ast | ) | [static, read] |
Definition at line 519 of file chan_agent.c.
References ast_channel::_bridge, ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, 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_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, agent_pvt::enddtmf, f, ast_channel::fdno, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, ast_channel::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, status, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, and agent_pvt::wrapuptime.
00520 { 00521 struct agent_pvt *p = ast->tech_pvt; 00522 struct ast_frame *f = NULL; 00523 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER }; 00524 const char *status; 00525 int cur_time = time(NULL); 00526 ast_mutex_lock(&p->lock); 00527 CHECK_FORMATS(ast, p); 00528 if (!p->start) { 00529 p->start = cur_time; 00530 } 00531 if (p->chan) { 00532 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION); 00533 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno; 00534 f = ast_read(p->chan); 00535 } else 00536 f = &ast_null_frame; 00537 if (!f) { 00538 /* If there's a channel, hang it up (if it's on a callback) make it NULL */ 00539 if (p->chan) { 00540 p->chan->_bridge = NULL; 00541 /* Note that we don't hangup if it's not a callback because Asterisk will do it 00542 for us when the PBX instance that called login finishes */ 00543 if (!ast_strlen_zero(p->loginchan)) { 00544 if (p->chan) 00545 ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name); 00546 if (p->owner->_state != AST_STATE_UP) { 00547 int howlong = cur_time - p->start; 00548 if (p->autologoff && howlong >= p->autologoff) { 00549 p->loginstart = 0; 00550 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00551 agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff"); 00552 } 00553 } 00554 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS"); 00555 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) { 00556 long logintime = cur_time - p->loginstart; 00557 p->loginstart = 0; 00558 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name); 00559 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail"); 00560 } 00561 ast_hangup(p->chan); 00562 if (p->wrapuptime && p->acknowledged) 00563 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000)); 00564 } 00565 p->chan = NULL; 00566 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 00567 p->acknowledged = 0; 00568 } 00569 } else { 00570 /* if acknowledgement is not required, and the channel is up, we may have missed 00571 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */ 00572 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) { 00573 p->acknowledged = 1; 00574 } 00575 00576 if (!p->acknowledged) { 00577 int howlong = cur_time - p->start; 00578 if (p->autologoff && (howlong >= p->autologoff)) { 00579 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong); 00580 agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff"); 00581 if (p->owner || p->chan) { 00582 while (p->owner && ast_channel_trylock(p->owner)) { 00583 DEADLOCK_AVOIDANCE(&p->lock); 00584 } 00585 if (p->owner) { 00586 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT); 00587 ast_channel_unlock(p->owner); 00588 } 00589 00590 while (p->chan && ast_channel_trylock(p->chan)) { 00591 DEADLOCK_AVOIDANCE(&p->lock); 00592 } 00593 if (p->chan) { 00594 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 00595 ast_channel_unlock(p->chan); 00596 } 00597 } else { 00598 long logintime; 00599 logintime = time(NULL) - p->loginstart; 00600 p->loginstart = 0; 00601 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff"); 00602 } 00603 } 00604 } 00605 switch (f->frametype) { 00606 case AST_FRAME_CONTROL: 00607 if (f->subclass == AST_CONTROL_ANSWER) { 00608 if (p->ackcall) { 00609 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf); 00610 /* Don't pass answer along */ 00611 ast_frfree(f); 00612 f = &ast_null_frame; 00613 } else { 00614 p->acknowledged = 1; 00615 /* Use the builtin answer frame for the 00616 recording start check below. */ 00617 ast_frfree(f); 00618 f = &answer_frame; 00619 } 00620 } 00621 break; 00622 case AST_FRAME_DTMF_BEGIN: 00623 /*ignore DTMF begin's as it can cause issues with queue announce files*/ 00624 if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){ 00625 ast_frfree(f); 00626 f = &ast_null_frame; 00627 } 00628 break; 00629 case AST_FRAME_DTMF_END: 00630 if (!p->acknowledged && (f->subclass == p->acceptdtmf)) { 00631 ast_verb(3, "%s acknowledged\n", p->chan->name); 00632 p->acknowledged = 1; 00633 ast_frfree(f); 00634 f = &answer_frame; 00635 } else if (f->subclass == p->enddtmf && endcall) { 00636 /* terminates call */ 00637 ast_frfree(f); 00638 f = NULL; 00639 } 00640 break; 00641 case AST_FRAME_VOICE: 00642 case AST_FRAME_VIDEO: 00643 /* don't pass voice or video until the call is acknowledged */ 00644 if (!p->acknowledged) { 00645 ast_frfree(f); 00646 f = &ast_null_frame; 00647 } 00648 default: 00649 /* pass everything else on through */ 00650 break; 00651 } 00652 } 00653 00654 CLEANUP(ast,p); 00655 if (p->chan && !p->chan->_bridge) { 00656 if (strcasecmp(p->chan->tech->type, "Local")) { 00657 p->chan->_bridge = ast; 00658 if (p->chan) 00659 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name); 00660 } 00661 } 00662 ast_mutex_unlock(&p->lock); 00663 if (recordagentcalls && f == &answer_frame) 00664 agent_start_monitoring(ast,0); 00665 return f; 00666 }
| static struct ast_channel * agent_request | ( | const char * | type, | |
| int | format, | |||
| void * | data, | |||
| int * | cause | |||
| ) | [static, read] |
Part of the Asterisk PBX interface.
Definition at line 1452 of file chan_agent.c.
References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_request(), AST_STATE_DOWN, ast_strlen_zero(), ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.
01453 { 01454 struct agent_pvt *p; 01455 struct ast_channel *chan = NULL; 01456 char *s; 01457 ast_group_t groupmatch; 01458 int groupoff; 01459 int waitforagent=0; 01460 int hasagent = 0; 01461 struct timeval now; 01462 01463 s = data; 01464 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01465 groupmatch = (1 << groupoff); 01466 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) { 01467 groupmatch = (1 << groupoff); 01468 waitforagent = 1; 01469 } else 01470 groupmatch = 0; 01471 01472 /* Check actual logged in agents first */ 01473 AST_LIST_LOCK(&agents); 01474 AST_LIST_TRAVERSE(&agents, p, list) { 01475 ast_mutex_lock(&p->lock); 01476 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) && 01477 ast_strlen_zero(p->loginchan)) { 01478 if (p->chan) 01479 hasagent++; 01480 now = ast_tvnow(); 01481 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01482 p->lastdisc = ast_tv(0, 0); 01483 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01484 if (!p->owner && p->chan) { 01485 /* Fixed agent */ 01486 chan = agent_new(p, AST_STATE_DOWN); 01487 } 01488 if (chan) { 01489 ast_mutex_unlock(&p->lock); 01490 break; 01491 } 01492 } 01493 } 01494 ast_mutex_unlock(&p->lock); 01495 } 01496 if (!p) { 01497 AST_LIST_TRAVERSE(&agents, p, list) { 01498 ast_mutex_lock(&p->lock); 01499 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) { 01500 if (p->chan || !ast_strlen_zero(p->loginchan)) 01501 hasagent++; 01502 now = ast_tvnow(); 01503 #if 0 01504 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec); 01505 #endif 01506 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) { 01507 p->lastdisc = ast_tv(0, 0); 01508 /* Agent must be registered, but not have any active call, and not be in a waiting state */ 01509 if (!p->owner && p->chan) { 01510 /* Could still get a fixed agent */ 01511 chan = agent_new(p, AST_STATE_DOWN); 01512 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) { 01513 /* Adjustable agent */ 01514 p->chan = ast_request("Local", format, p->loginchan, cause); 01515 if (p->chan) 01516 chan = agent_new(p, AST_STATE_DOWN); 01517 } 01518 if (chan) { 01519 ast_mutex_unlock(&p->lock); 01520 break; 01521 } 01522 } 01523 } 01524 ast_mutex_unlock(&p->lock); 01525 } 01526 } 01527 01528 if (!chan && waitforagent) { 01529 /* No agent available -- but we're requesting to wait for one. 01530 Allocate a place holder */ 01531 if (hasagent) { 01532 ast_debug(1, "Creating place holder for '%s'\n", s); 01533 p = add_agent(data, 1); 01534 p->group = groupmatch; 01535 chan = agent_new(p, AST_STATE_DOWN); 01536 if (!chan) 01537 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n"); 01538 } else { 01539 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s); 01540 } 01541 } 01542 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED; 01543 AST_LIST_UNLOCK(&agents); 01544 return chan; 01545 }
| static int agent_sendhtml | ( | struct ast_channel * | ast, | |
| int | subclass, | |||
| const char * | data, | |||
| int | datalen | |||
| ) | [static] |
Definition at line 668 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.
00669 { 00670 struct agent_pvt *p = ast->tech_pvt; 00671 int res = -1; 00672 ast_mutex_lock(&p->lock); 00673 if (p->chan) 00674 res = ast_channel_sendhtml(p->chan, subclass, data, datalen); 00675 ast_mutex_unlock(&p->lock); 00676 return res; 00677 }
| static int agent_sendtext | ( | struct ast_channel * | ast, | |
| const char * | text | |||
| ) | [static] |
Definition at line 679 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.
00680 { 00681 struct agent_pvt *p = ast->tech_pvt; 00682 int res = -1; 00683 ast_mutex_lock(&p->lock); 00684 if (p->chan) 00685 res = ast_sendtext(p->chan, text); 00686 ast_mutex_unlock(&p->lock); 00687 return res; 00688 }
| int agent_set_base_channel | ( | struct ast_channel * | chan, | |
| struct ast_channel * | base | |||
| ) | [static] |
Definition at line 876 of file chan_agent.c.
References ast_log(), agent_pvt::chan, LOG_ERROR, ast_channel::name, and ast_channel::tech_pvt.
00877 { 00878 struct agent_pvt *p = NULL; 00879 00880 if (!chan || !base) { 00881 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base); 00882 return -1; 00883 } 00884 p = chan->tech_pvt; 00885 if (!p) { 00886 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name); 00887 return -1; 00888 } 00889 p->chan = base; 00890 return 0; 00891 }
| static int agent_start_monitoring | ( | struct ast_channel * | ast, | |
| int | needlock | |||
| ) | [static] |
Definition at line 514 of file chan_agent.c.
References __agent_start_monitoring(), and ast_channel::tech_pvt.
Referenced by agent_call(), and agent_read().
00515 { 00516 return __agent_start_monitoring(ast, ast->tech_pvt, needlock); 00517 }
| static int agent_write | ( | struct ast_channel * | ast, | |
| struct ast_frame * | f | |||
| ) | [static] |
Definition at line 690 of file chan_agent.c.
References ast_debug, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock(), ast_mutex_unlock(), ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame::frametype, agent_pvt::lock, ast_channel::name, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.
00691 { 00692 struct agent_pvt *p = ast->tech_pvt; 00693 int res = -1; 00694 CHECK_FORMATS(ast, p); 00695 ast_mutex_lock(&p->lock); 00696 if (!p->chan) 00697 res = 0; 00698 else { 00699 if ((f->frametype != AST_FRAME_VOICE) || 00700 (f->frametype != AST_FRAME_VIDEO) || 00701 (f->subclass == p->chan->writeformat)) { 00702 res = ast_write(p->chan, f); 00703 } else { 00704 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 00705 f->frametype == AST_FRAME_VOICE ? "audio" : "video", 00706 ast->name, p->chan->name); 00707 res = 0; 00708 } 00709 } 00710 CLEANUP(ast, p); 00711 ast_mutex_unlock(&p->lock); 00712 return res; 00713 }
| static int agentmonitoroutgoing_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Called by the AgentMonitorOutgoing application (from the dial plan).
| chan | ||
| data |
Definition at line 2309 of file chan_agent.c.
References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, GETAGENTBYCALLERID, LOG_WARNING, and pbx_builtin_getvar_helper().
Referenced by load_module().
02310 { 02311 int exitifnoagentid = 0; 02312 int nowarnings = 0; 02313 int changeoutgoing = 0; 02314 int res = 0; 02315 char agent[AST_MAX_AGENT]; 02316 02317 if (data) { 02318 if (strchr(data, 'd')) 02319 exitifnoagentid = 1; 02320 if (strchr(data, 'n')) 02321 nowarnings = 1; 02322 if (strchr(data, 'c')) 02323 changeoutgoing = 1; 02324 } 02325 if (chan->cid.cid_num) { 02326 const char *tmp; 02327 char agentvar[AST_MAX_BUF]; 02328 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num); 02329 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) { 02330 struct agent_pvt *p; 02331 ast_copy_string(agent, tmp, sizeof(agent)); 02332 AST_LIST_LOCK(&agents); 02333 AST_LIST_TRAVERSE(&agents, p, list) { 02334 if (!strcasecmp(p->agent, tmp)) { 02335 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02336 __agent_start_monitoring(chan, p, 1); 02337 break; 02338 } 02339 } 02340 AST_LIST_UNLOCK(&agents); 02341 02342 } else { 02343 res = -1; 02344 if (!nowarnings) 02345 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); 02346 } 02347 } else { 02348 res = -1; 02349 if (!nowarnings) 02350 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"); 02351 } 02352 if (res) { 02353 if (exitifnoagentid) 02354 return res; 02355 } 02356 return 0; 02357 }
| 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 1817 of file chan_agent.c.
References agent_pvt::acknowledged, agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.
01818 { 01819 struct agent_pvt *p; 01820 char username[AST_MAX_BUF]; 01821 char location[AST_MAX_BUF] = ""; 01822 char talkingto[AST_MAX_BUF] = ""; 01823 char music[AST_MAX_BUF]; 01824 int count_agents = 0; /*!< Number of agents configured */ 01825 int online_agents = 0; /*!< Number of online agents */ 01826 int offline_agents = 0; /*!< Number of offline agents */ 01827 01828 switch (cmd) { 01829 case CLI_INIT: 01830 e->command = "agent show"; 01831 e->usage = 01832 "Usage: agent show\n" 01833 " Provides summary information on agents.\n"; 01834 return NULL; 01835 case CLI_GENERATE: 01836 return NULL; 01837 } 01838 01839 if (a->argc != 2) 01840 return CLI_SHOWUSAGE; 01841 01842 AST_LIST_LOCK(&agents); 01843 AST_LIST_TRAVERSE(&agents, p, list) { 01844 ast_mutex_lock(&p->lock); 01845 if (p->pending) { 01846 if (p->group) 01847 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group)); 01848 else 01849 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent); 01850 } else { 01851 if (!ast_strlen_zero(p->name)) 01852 snprintf(username, sizeof(username), "(%s) ", p->name); 01853 else 01854 username[0] = '\0'; 01855 if (p->chan) { 01856 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01857 if (p->owner && ast_bridged_channel(p->owner)) 01858 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01859 else 01860 strcpy(talkingto, " is idle"); 01861 online_agents++; 01862 } else if (!ast_strlen_zero(p->loginchan)) { 01863 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 01864 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01865 else 01866 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan); 01867 talkingto[0] = '\0'; 01868 online_agents++; 01869 if (p->acknowledged) 01870 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01871 } else { 01872 strcpy(location, "not logged in"); 01873 talkingto[0] = '\0'; 01874 offline_agents++; 01875 } 01876 if (!ast_strlen_zero(p->moh)) 01877 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01878 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 01879 username, location, talkingto, music); 01880 count_agents++; 01881 } 01882 ast_mutex_unlock(&p->lock); 01883 } 01884 AST_LIST_UNLOCK(&agents); 01885 if ( !count_agents ) 01886 ast_cli(a->fd, "No Agents are configured in %s\n",config); 01887 else 01888 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents); 01889 ast_cli(a->fd, "\n"); 01890 01891 return CLI_SUCCESS; 01892 }
| static char* agents_show_online | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1895 of file chan_agent.c.
References agent_pvt::acknowledged, agent_pvt::agent, ast_cli_args::argc, ast_bridged_channel(), ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.
01896 { 01897 struct agent_pvt *p; 01898 char username[AST_MAX_BUF]; 01899 char location[AST_MAX_BUF] = ""; 01900 char talkingto[AST_MAX_BUF] = ""; 01901 char music[AST_MAX_BUF]; 01902 int count_agents = 0; /* Number of agents configured */ 01903 int online_agents = 0; /* Number of online agents */ 01904 int agent_status = 0; /* 0 means offline, 1 means online */ 01905 01906 switch (cmd) { 01907 case CLI_INIT: 01908 e->command = "agent show online"; 01909 e->usage = 01910 "Usage: agent show online\n" 01911 " Provides a list of all online agents.\n"; 01912 return NULL; 01913 case CLI_GENERATE: 01914 return NULL; 01915 } 01916 01917 if (a->argc != 3) 01918 return CLI_SHOWUSAGE; 01919 01920 AST_LIST_LOCK(&agents); 01921 AST_LIST_TRAVERSE(&agents, p, list) { 01922 agent_status = 0; /* reset it to offline */ 01923 ast_mutex_lock(&p->lock); 01924 if (!ast_strlen_zero(p->name)) 01925 snprintf(username, sizeof(username), "(%s) ", p->name); 01926 else 01927 username[0] = '\0'; 01928 if (p->chan) { 01929 snprintf(location, sizeof(location), "logged in on %s", p->chan->name); 01930 if (p->owner && ast_bridged_channel(p->owner)) 01931 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name); 01932 else 01933 strcpy(talkingto, " is idle"); 01934 agent_status = 1; 01935 online_agents++; 01936 } else if (!ast_strlen_zero(p->loginchan)) { 01937 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan); 01938 talkingto[0] = '\0'; 01939 agent_status = 1; 01940 online_agents++; 01941 if (p->acknowledged) 01942 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1); 01943 } 01944 if (!ast_strlen_zero(p->moh)) 01945 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh); 01946 if (agent_status) 01947 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music); 01948 count_agents++; 01949 ast_mutex_unlock(&p->lock); 01950 } 01951 AST_LIST_UNLOCK(&agents); 01952 if (!count_agents) 01953 ast_cli(a->fd, "No Agents are configured in %s\n", config); 01954 else 01955 ast_cli(a->fd, "%d agents online\n", online_agents); 01956 ast_cli(a->fd, "\n"); 01957 return CLI_SUCCESS; 01958 }
| static int check_availability | ( | struct agent_pvt * | newlyavailable, | |
| int | needlock | |||
| ) | [static] |
Definition at line 1350 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), ast_copy_string(), ast_debug, AST_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, ast_channel::language, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01351 { 01352 struct ast_channel *chan=NULL, *parent=NULL; 01353 struct agent_pvt *p; 01354 int res; 01355 01356 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent); 01357 if (needlock) 01358 AST_LIST_LOCK(&agents); 01359 AST_LIST_TRAVERSE(&agents, p, list) { 01360 if (p == newlyavailable) { 01361 continue; 01362 } 01363 ast_mutex_lock(&p->lock); 01364 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01365 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01366 /* We found a pending call, time to merge */ 01367 chan = agent_new(newlyavailable, AST_STATE_DOWN); 01368 parent = p->owner; 01369 p->abouttograb = 1; 01370 ast_mutex_unlock(&p->lock); 01371 break; 01372 } 01373 ast_mutex_unlock(&p->lock); 01374 } 01375 if (needlock) 01376 AST_LIST_UNLOCK(&agents); 01377 if (parent && chan) { 01378 if (newlyavailable->ackcall > 1) { 01379 /* Don't do beep here */ 01380 res = 0; 01381 } else { 01382 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01383 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01384 ast_debug(3, "Played beep, result '%d'\n", res); 01385 if (!res) { 01386 res = ast_waitstream(newlyavailable->chan, ""); 01387 ast_debug(1, "Waited for stream, result '%d'\n", res); 01388 } 01389 } 01390 if (!res) { 01391 /* Note -- parent may have disappeared */ 01392 if (p->abouttograb) { 01393 newlyavailable->acknowledged = 1; 01394 /* Safe -- agent lock already held */ 01395 ast_setstate(parent, AST_STATE_UP); 01396 ast_setstate(chan, AST_STATE_UP); 01397 ast_copy_string(parent->context, chan->context, sizeof(parent->context)); 01398 /* Go ahead and mark the channel as a zombie so that masquerade will 01399 destroy it for us, and we need not call ast_hangup */ 01400 ast_set_flag(chan, AST_FLAG_ZOMBIE); 01401 ast_channel_masquerade(parent, chan); 01402 p->abouttograb = 0; 01403 } else { 01404 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n"); 01405 agent_cleanup(newlyavailable); 01406 } 01407 } else { 01408 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n"); 01409 agent_cleanup(newlyavailable); 01410 } 01411 } 01412 return 0; 01413 }
| static int check_beep | ( | struct agent_pvt * | newlyavailable, | |
| int | needlock | |||
| ) | [static] |
Definition at line 1415 of file chan_agent.c.
References agent_pvt::abouttograb, agent_pvt::agent, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, ast_channel::language, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.
Referenced by login_exec().
01416 { 01417 struct agent_pvt *p; 01418 int res=0; 01419 01420 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent); 01421 if (needlock) 01422 AST_LIST_LOCK(&agents); 01423 AST_LIST_TRAVERSE(&agents, p, list) { 01424 if (p == newlyavailable) { 01425 continue; 01426 } 01427 ast_mutex_lock(&p->lock); 01428 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) { 01429 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent); 01430 ast_mutex_unlock(&p->lock); 01431 break; 01432 } 01433 ast_mutex_unlock(&p->lock); 01434 } 01435 if (needlock) 01436 AST_LIST_UNLOCK(&agents); 01437 if (p) { 01438 ast_mutex_unlock(&newlyavailable->lock); 01439 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language); 01440 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language); 01441 ast_debug(1, "Played beep, result '%d'\n", res); 01442 if (!res) { 01443 res = ast_waitstream(newlyavailable->chan, ""); 01444 ast_debug(1, "Waited for stream, result '%d'\n", res); 01445 } 01446 ast_mutex_lock(&newlyavailable->lock); 01447 } 01448 return res; 01449 }
| static char * complete_agent_logoff_cmd | ( | const char * | line, | |
| const char * | word, | |||
| int | pos, | |||
| int | state | |||
| ) | [static] |
Definition at line 1790 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().
01791 { 01792 char *ret = NULL; 01793 01794 if (pos == 2) { 01795 struct agent_pvt *p; 01796 char name[AST_MAX_AGENT]; 01797 int which = 0, len = strlen(word); 01798 01799 AST_LIST_LOCK(&agents); 01800 AST_LIST_TRAVERSE(&agents, p, list) { 01801 snprintf(name, sizeof(name), "Agent/%s", p->agent); 01802 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) { 01803 ret = ast_strdup(name); 01804 break; 01805 } 01806 } 01807 AST_LIST_UNLOCK(&agents); 01808 } else if (pos == 3 && state == 0) 01809 return ast_strdup("soft"); 01810 01811 return ret; 01812 }
| static void dump_agents | ( | void | ) | [static] |
Dump AgentCallbackLogin agents to the ASTdb database for persistence.
Definition at line 2362 of file chan_agent.c.
References agent_pvt::agent, ast_db_del(), ast_db_put(), ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), buf, agent_pvt::chan, LOG_WARNING, agent_pvt::logincallerid, and agent_pvt::loginchan.
Referenced by agent_hangup(), and agent_logoff_maintenance().
02363 { 02364 struct agent_pvt *cur_agent = NULL; 02365 char buf[256]; 02366 02367 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02368 if (cur_agent->chan) 02369 continue; 02370 02371 if (!ast_strlen_zero(cur_agent->loginchan)) { 02372 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid); 02373 if (ast_db_put(pa_family, cur_agent->agent, buf)) 02374 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf); 02375 else 02376 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan); 02377 } else { 02378 /* Delete - no agent or there is an error */ 02379 ast_db_del(pa_family, cur_agent->agent); 02380 } 02381 } 02382 }
| static struct agent_pvt* find_agent | ( | char * | agentid | ) | [static, read] |
Definition at line 2485 of file chan_agent.c.
References agent_pvt::agent, and AST_LIST_TRAVERSE.
Referenced by function_agent().
02486 { 02487 struct agent_pvt *cur; 02488 02489 AST_LIST_TRAVERSE(&agents, cur, list) { 02490 if (!strcmp(cur->agent, agentid)) 02491 break; 02492 } 02493 02494 return cur; 02495 }
| static int function_agent | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 2497 of file chan_agent.c.
References agent_pvt::agent, AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strlen_zero(), agent_pvt::chan, find_agent(), LOG_WARNING, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, parse(), agent_pvt::password, and status.
02498 { 02499 char *parse; 02500 AST_DECLARE_APP_ARGS(args, 02501 AST_APP_ARG(agentid); 02502 AST_APP_ARG(item); 02503 ); 02504 char *tmp; 02505 struct agent_pvt *agent; 02506 02507 buf[0] = '\0'; 02508 02509 if (ast_strlen_zero(data)) { 02510 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n"); 02511 return -1; 02512 } 02513 02514 parse = ast_strdupa(data); 02515 02516 AST_NONSTANDARD_APP_ARGS(args, parse, ':'); 02517 if (!args.item) 02518 args.item = "status"; 02519 02520 AST_LIST_LOCK(&agents); 02521 02522 if (!(agent = find_agent(args.agentid))) { 02523 AST_LIST_UNLOCK(&agents); 02524 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid); 02525 return -1; 02526 } 02527 02528 if (!strcasecmp(args.item, "status")) { 02529 char *status = "LOGGEDOUT"; 02530 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 02531 status = "LOGGEDIN"; 02532 ast_copy_string(buf, status, len); 02533 } else if (!strcasecmp(args.item, "password")) 02534 ast_copy_string(buf, agent->password, len); 02535 else if (!strcasecmp(args.item, "name")) 02536 ast_copy_string(buf, agent->name, len); 02537 else if (!strcasecmp(args.item, "mohclass")) 02538 ast_copy_string(buf, agent->moh, len); 02539 else if (!strcasecmp(args.item, "channel")) { 02540 if (agent->chan) { 02541 ast_copy_string(buf, agent->chan->name, len); 02542 tmp = strrchr(buf, '-'); 02543 if (tmp) 02544 *tmp = '\0'; 02545 } 02546 } else if (!strcasecmp(args.item, "exten")) 02547 ast_copy_string(buf, agent->loginchan, len); 02548 02549 AST_LIST_UNLOCK(&agents); 02550 02551 return 0; 02552 }
| 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 2567 of file chan_agent.c.
References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().
02568 { 02569 /* Make sure we can register our agent channel type */ 02570 if (ast_channel_register(&agent_tech)) { 02571 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n"); 02572 return AST_MODULE_LOAD_FAILURE; 02573 } 02574 /* Read in the config */ 02575 if (!read_agent_config(0)) 02576 return AST_MODULE_LOAD_DECLINE; 02577 if (persistent_agents) 02578 reload_agents(); 02579 /* Dialplan applications */ 02580 ast_register_application_xml(app, login_exec); 02581 ast_register_application_xml(app3, agentmonitoroutgoing_exec); 02582 02583 /* Manager commands */ 02584 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents); 02585 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff); 02586 02587 /* CLI Commands */ 02588 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02589 02590 /* Dialplan Functions */ 02591 ast_custom_function_register(&agent_function); 02592 02593 return AST_MODULE_LOAD_SUCCESS; 02594 }
| static int login_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Log in agent application.
Called by the AgentLogin application (from the dial plan).
| chan | ||
| data |
Definition at line 1981 of file chan_agent.c.
References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_wait(), AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::name, ast_channel::nativeformats, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, ast_channel::readformat, S_OR, ast_channel::uniqueid, update_cdr, agent_pvt::wrapuptime, and ast_channel::writeformat.
Referenced by load_module().
01982 { 01983 int res=0; 01984 int tries = 0; 01985 int max_login_tries = maxlogintries; 01986 struct agent_pvt *p; 01987 struct ast_module_user *u; 01988 int login_state = 0; 01989 char user[AST_MAX_AGENT] = ""; 01990 char pass[AST_MAX_AGENT]; 01991 char agent[AST_MAX_AGENT] = ""; 01992 char xpass[AST_MAX_AGENT] = ""; 01993 char *errmsg; 01994 char *parse; 01995 AST_DECLARE_APP_ARGS(args, 01996 AST_APP_ARG(agent_id); 01997 AST_APP_ARG(options); 01998 AST_APP_ARG(extension); 01999 ); 02000 const char *tmpoptions = NULL; 02001 int play_announcement = 1; 02002 char agent_goodbye[AST_MAX_FILENAME_LEN]; 02003 int update_cdr = updatecdr; 02004 char *filename = "agent-loginok"; 02005 02006 u = ast_module_user_add(chan); 02007 02008 parse = ast_strdupa(data); 02009 02010 AST_STANDARD_APP_ARGS(args, parse); 02011 02012 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye)); 02013 02014 ast_channel_lock(chan); 02015 /* Set Channel Specific Login Overrides */ 02016 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) { 02017 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES")); 02018 if (max_login_tries < 0) 02019 max_login_tries = 0; 02020 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"); 02021 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name); 02022 } 02023 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) { 02024 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) 02025 update_cdr = 1; 02026 else 02027 update_cdr = 0; 02028 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"); 02029 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name); 02030 } 02031 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) { 02032 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE")); 02033 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"); 02034 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name); 02035 } 02036 ast_channel_unlock(chan); 02037 /* End Channel Specific Login Overrides */ 02038 02039 if (!ast_strlen_zero(args.options)) { 02040 if (strchr(args.options, 's')) { 02041 play_announcement = 0; 02042 } 02043 } 02044 02045 if (chan->_state != AST_STATE_UP) 02046 res = ast_answer(chan); 02047 if (!res) { 02048 if (!ast_strlen_zero(args.agent_id)) 02049 ast_copy_string(user, args.agent_id, AST_MAX_AGENT); 02050 else 02051 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0); 02052 } 02053 while (!res && (max_login_tries==0 || tries < max_login_tries)) { 02054 tries++; 02055 /* Check for password */ 02056 AST_LIST_LOCK(&agents); 02057 AST_LIST_TRAVERSE(&agents, p, list) { 02058 if (!strcmp(p->agent, user) && !p->pending) 02059 ast_copy_string(xpass, p->password, sizeof(xpass)); 02060 } 02061 AST_LIST_UNLOCK(&agents); 02062 if (!res) { 02063 if (!ast_strlen_zero(xpass)) 02064 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0); 02065 else 02066 pass[0] = '\0'; 02067 } 02068 errmsg = "agent-incorrect"; 02069 02070 #if 0 02071 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass); 02072 #endif 02073 02074 /* Check again for accuracy */ 02075 AST_LIST_LOCK(&agents); 02076 AST_LIST_TRAVERSE(&agents, p, list) { 02077 int unlock_channel = 1; 02078 ast_channel_lock(chan); 02079 ast_mutex_lock(&p->lock); 02080 if (!strcmp(p->agent, user) && 02081 !strcmp(p->password, pass) && !p->pending) { 02082 login_state = 1; /* Successful Login */ 02083 02084 /* Ensure we can't be gotten until we're done */ 02085 p->lastdisc = ast_tvnow(); 02086 p->lastdisc.tv_sec++; 02087 02088 /* Set Channel Specific Agent Overrides */ 02089 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) { 02090 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always")) 02091 p->ackcall = 2; 02092 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) 02093 p->ackcall = 1; 02094 else 02095 p->ackcall = 0; 02096 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL"); 02097 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent); 02098 ast_set_flag(p, AGENT_FLAG_ACKCALL); 02099 } else { 02100 p->ackcall = ackcall; 02101 } 02102 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) { 02103 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF")); 02104 if (p->autologoff < 0) 02105 p->autologoff = 0; 02106 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"); 02107 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent); 02108 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF); 02109 } else { 02110 p->autologoff = autologoff; 02111 } 02112 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) { 02113 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME")); 02114 if (p->wrapuptime < 0) 02115 p->wrapuptime = 0; 02116 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"); 02117 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent); 02118 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME); 02119 } else { 02120 p->wrapuptime = wrapuptime; 02121 } 02122 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF"); 02123 if (!ast_strlen_zero(tmpoptions)) { 02124 p->acceptdtmf = *tmpoptions; 02125 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent); 02126 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF); 02127 } 02128 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF"); 02129 if (!ast_strlen_zero(tmpoptions)) { 02130 p->enddtmf = *tmpoptions; 02131 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent); 02132 ast_set_flag(p, AGENT_FLAG_ENDDTMF); 02133 } 02134 ast_channel_unlock(chan); 02135 unlock_channel = 0; 02136 /* End Channel Specific Agent Overrides */ 02137 if (!p->chan) { 02138 long logintime; 02139 snprintf(agent, sizeof(agent), "Agent/%s", p->agent); 02140 02141 p->loginchan[0] = '\0'; 02142 p->logincallerid[0] = '\0'; 02143 p->acknowledged = 0; 02144 02145 ast_mutex_unlock(&p->lock); 02146 AST_LIST_UNLOCK(&agents); 02147 if( !res && play_announcement==1 ) 02148 res = ast_streamfile(chan, filename, chan->language); 02149 if (!res) 02150 ast_waitstream(chan, ""); 02151 AST_LIST_LOCK(&agents); 02152 ast_mutex_lock(&p->lock); 02153 if (!res) { 02154 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats)); 02155 if (res) 02156 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats)); 02157 } 02158 if (!res) { 02159 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats)); 02160 if (res) 02161 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats)); 02162 } 02163 /* Check once more just in case */ 02164 if (p->chan) 02165 res = -1; 02166 if (!res) { 02167 ast_indicate_data(chan, AST_CONTROL_HOLD, 02168 S_OR(p->moh, NULL), 02169 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0); 02170 if (p->loginstart == 0) 02171 time(&p->loginstart); 02172 manager_event(EVENT_FLAG_AGENT, "Agentlogin", 02173 "Agent: %s\r\n" 02174 "Channel: %s\r\n" 02175 "Uniqueid: %s\r\n", 02176 p->agent, chan->name, chan->uniqueid); 02177 if (update_cdr && chan->cdr) 02178 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent); 02179 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name); 02180 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent, 02181 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat)); 02182 /* Login this channel and wait for it to go away */ 02183 p->chan = chan; 02184 if (p->ackcall > 1) 02185 check_beep(p, 0); 02186 else 02187 check_availability(p, 0); 02188 ast_mutex_unlock(&p->lock); 02189 AST_LIST_UNLOCK(&agents); 02190 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02191 while (res >= 0) { 02192 ast_mutex_lock(&p->lock); 02193 if (p->deferlogoff && p->chan) { 02194 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 02195 p->deferlogoff = 0; 02196 } 02197 if (p->chan != chan) 02198 res = -1; 02199 ast_mutex_unlock(&p->lock); 02200 /* Yield here so other interested threads can kick in. */ 02201 sched_yield(); 02202 if (res) 02203 break; 02204 02205 AST_LIST_LOCK(&agents); 02206 ast_mutex_lock(&p->lock); 02207 if (p->lastdisc.tv_sec) { 02208 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) { 02209 ast_debug(1, "Wrapup time for %s expired!\n", p->agent); 02210 p->lastdisc = ast_tv(0, 0); 02211 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent); 02212 if (p->ackcall > 1) 02213 check_beep(p, 0); 02214 else 02215 check_availability(p, 0); 02216 } 02217 } 02218 ast_mutex_unlock(&p->lock); 02219 AST_LIST_UNLOCK(&agents); 02220 /* Synchronize channel ownership between call to agent and itself. */ 02221 ast_mutex_lock(&p->app_lock); 02222 if (p->app_lock_flag == 1) { 02223 ast_cond_wait(&p->app_complete_cond, &p->app_lock); 02224 } 02225 ast_mutex_unlock(&p->app_lock); 02226 ast_mutex_lock(&p->lock); 02227 ast_mutex_unlock(&p->lock); 02228 if (p->ackcall > 1) 02229 res = agent_ack_sleep(p); 02230 else 02231 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p ); 02232 if ((p->ackcall > 1) && (res == 1)) { 02233 AST_LIST_LOCK(&agents); 02234 ast_mutex_lock(&p->lock); 02235 check_availability(p, 0); 02236 ast_mutex_unlock(&p->lock); 02237 AST_LIST_UNLOCK(&agents); 02238 res = 0; 02239 } 02240 sched_yield(); 02241 } 02242 ast_mutex_lock(&p->lock); 02243 if (res && p->owner) 02244 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n"); 02245 /* Log us off if appropriate */ 02246 if (p->chan == chan) { 02247 p->chan = NULL; 02248 } 02249 p->acknowledged = 0; 02250 logintime = time(NULL) - p->loginstart; 02251 p->loginstart = 0; 02252 ast_mutex_unlock(&p->lock); 02253 manager_event(EVENT_FLAG_AGENT, "Agentlogoff", 02254 "Agent: %s\r\n" 02255 "Logintime: %ld\r\n" 02256 "Uniqueid: %s\r\n", 02257 p->agent, logintime, chan->uniqueid); 02258 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime); 02259 ast_verb(2, "Agent '%s' logged out\n", p->agent); 02260 /* If there is no owner, go ahead and kill it now */ 02261 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent); 02262 if (p->dead && !p->owner) { 02263 ast_mutex_destroy(&p->lock); 02264 ast_mutex_destroy(&p->app_lock); 02265 ast_cond_destroy(&p->app_complete_cond); 02266 ast_free(p); 02267 } 02268 } 02269 else { 02270 ast_mutex_unlock(&p->lock); 02271 p = NULL; 02272 } 02273 res = -1; 02274 } else { 02275 ast_mutex_unlock(&p->lock); 02276 errmsg = "agent-alreadyon"; 02277 p = NULL; 02278 } 02279 break; 02280 } 02281 ast_mutex_unlock(&p->lock); 02282 if (unlock_channel) { 02283 ast_channel_unlock(chan); 02284 } 02285 } 02286 if (!p) 02287 AST_LIST_UNLOCK(&agents); 02288 02289 if (!res && (max_login_tries==0 || tries < max_login_tries)) 02290 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0); 02291 } 02292 02293 if (!res) 02294 res = ast_safe_sleep(chan, 500); 02295 02296 ast_module_user_remove(u); 02297 02298 return -1; 02299 }
| static force_inline int powerof | ( | unsigned int | d | ) | [static] |
Definition at line 1547 of file chan_agent.c.
Referenced by agents_show().
| static int read_agent_config | ( | int | reload | ) | [static] |
Read configuration data. The file named agents.conf.
Definition at line 1180 of file chan_agent.c.
References add_agent(), agent_pvt::app_complete_cond, agent_pvt::app_lock, ast_category_browse(), ast_cond_destroy(), ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_get_group(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), agent_pvt::chan, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, agent_pvt::dead, agent_pvt::lock, LOG_ERROR, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.
Referenced by load_module(), and reload().
01181 { 01182 struct ast_config *cfg; 01183 struct ast_config *ucfg; 01184 struct ast_variable *v; 01185 struct agent_pvt *p; 01186 const char *general_val; 01187 const char *catname; 01188 const char *hasagent; 01189 int genhasagent; 01190 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01191 01192 group = 0; 01193 autologoff = 0; 01194 wrapuptime = 0; 01195 ackcall = 0; 01196 endcall = 1; 01197 cfg = ast_config_load(config, config_flags); 01198 if (!cfg) { 01199 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n"); 01200 return 0; 01201 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 01202 return -1; 01203 } else if (cfg == CONFIG_STATUS_FILEINVALID) { 01204 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config); 01205 return 0; 01206 } 01207 if ((ucfg = ast_config_load("users.conf", config_flags))) { 01208 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) { 01209 ucfg = NULL; 01210 } else if (ucfg == CONFIG_STATUS_FILEINVALID) { 01211 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n"); 01212 return 0; 01213 } 01214 } 01215 01216 AST_LIST_LOCK(&agents); 01217 AST_LIST_TRAVERSE(&agents, p, list) { 01218 p->dead = 1; 01219 } 01220 strcpy(moh, "default"); 01221 /* set the default recording values */ 01222 recordagentcalls = 0; 01223 strcpy(recordformat, "wav"); 01224 strcpy(recordformatext, "wav"); 01225 urlprefix[0] = '\0'; 01226 savecallsin[0] = '\0'; 01227 01228 /* Read in [general] section for persistence */ 01229 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents"))) 01230 persistent_agents = ast_true(general_val); 01231 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin")); 01232 01233 /* Read in the [agents] section */ 01234 v = ast_variable_browse(cfg, "agents"); 01235 while(v) { 01236 /* Create the interface list */ 01237 if (!strcasecmp(v->name, "agent")) { 01238 add_agent(v->value, 0); 01239 } else if (!strcasecmp(v->name, "group")) { 01240 group = ast_get_group(v->value); 01241 } else if (!strcasecmp(v->name, "autologoff")) { 01242 autologoff = atoi(v->value); 01243 if (autologoff < 0) 01244 autologoff = 0; 01245 } else if (!strcasecmp(v->name, "ackcall")) { 01246 if (!strcasecmp(v->value, "always")) 01247 ackcall = 2; 01248 else if (ast_true(v->value)) 01249 ackcall = 1; 01250 else 01251 ackcall = 0; 01252 } else if (!strcasecmp(v->name, "endcall")) { 01253 endcall = ast_true(v->value); 01254 } else if (!strcasecmp(v->name, "acceptdtmf")) { 01255 acceptdtmf = *(v->value); 01256 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf); 01257 } else if (!strcasecmp(v->name, "enddtmf")) { 01258 enddtmf = *(v->value); 01259 } else if (!strcasecmp(v->name, "wrapuptime")) { 01260 wrapuptime = atoi(v->value); 01261 if (wrapuptime < 0) 01262 wrapuptime = 0; 01263 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) { 01264 maxlogintries = atoi(v->value); 01265 if (maxlogintries < 0) 01266 maxlogintries = 0; 01267 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) { 01268 strcpy(agentgoodbye,v->value); 01269 } else if (!strcasecmp(v->name, "musiconhold")) { 01270 ast_copy_string(moh, v->value, sizeof(moh)); 01271 } else if (!strcasecmp(v->name, "updatecdr")) { 01272 if (ast_true(v->value)) 01273 updatecdr = 1; 01274 else 01275 updatecdr = 0; 01276 } else if (!strcasecmp(v->name, "autologoffunavail")) { 01277 if (ast_true(v->value)) 01278 autologoffunavail = 1; 01279 else 01280 autologoffunavail = 0; 01281 } else if (!strcasecmp(v->name, "recordagentcalls")) { 01282 recordagentcalls = ast_true(v->value); 01283 } else if (!strcasecmp(v->name, "recordformat")) { 01284 ast_copy_string(recordformat, v->value, sizeof(recordformat)); 01285 if (!strcasecmp(v->value, "wav49")) 01286 strcpy(recordformatext, "WAV"); 01287 else 01288 ast_copy_string(recordformatext, v->value, sizeof(recordformatext)); 01289 } else if (!strcasecmp(v->name, "urlprefix")) { 01290 ast_copy_string(urlprefix, v->value, sizeof(urlprefix)); 01291 if (urlprefix[strlen(urlprefix) - 1] != '/') 01292 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1); 01293 } else if (!strcasecmp(v->name, "savecallsin")) { 01294 if (v->value[0] == '/') 01295 ast_copy_string(savecallsin, v->value, sizeof(savecallsin)); 01296 else 01297 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value); 01298 if (savecallsin[strlen(savecallsin) - 1] != '/') 01299 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1); 01300 } else if (!strcasecmp(v->name, "custom_beep")) { 01301 ast_copy_string(beep, v->value, sizeof(beep)); 01302 } 01303 v = v->next; 01304 } 01305 if (ucfg) { 01306 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent")); 01307 catname = ast_category_browse(ucfg, NULL); 01308 while(catname) { 01309 if (strcasecmp(catname, "general")) { 01310 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent"); 01311 if (ast_true(hasagent) || (!hasagent && genhasagent)) { 01312 char tmp[256]; 01313 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname"); 01314 const char *secret = ast_variable_retrieve(ucfg, catname, "secret"); 01315 if (!fullname) 01316 fullname = ""; 01317 if (!secret) 01318 secret = ""; 01319 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname); 01320 add_agent(tmp, 0); 01321 } 01322 } 01323 catname = ast_category_browse(ucfg, catname); 01324 } 01325 ast_config_destroy(ucfg); 01326 } 01327 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) { 01328 if (p->dead) { 01329 AST_LIST_REMOVE_CURRENT(list); 01330 /* Destroy if appropriate */ 01331 if (!p->owner) { 01332 if (!p->chan) { 01333 ast_mutex_destroy(&p->lock); 01334 ast_mutex_destroy(&p->app_lock); 01335 ast_cond_destroy(&p->app_complete_cond); 01336 ast_free(p); 01337 } else { 01338 /* Cause them to hang up */ 01339 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT); 01340 } 01341 } 01342 } 01343 } 01344 AST_LIST_TRAVERSE_SAFE_END; 01345 AST_LIST_UNLOCK(&agents); 01346 ast_config_destroy(cfg); 01347 return 1; 01348 }
| static int reload | ( | void | ) | [static] |
Definition at line 2596 of file chan_agent.c.
References read_agent_config(), and reload_agents().
02597 { 02598 if (!read_agent_config(1)) { 02599 if (persistent_agents) 02600 reload_agents(); 02601 } 02602 return 0; 02603 }
| static void reload_agents | ( | void | ) | [static] |
Reload the persistent agents from astdb.
Definition at line 2387 of file chan_agent.c.
References agent_pvt::agent, ast_copy_string(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, AST_DEVICE_UNKNOWN, ast_devstate_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::lock, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, ast_db_entry::next, parse(), and set_agentbycallerid().
Referenced by load_module(), and reload().
02388 { 02389 char *agent_num; 02390 struct ast_db_entry *db_tree; 02391 struct ast_db_entry *entry; 02392 struct agent_pvt *cur_agent; 02393 char agent_data[256]; 02394 char *parse; 02395 char *agent_chan; 02396 char *agent_callerid; 02397 02398 db_tree = ast_db_gettree(pa_family, NULL); 02399 02400 AST_LIST_LOCK(&agents); 02401 for (entry = db_tree; entry; entry = entry->next) { 02402 agent_num = entry->key + strlen(pa_family) + 2; 02403 AST_LIST_TRAVERSE(&agents, cur_agent, list) { 02404 ast_mutex_lock(&cur_agent->lock); 02405 if (strcmp(agent_num, cur_agent->agent) == 0) 02406 break; 02407 ast_mutex_unlock(&cur_agent->lock); 02408 } 02409 if (!cur_agent) { 02410 ast_db_del(pa_family, agent_num); 02411 continue; 02412 } else 02413 ast_mutex_unlock(&cur_agent->lock); 02414 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) { 02415 ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data); 02416 parse = agent_data; 02417 agent_chan = strsep(&parse, ";"); 02418 agent_callerid = strsep(&parse, ";"); 02419 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan)); 02420 if (agent_callerid) { 02421 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid)); 02422 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent); 02423 } else 02424 cur_agent->logincallerid[0] = '\0'; 02425 if (cur_agent->loginstart == 0) 02426 time(&cur_agent->loginstart); 02427 ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 02428 } 02429 } 02430 AST_LIST_UNLOCK(&agents); 02431 if (db_tree) { 02432 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n"); 02433 ast_db_freetree(db_tree); 02434 } 02435 }
| static void set_agentbycallerid | ( | const char * | callerid, | |
| const char * | agent | |||
| ) | [static] |
store/clear the global variable that stores agentid based on the callerid
Definition at line 847 of file chan_agent.c.
References AST_MAX_BUF, ast_strlen_zero(), buf, GETAGENTBYCALLERID, and pbx_builtin_setvar_helper().
Referenced by agent_logoff_maintenance(), and reload_agents().
00848 { 00849 char buf[AST_MAX_BUF]; 00850 00851 /* if there is no Caller ID, nothing to do */ 00852 if (ast_strlen_zero(callerid)) 00853 return; 00854 00855 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid); 00856 pbx_builtin_setvar_helper(NULL, buf, agent); 00857 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 2605 of file chan_agent.c.
References agent_function, agent_tech, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), cli_agents, and agent_pvt::owner.
02606 { 02607 struct agent_pvt *p; 02608 /* First, take us out of the channel loop */ 02609 ast_channel_unregister(&agent_tech); 02610 /* Unregister dialplan functions */ 02611 ast_custom_function_unregister(&agent_function); 02612 /* Unregister CLI commands */ 02613 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents)); 02614 /* Unregister dialplan applications */ 02615 ast_unregister_application(app); 02616 ast_unregister_application(app3); 02617 /* Unregister manager command */ 02618 ast_manager_unregister("Agents"); 02619 ast_manager_unregister("AgentLogoff"); 02620 /* Unregister channel */ 02621 AST_LIST_LOCK(&agents); 02622 /* Hangup all interfaces if they have an owner */ 02623 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) { 02624 if (p->owner) 02625 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); 02626 ast_free(p); 02627 } 02628 AST_LIST_UNLOCK(&agents); 02629 return 0; 02630 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 2636 of file chan_agent.c.
char acceptdtmf = DEFAULT_ACCEPTDTMF [static] |
Definition at line 211 of file chan_agent.c.
Referenced by play_record_review().
int ackcall [static] |
Definition at line 207 of file chan_agent.c.
{
.name = "AGENT",
.read = function_agent,
}
Definition at line 2554 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char agent_logoff_usage[] [static] |
"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 1960 of file chan_agent.c.
struct ast_channel_tech agent_tech [static] |
Channel interface description for PBX integration.
Definition at line 325 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 215 of file chan_agent.c.
const char app[] = "AgentLogin" [static] |
Definition at line 176 of file chan_agent.c.
const char app3[] = "AgentMonitorOutgoing" [static] |
Definition at line 177 of file chan_agent.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2636 of file chan_agent.c.
int autologoff [static] |
Definition at line 205 of file chan_agent.c.
int autologoffunavail = 0 [static] |
Definition at line 210 of file chan_agent.c.
char beep[AST_MAX_BUF] = "beep" [static] |
Definition at line 223 of file chan_agent.c.
struct ast_cli_entry cli_agents[] [static] |
{
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 1965 of file chan_agent.c.
Referenced by load_module(), and unload_module().
const char config[] = "agents.conf" [static] |
Definition at line 174 of file chan_agent.c.
int endcall [static] |
Definition at line 208 of file chan_agent.c.
char enddtmf = DEFAULT_ENDDTMF [static] |
Definition at line 212 of file chan_agent.c.
ast_group_t group [static] |
Definition at line 204 of file chan_agent.c.
const char mandescr_agent_logoff[] [static] |
"Description: Sets an agent as no longer logged in.\n" "Variables: (Names marked with * are required)\n" " *Agent: Agent ID of the agent to log off\n" " Soft: Set to 'true' to not hangup existing calls\n"
Definition at line 183 of file chan_agent.c.
const char mandescr_agents[] [static] |
"Description: Will list info about all possible agents.\n" "Variables: NONE\n"
Definition at line 179 of file chan_agent.c.
int maxlogintries = 3 [static] |
Definition at line 214 of file chan_agent.c.
char moh[80] = "default" [static] |
Definition at line 189 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 209 of file chan_agent.c.
const char pa_family[] = "Agents" [static] |
Persistent Agents astdb family
Definition at line 195 of file chan_agent.c.
int persistent_agents = 0 [static] |
queues.conf [general] option
Definition at line 198 of file chan_agent.c.
int recordagentcalls = 0 [static] |
Definition at line 217 of file chan_agent.c.
char recordformat[AST_MAX_BUF] = "" [static] |
Definition at line 218 of file chan_agent.c.
char recordformatext[AST_MAX_BUF] = "" [static] |
Definition at line 219 of file chan_agent.c.
char savecallsin[AST_MAX_BUF] = "" [static] |
Definition at line 221 of file chan_agent.c.
const char tdesc[] = "Call Agent Proxy Channel" [static] |
Definition at line 173 of file chan_agent.c.
int updatecdr = 0 [static] |
Definition at line 222 of file chan_agent.c.
char urlprefix[AST_MAX_BUF] = "" [static] |
Definition at line 220 of file chan_agent.c.
Referenced by start_monitor_exec().
int wrapuptime [static] |
Definition at line 206 of file chan_agent.c.
1.6.2