Mon Aug 31 12:30:22 2015

Asterisk developer's documentation


chan_agent.c File Reference

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/acl.h"
#include "asterisk/callerid.h"
#include "asterisk/file.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/manager.h"
#include "asterisk/features.h"
#include "asterisk/utils.h"
#include "asterisk/causes.h"
#include "asterisk/astdb.h"
#include "asterisk/devicestate.h"
#include "asterisk/monitor.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"
#include "asterisk/data.h"

Go to the source code of this file.

Data Structures

struct  agent_pvt
 Structure representing an agent. More...

Defines

#define AST_MAX_AGENT   80
#define AST_MAX_BUF   256
#define AST_MAX_FILENAME_LEN   256
#define CHECK_FORMATS(ast, p)
#define CLEANUP(ast, p)
 Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
#define DATA_EXPORT_AGENT(MEMBER)
#define DEFAULT_ACCEPTDTMF   '#'
#define DEFAULT_ENDDTMF   '*'
#define GETAGENTBYCALLERID   "AGENTBYCALLERID"
#define PA_MAX_LEN   2048

Enumerations

enum  {
  AGENT_FLAG_ACKCALL = (1 << 0), AGENT_FLAG_AUTOLOGOFF = (1 << 1), AGENT_FLAG_WRAPUPTIME = (1 << 2), AGENT_FLAG_ACCEPTDTMF = (1 << 3),
  AGENT_FLAG_ENDDTMF = (1 << 4)
}

Functions

static int __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static 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_pvtadd_agent (const char *agent, int pending)
static int agent_ack_sleep (struct agent_pvt *p)
static int agent_answer (struct ast_channel *ast)
static struct ast_channelagent_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_channelagent_get_base_channel (struct ast_channel *chan)
 return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
static int agent_hangup (struct ast_channel *ast)
static int agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
static struct ast_channelagent_lock_owner (struct agent_pvt *pvt)
 Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed.
static int agent_logoff (const char *agent, int soft)
static char * agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_channelagent_new (struct agent_pvt *p, int state, const char *linkedid)
 Create new agent channel.
static void agent_pvt_destroy (struct agent_pvt *doomed)
static struct ast_frameagent_read (struct ast_channel *ast)
static struct ast_channelagent_request (const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause)
 Part of the Asterisk PBX interface.
static int agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int agent_sendtext (struct ast_channel *ast, const char *text)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, const char *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static int agents_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static char * agents_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * agents_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 AST_DATA_STRUCTURE (agent_pvt, DATA_EXPORT_AGENT)
static AST_LIST_HEAD_STATIC (agents, agent_pvt)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DRIVER,.nonoptreq="res_monitor,chan_local",)
static int check_availability (struct agent_pvt *newlyavailable, int needlock)
static int check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state)
static struct agent_pvtfind_agent (char *agentid)
static int function_agent (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int load_module (void)
 Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.
static int login_exec (struct ast_channel *chan, const char *data)
 Log in agent application.
static force_inline int powerof (unsigned int d)
static int read_agent_config (int reload)
static int reload (void)
static int unload_module (void)

Variables

static char acceptdtmf = DEFAULT_ACCEPTDTMF
static int ackcall
static struct ast_custom_function agent_function
static const char agent_logoff_usage []
static struct ast_channel_tech agent_tech
 Channel interface description for PBX integration.
static char agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static struct ast_data_handler agents_data_provider
static struct ast_data_entry agents_data_providers []
static const char app [] = "AgentLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static const char config [] = "agents.conf"
static int endcall
static char enddtmf = DEFAULT_ENDDTMF
static ast_group_t group
static int maxlogintries = 3
static char moh [80] = "default"
static const char pa_family [] = "Agents"
static int recordagentcalls = 0
static char recordformat [AST_MAX_BUF] = ""
static char recordformatext [AST_MAX_BUF] = ""
static char savecallsin [AST_MAX_BUF] = ""
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int wrapuptime

Detailed Description

Implementation of Agents (proxy channel).

Author:
Mark Spencer <markster@digium.com>

This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.

See also

Definition in file chan_agent.c.


Define Documentation

#define AST_MAX_AGENT   80

Agent ID or Password max length

Definition at line 211 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec(), complete_agent_logoff_cmd(), and login_exec().

#define AST_MAX_BUF   256
#define AST_MAX_FILENAME_LEN   256

Definition at line 213 of file chan_agent.c.

Referenced by login_exec().

#define CHECK_FORMATS ( ast,
 ) 

Definition at line 296 of file chan_agent.c.

Referenced by agent_read(), and agent_write().

#define CLEANUP ( ast,
 ) 

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 318 of file chan_agent.c.

Referenced by agent_call(), agent_read(), and agent_write().

#define DATA_EXPORT_AGENT ( MEMBER   ) 

Definition at line 282 of file chan_agent.c.

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 218 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 219 of file chan_agent.c.

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 241 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec().

#define PA_MAX_LEN   2048

The maximum length of each persistent member agent database entry

Definition at line 216 of file chan_agent.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
AGENT_FLAG_ACKCALL 
AGENT_FLAG_AUTOLOGOFF 
AGENT_FLAG_WRAPUPTIME 
AGENT_FLAG_ACCEPTDTMF 
AGENT_FLAG_ENDDTMF 

Definition at line 243 of file chan_agent.c.

00243      {
00244    AGENT_FLAG_ACKCALL = (1 << 0),
00245    AGENT_FLAG_AUTOLOGOFF = (1 << 1),
00246    AGENT_FLAG_WRAPUPTIME = (1 << 2),
00247    AGENT_FLAG_ACCEPTDTMF = (1 << 3),
00248    AGENT_FLAG_ENDDTMF = (1 << 4),
00249 };


Function Documentation

static int __agent_start_monitoring ( struct ast_channel ast,
struct agent_pvt p,
int  needlock 
) [static]

Definition at line 574 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, X_REC_IN, and X_REC_OUT.

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

00575 {
00576    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00577    char filename[AST_MAX_BUF];
00578    int res = -1;
00579    if (!p)
00580       return -1;
00581    if (!ast->monitor) {
00582       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00583       /* substitute . for - */
00584       if ((pointer = strchr(filename, '.')))
00585          *pointer = '-';
00586       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00587       ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
00588       ast_monitor_setjoinfiles(ast, 1);
00589       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00590 #if 0
00591       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00592 #endif
00593       if (!ast->cdr)
00594          ast->cdr = ast_cdr_alloc();
00595       ast_cdr_setuserfield(ast, tmp2);
00596       res = 0;
00597    } else
00598       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00599    return res;
00600 }

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.

Parameters:
s 
m 
Returns:
See also:
action_agents(), load_module().

Definition at line 1653 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().

01654 {
01655    const char *agent = astman_get_header(m, "Agent");
01656    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01657    int soft;
01658    int ret; /* return value of agent_logoff */
01659 
01660    if (ast_strlen_zero(agent)) {
01661       astman_send_error(s, m, "No agent specified");
01662       return 0;
01663    }
01664 
01665    soft = ast_true(soft_s) ? 1 : 0;
01666    ret = agent_logoff(agent, soft);
01667    if (ret == 0)
01668       astman_send_ack(s, m, "Agent logged out");
01669    else
01670       astman_send_error(s, m, "No such agent");
01671 
01672    return 0;
01673 }

static int action_agents ( struct mansession s,
const struct message m 
) [static]

Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend. This function locks both the pvt and the channel that owns it for a while, but does not keep these locks.

Parameters:
s 
m 
Returns:
See also:
action_agent_logoff(), load_module().

Definition at line 1494 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::agent, agent_lock_owner(), ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::bridge, ast_channel::caller, agent_pvt::chan, ast_party_caller::id, agent_pvt::lock, agent_pvt::loginstart, agent_pvt::name, ast_party_id::number, agent_pvt::owner, S_COR, S_OR, status, ast_party_number::str, and ast_party_number::valid.

Referenced by load_module().

01495 {
01496    const char *id = astman_get_header(m,"ActionID");
01497    char idText[256] = "";
01498    struct agent_pvt *p;
01499    char *username = NULL;
01500    char *loginChan = NULL;
01501    char *talkingto = NULL;
01502    char *talkingtoChan = NULL;
01503    char *status = NULL;
01504    struct ast_channel *bridge;
01505 
01506    if (!ast_strlen_zero(id))
01507       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01508    astman_send_ack(s, m, "Agents will follow");
01509    AST_LIST_LOCK(&agents);
01510    AST_LIST_TRAVERSE(&agents, p, list) {
01511       struct ast_channel *owner;
01512       ast_mutex_lock(&p->lock);
01513       owner = agent_lock_owner(p);
01514 
01515       /* Status Values:
01516          AGENT_LOGGEDOFF - Agent isn't logged in
01517          AGENT_IDLE      - Agent is logged in, and waiting for call
01518          AGENT_ONCALL    - Agent is logged in, and on a call
01519          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01520 
01521       username = S_OR(p->name, "None");
01522 
01523       /* Set a default status. It 'should' get changed. */
01524       status = "AGENT_UNKNOWN";
01525 
01526       if (p->chan) {
01527          loginChan = ast_strdupa(p->chan->name);
01528          if (owner && owner->_bridge) {
01529             talkingto = S_COR(p->chan->caller.id.number.valid,
01530                p->chan->caller.id.number.str, "n/a");
01531             if ((bridge = ast_bridged_channel(owner))) {
01532                talkingtoChan = ast_strdupa(bridge->name);
01533             } else {
01534                talkingtoChan = "n/a";
01535             }
01536             status = "AGENT_ONCALL";
01537          } else {
01538             talkingto = "n/a";
01539             talkingtoChan = "n/a";
01540             status = "AGENT_IDLE";
01541          }
01542       } else {
01543          loginChan = "n/a";
01544          talkingto = "n/a";
01545          talkingtoChan = "n/a";
01546          status = "AGENT_LOGGEDOFF";
01547       }
01548 
01549       if (owner) {
01550          ast_channel_unlock(owner);
01551          owner = ast_channel_unref(owner);
01552       }
01553 
01554       astman_append(s, "Event: Agents\r\n"
01555          "Agent: %s\r\n"
01556          "Name: %s\r\n"
01557          "Status: %s\r\n"
01558          "LoggedInChan: %s\r\n"
01559          "LoggedInTime: %d\r\n"
01560          "TalkingTo: %s\r\n"
01561          "TalkingToChan: %s\r\n"
01562          "%s"
01563          "\r\n",
01564          p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
01565       ast_mutex_unlock(&p->lock);
01566    }
01567    AST_LIST_UNLOCK(&agents);
01568    astman_append(s, "Event: AgentsComplete\r\n"
01569       "%s"
01570       "\r\n",idText);
01571    return 0;
01572 }

static struct agent_pvt* add_agent ( const char *  agent,
int  pending 
) [static, read]

Adds an agent to the global list of agents.

Parameters:
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.
Returns:
The just created agent.
See also:
agent_pvt, agents.

Definition at line 433 of file chan_agent.c.

References agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::agent, AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, args, AST_APP_ARG, ast_calloc, ast_cond_init, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_tvnow(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::enddtmf, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

00434 {
00435    char *parse;
00436    AST_DECLARE_APP_ARGS(args,
00437       AST_APP_ARG(agt);
00438       AST_APP_ARG(password);
00439       AST_APP_ARG(name);
00440    );
00441    char *password = NULL;
00442    char *name = NULL;
00443    char *agt = NULL;
00444    struct agent_pvt *p;
00445 
00446    parse = ast_strdupa(agent);
00447 
00448    /* Extract username (agt), password and name from agent (args). */
00449    AST_STANDARD_APP_ARGS(args, parse);
00450 
00451    if(args.argc == 0) {
00452       ast_log(LOG_WARNING, "A blank agent line!\n");
00453       return NULL;
00454    }
00455 
00456    if(ast_strlen_zero(args.agt) ) {
00457       ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00458       return NULL;
00459    } else
00460       agt = args.agt;
00461 
00462    if(!ast_strlen_zero(args.password)) {
00463       password = args.password;
00464       while (*password && *password < 33) password++;
00465    }
00466    if(!ast_strlen_zero(args.name)) {
00467       name = args.name;
00468       while (*name && *name < 33) name++;
00469    }
00470 
00471    if (!pending) {
00472       /* Are we searching for the agent here ? To see if it exists already ? */
00473       AST_LIST_TRAVERSE(&agents, p, list) {
00474          if (!strcmp(p->agent, agt)) {
00475             break;
00476          }
00477       }
00478    } else {
00479       p = NULL;
00480    }
00481    if (!p) {
00482       // Build the agent.
00483       if (!(p = ast_calloc(1, sizeof(*p))))
00484          return NULL;
00485       ast_copy_string(p->agent, agt, sizeof(p->agent));
00486       ast_mutex_init(&p->lock);
00487       ast_cond_init(&p->app_complete_cond, NULL);
00488       ast_cond_init(&p->login_wait_cond, NULL);
00489       p->app_lock_flag = 0;
00490       p->app_sleep_cond = 1;
00491       p->group = group;
00492       p->pending = pending;
00493       AST_LIST_INSERT_TAIL(&agents, p, list);
00494    }
00495    
00496    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00497    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00498    ast_copy_string(p->moh, moh, sizeof(p->moh));
00499    if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) {
00500       p->ackcall = ackcall;
00501    }
00502    if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) {
00503       p->autologoff = autologoff;
00504    }
00505    if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) {
00506       p->acceptdtmf = acceptdtmf;
00507    }
00508    if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) {
00509       p->enddtmf = enddtmf;
00510    }
00511 
00512    /* If someone reduces the wrapuptime and reloads, we want it
00513     * to change the wrapuptime immediately on all calls */
00514    if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) {
00515       struct timeval now = ast_tvnow();
00516       /* XXX check what is this exactly */
00517 
00518       /* We won't be pedantic and check the tv_usec val */
00519       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00520          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00521          p->lastdisc.tv_usec = now.tv_usec;
00522       }
00523    }
00524    p->wrapuptime = wrapuptime;
00525 
00526    if (pending)
00527       p->dead = 1;
00528    else
00529       p->dead = 0;
00530    return p;
00531 }

static int agent_ack_sleep ( struct agent_pvt p  )  [static]

Definition at line 999 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_remaining_ms(), ast_tvdiff_ms(), ast_tvnow(), ast_waitfor(), agent_pvt::chan, f, ast_frame::frametype, ast_frame_subclass::integer, agent_pvt::lastdisc, agent_pvt::lock, and ast_frame::subclass.

Referenced by login_exec().

01000 {
01001    int digit;
01002    int to = 1000;
01003    struct ast_frame *f;
01004    struct timeval start = ast_tvnow();
01005    int ms;
01006 
01007    /* Wait a second and look for something */
01008    while ((ms = ast_remaining_ms(start, to))) {
01009       ms = ast_waitfor(p->chan, ms);
01010       if (ms < 0) {
01011          return -1;
01012       }
01013       if (ms == 0) {
01014          return 0;
01015       }
01016       f = ast_read(p->chan);
01017       if (!f) {
01018          return -1;
01019       }
01020       if (f->frametype == AST_FRAME_DTMF) {
01021          digit = f->subclass.integer;
01022       } else {
01023          digit = 0;
01024       }
01025       ast_frfree(f);
01026       ast_mutex_lock(&p->lock);
01027       if (!p->app_sleep_cond) {
01028          ast_mutex_unlock(&p->lock);
01029          return 0;
01030       }
01031       if (digit == p->acceptdtmf) {
01032          ast_mutex_unlock(&p->lock);
01033          return 1;
01034       }
01035       if (p->lastdisc.tv_sec) {
01036          if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
01037             ast_mutex_unlock(&p->lock);
01038             return 0;
01039          }
01040       }
01041       ast_mutex_unlock(&p->lock);
01042    }
01043    return 0;
01044 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 568 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00569 {
00570    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00571    return -1;
00572 }

static struct ast_channel * agent_bridgedchannel ( struct ast_channel chan,
struct ast_channel bridge 
) [static, read]

Definition at line 1046 of file chan_agent.c.

References ast_channel::_bridge, ast_debug, agent_pvt::chan, and ast_channel::tech_pvt.

01047 {
01048    struct agent_pvt *p = bridge->tech_pvt;
01049    struct ast_channel *ret = NULL;
01050 
01051    if (p) {
01052       if (chan == p->chan)
01053          ret = bridge->_bridge;
01054       else if (chan == bridge->_bridge)
01055          ret = p->chan;
01056    }
01057 
01058    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01059    return ret;
01060 }

static int agent_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

Definition at line 829 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_assert, ast_best_codec(), ast_debug, ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_verb, ast_waitstream(), agent_pvt::chan, CLEANUP, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.

00830 {
00831    struct agent_pvt *p = ast->tech_pvt;
00832    int res;
00833    int newstate=0;
00834 
00835    ast_mutex_lock(&p->lock);
00836    p->acknowledged = 0;
00837 
00838    if (p->pending) {
00839       ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00840       ast_mutex_unlock(&p->lock);
00841       ast_setstate(ast, AST_STATE_DIALING);
00842       return 0;
00843    }
00844 
00845    ast_assert(p->chan != NULL);
00846    ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00847    ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
00848 
00849    ast_mutex_unlock(&p->lock);
00850 
00851    res = ast_streamfile(p->chan, beep, p->chan->language);
00852    ast_debug(3, "Played beep, result '%d'\n", res);
00853    if (!res) {
00854       res = ast_waitstream(p->chan, "");
00855       ast_debug(3, "Waited for stream, result '%d'\n", res);
00856    }
00857    
00858    ast_mutex_lock(&p->lock);
00859 
00860    if (!res) {
00861       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00862       ast_debug(3, "Set read format, result '%d'\n", res);
00863       if (res)
00864          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00865    }
00866 
00867    if (!res) {
00868       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00869       ast_debug(3, "Set write format, result '%d'\n", res);
00870       if (res)
00871          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00872    }
00873    if(!res) {
00874       /* Call is immediately up, or might need ack */
00875       if (p->ackcall) {
00876          newstate = AST_STATE_RINGING;
00877       } else {
00878          newstate = AST_STATE_UP;
00879          if (recordagentcalls)
00880             agent_start_monitoring(ast, 0);
00881          p->acknowledged = 1;
00882       }
00883    }
00884    CLEANUP(ast, p);
00885    ast_mutex_unlock(&p->lock);
00886    if (newstate)
00887       ast_setstate(ast, newstate);
00888    return res ? -1 : 0;
00889 }

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.

Warning:
XXX This function seems to be very unsafe. Potential for double free and use after free among other problems.
Parameters:
p Agent to be deleted.
Returns:
Always 0.

Definition at line 544 of file chan_agent.c.

References agent_pvt_destroy(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_release(), ast_cond_signal, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

00545 {
00546    struct ast_channel *chan;
00547 
00548    ast_mutex_lock(&p->lock);
00549    chan = p->owner;
00550    p->owner = NULL;
00551    /* Release ownership of the agent to other threads (presumably running the login app). */
00552    p->app_sleep_cond = 1;
00553    p->app_lock_flag = 0;
00554    ast_cond_signal(&p->app_complete_cond);
00555    if (chan) {
00556       chan->tech_pvt = NULL;
00557       chan = ast_channel_release(chan);
00558    }
00559    if (p->dead) {
00560       ast_mutex_unlock(&p->lock);
00561       agent_pvt_destroy(p);
00562    } else {
00563       ast_mutex_unlock(&p->lock);
00564    }
00565    return 0;
00566 }

static int agent_cont_sleep ( void *  data  )  [static]

Definition at line 976 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().

00977 {
00978    struct agent_pvt *p;
00979    int res;
00980 
00981    p = (struct agent_pvt *) data;
00982 
00983    ast_mutex_lock(&p->lock);
00984    res = p->app_sleep_cond;
00985    if (res && p->lastdisc.tv_sec) {
00986       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
00987          res = 0;
00988       }
00989    }
00990    ast_mutex_unlock(&p->lock);
00991 
00992    if (!res) {
00993       ast_debug(5, "agent_cont_sleep() returning %d\n", res);
00994    }
00995 
00996    return res;
00997 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2252 of file chan_agent.c.

References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::deferlogoff, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.

02253 {
02254    struct agent_pvt *p;
02255    const char *device = data;
02256    int res = AST_DEVICE_INVALID;
02257 
02258    if (device[0] == '@' || device[0] == ':') {
02259       /* Device state of groups not supported. */
02260       return AST_DEVICE_INVALID;
02261    }
02262 
02263    /* Want device state of a specific agent. */
02264    AST_LIST_LOCK(&agents);
02265    AST_LIST_TRAVERSE(&agents, p, list) {
02266       ast_mutex_lock(&p->lock);
02267       if (!p->pending && !strcmp(device, p->agent)) {
02268          if (p->owner) {
02269             res = AST_DEVICE_BUSY;
02270          } else if (p->chan) {
02271             if (p->lastdisc.tv_sec || p->deferlogoff) {
02272                /* Agent is in wrapup time so unavailable for another call. */
02273                res = AST_DEVICE_INUSE;
02274             } else {
02275                res = AST_DEVICE_NOT_INUSE;
02276             }
02277          } else {
02278             res = AST_DEVICE_UNAVAILABLE;
02279          }
02280          ast_mutex_unlock(&p->lock);
02281          break;
02282       }
02283       ast_mutex_unlock(&p->lock);
02284    }
02285    AST_LIST_UNLOCK(&agents);
02286    return res;
02287 }

static int agent_digit_begin ( struct ast_channel ast,
char  digit 
) [static]

Definition at line 807 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.

00808 {
00809    struct agent_pvt *p = ast->tech_pvt;
00810    ast_mutex_lock(&p->lock);
00811    if (p->chan) {
00812       ast_senddigit_begin(p->chan, digit);
00813    }
00814    ast_mutex_unlock(&p->lock);
00815    return 0;
00816 }

static int agent_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 818 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.

00819 {
00820    struct agent_pvt *p = ast->tech_pvt;
00821    ast_mutex_lock(&p->lock);
00822    if (p->chan) {
00823       ast_senddigit_end(p->chan, digit, duration);
00824    }
00825    ast_mutex_unlock(&p->lock);
00826    return 0;
00827 }

static int agent_fixup ( struct ast_channel oldchan,
struct ast_channel newchan 
) [static]

Definition at line 773 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.

00774 {
00775    struct agent_pvt *p = newchan->tech_pvt;
00776    ast_mutex_lock(&p->lock);
00777    if (p->owner != oldchan) {
00778       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00779       ast_mutex_unlock(&p->lock);
00780       return -1;
00781    }
00782    p->owner = newchan;
00783    ast_mutex_unlock(&p->lock);
00784    return 0;
00785 }

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 892 of file chan_agent.c.

References ast_log(), agent_pvt::chan, LOG_ERROR, and ast_channel::tech_pvt.

00893 {
00894    struct agent_pvt *p;
00895    struct ast_channel *base = chan;
00896 
00897    /* chan is locked by the calling function */
00898    if (!chan || !chan->tech_pvt) {
00899       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);
00900       return NULL;
00901    }
00902    p = chan->tech_pvt;
00903    if (p->chan) 
00904       base = p->chan;
00905    return base;
00906 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 908 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt_destroy(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_ref, ast_channel_unref, ast_cond_signal, AST_CONTROL_HOLD, ast_debug, ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), ast_strdupa, ast_strlen_zero(), ast_tvadd(), ast_tvnow(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::owner, agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.

00909 {
00910    struct agent_pvt *p = ast->tech_pvt;
00911    struct ast_channel *indicate_chan = NULL;
00912    char *tmp_moh; /* moh buffer for indicating after unlocking p */
00913 
00914    if (p->pending) {
00915       AST_LIST_LOCK(&agents);
00916       AST_LIST_REMOVE(&agents, p, list);
00917       AST_LIST_UNLOCK(&agents);
00918    }
00919 
00920    ast_mutex_lock(&p->lock);
00921    p->owner = NULL;
00922    ast->tech_pvt = NULL;
00923    p->acknowledged = 0;
00924 
00925    /* if they really are hung up then set start to 0 so the test
00926     * later if we're called on an already downed channel
00927     * doesn't cause an agent to be logged out like when
00928     * agent_request() is followed immediately by agent_hangup()
00929     * as in apps/app_chanisavail.c:chanavail_exec()
00930     */
00931 
00932    ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
00933    p->start = 0;
00934    if (p->chan) {
00935       p->chan->_bridge = NULL;
00936       /* If they're dead, go ahead and hang up on the agent now */
00937       if (p->dead) {
00938          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00939       } else if (p->loginstart) {
00940          indicate_chan = ast_channel_ref(p->chan);
00941          tmp_moh = ast_strdupa(p->moh);
00942       }
00943    }
00944    ast_mutex_unlock(&p->lock);
00945 
00946    if (indicate_chan) {
00947       ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
00948          S_OR(tmp_moh, NULL),
00949          !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
00950       indicate_chan = ast_channel_unref(indicate_chan);
00951    }
00952 
00953    ast_mutex_lock(&p->lock);
00954    if (p->abouttograb) {
00955       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00956          kill it later */
00957       p->abouttograb = 0;
00958    } else if (p->dead) {
00959       ast_mutex_unlock(&p->lock);
00960       agent_pvt_destroy(p);
00961       return 0;
00962    } else {
00963       /* Store last disconnect time */
00964       p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00965    }
00966 
00967    /* Release ownership of the agent to other threads (presumably running the login app). */
00968    p->app_sleep_cond = 1;
00969    p->app_lock_flag = 0;
00970    ast_cond_signal(&p->app_complete_cond);
00971 
00972    ast_mutex_unlock(&p->lock);
00973    return 0;
00974 }

static int agent_indicate ( struct ast_channel ast,
int  condition,
const void *  data,
size_t  datalen 
) [static]

Definition at line 787 of file chan_agent.c.

References ast_channel_lock, 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.

00788 {
00789    struct agent_pvt *p = ast->tech_pvt;
00790    int res = -1;
00791 
00792    ast_mutex_lock(&p->lock);
00793    if (p->chan && !ast_check_hangup(p->chan)) {
00794       ast_channel_unlock(ast);
00795       ast_channel_lock(p->chan);
00796       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00797       ast_channel_unlock(p->chan);
00798       ast_mutex_unlock(&p->lock);
00799       ast_channel_lock(ast);
00800    } else {
00801       ast_mutex_unlock(&p->lock);
00802       res = 0;
00803    }
00804    return res;
00805 }

static struct ast_channel* agent_lock_owner ( struct agent_pvt pvt  )  [static, read]

Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed.

Parameters:
pvt Pointer to the LOCKED agent_pvt for which the owner is needed locked channel which owns the pvt at the time of completion. NULL if not available.

Definition at line 382 of file chan_agent.c.

References ast_channel_lock, ast_channel_ref, ast_channel_unlock, ast_channel_unref, ast_mutex_lock, ast_mutex_unlock, agent_pvt::lock, and agent_pvt::owner.

Referenced by action_agents(), agent_logoff(), agent_read(), agents_data_provider_get(), agents_show(), and agents_show_online().

00383 {
00384    struct ast_channel *owner;
00385 
00386    for (;;) {
00387       if (!pvt->owner) { /* No owner. Nothing to do. */
00388          return NULL;
00389       }
00390 
00391       /* If we don't ref the owner, it could be killed when we unlock the pvt. */
00392       owner = ast_channel_ref(pvt->owner);
00393 
00394       /* Locking order requires us to lock channel, then pvt. */
00395       ast_mutex_unlock(&pvt->lock);
00396       ast_channel_lock(owner);
00397       ast_mutex_lock(&pvt->lock);
00398 
00399       /* Check if owner changed during pvt unlock period */
00400       if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */
00401          ast_channel_unlock(owner);
00402          owner = ast_channel_unref(owner);
00403       } else { /* Channel stayed the same. Return it. */
00404          return owner;
00405       }
00406    }
00407 }

static int agent_logoff ( const char *  agent,
int  soft 
) [static]

Definition at line 1574 of file chan_agent.c.

References agent_pvt::agent, agent_lock_owner(), ast_channel_trylock, ast_channel_unlock, ast_channel_unref, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, DEADLOCK_AVOIDANCE, agent_pvt::deferlogoff, agent_pvt::lock, and agent_pvt::owner.

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01575 {
01576    struct agent_pvt *p;
01577    int ret = -1; /* Return -1 if no agent if found */
01578 
01579    AST_LIST_LOCK(&agents);
01580    AST_LIST_TRAVERSE(&agents, p, list) {
01581       if (!strcasecmp(p->agent, agent)) {
01582          ret = 0;
01583          if (p->owner || p->chan) {
01584             if (!soft) {
01585                struct ast_channel *owner;
01586                ast_mutex_lock(&p->lock);
01587                owner = agent_lock_owner(p);
01588 
01589                if (owner) {
01590                   ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
01591                   ast_channel_unlock(owner);
01592                   owner = ast_channel_unref(owner);
01593                }
01594 
01595                while (p->chan && ast_channel_trylock(p->chan)) {
01596                   DEADLOCK_AVOIDANCE(&p->lock);
01597                }
01598                if (p->chan) {
01599                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01600                   ast_channel_unlock(p->chan);
01601                }
01602 
01603                ast_mutex_unlock(&p->lock);
01604             } else
01605                p->deferlogoff = 1;
01606          }
01607          break;
01608       }
01609    }
01610    AST_LIST_UNLOCK(&agents);
01611 
01612    return ret;
01613 }

static char* agent_logoff_cmd ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1615 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.

01616 {
01617    int ret;
01618    const char *agent;
01619 
01620    switch (cmd) {
01621    case CLI_INIT:
01622       e->command = "agent logoff";
01623       e->usage =
01624          "Usage: agent logoff <channel> [soft]\n"
01625          "       Sets an agent as no longer logged in.\n"
01626          "       If 'soft' is specified, do not hangup existing calls.\n";
01627       return NULL;
01628    case CLI_GENERATE:
01629       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01630    }
01631 
01632    if (a->argc < 3 || a->argc > 4)
01633       return CLI_SHOWUSAGE;
01634    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01635       return CLI_SHOWUSAGE;
01636 
01637    agent = a->argv[2] + 6;
01638    ret = agent_logoff(agent, a->argc == 4);
01639    if (ret == 0)
01640       ast_cli(a->fd, "Logging out %s\n", agent);
01641 
01642    return CLI_SUCCESS;
01643 }

static struct ast_channel* agent_new ( struct agent_pvt p,
int  state,
const char *  linkedid 
) [static, read]

Create new agent channel.

Definition at line 1063 of file chan_agent.c.

References agent_pvt::agent, agent_tech, ast_channel_alloc, ast_copy_string(), AST_FORMAT_SLINEAR, ast_log(), ast_random(), ast_string_field_set, agent_pvt::chan, ast_channel::context, ast_channel::exten, language, LOG_WARNING, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by agent_request(), and check_availability().

01064 {
01065    struct ast_channel *tmp;
01066 #if 0
01067    if (!p->chan) {
01068       ast_log(LOG_WARNING, "No channel? :(\n");
01069       return NULL;
01070    }
01071 #endif   
01072    if (p->pending)
01073       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
01074    else
01075       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent);
01076    if (!tmp) {
01077       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01078       return NULL;
01079    }
01080 
01081    tmp->tech = &agent_tech;
01082    if (p->chan) {
01083       tmp->nativeformats = p->chan->nativeformats;
01084       tmp->writeformat = p->chan->writeformat;
01085       tmp->rawwriteformat = p->chan->writeformat;
01086       tmp->readformat = p->chan->readformat;
01087       tmp->rawreadformat = p->chan->readformat;
01088       ast_string_field_set(tmp, language, p->chan->language);
01089       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01090       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01091       /* XXX Is this really all we copy form the originating channel?? */
01092    } else {
01093       tmp->nativeformats = AST_FORMAT_SLINEAR;
01094       tmp->writeformat = AST_FORMAT_SLINEAR;
01095       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01096       tmp->readformat = AST_FORMAT_SLINEAR;
01097       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01098    }
01099    /* Safe, agentlock already held */
01100    tmp->tech_pvt = p;
01101    p->owner = tmp;
01102    tmp->priority = 1;
01103    return tmp;
01104 }

static void agent_pvt_destroy ( struct agent_pvt doomed  )  [static]
static struct ast_frame * agent_read ( struct ast_channel ast  )  [static, read]

Definition at line 607 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_lock_owner(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, ast_channel_unref, AST_CONTROL_ANSWER, ast_copy_flags, ast_debug, AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_read(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, AST_TIMING_FD, ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, agent_pvt::enddtmf, f, ast_channel::fdno, ast_frame::frametype, ast_frame_subclass::integer, agent_pvt::lock, LOG_NOTICE, agent_pvt::name, agent_pvt::owner, agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.

00608 {
00609    struct agent_pvt *p = ast->tech_pvt;
00610    struct ast_frame *f = NULL;
00611    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00612    int cur_time = time(NULL);
00613    struct ast_channel *owner;
00614 
00615    ast_mutex_lock(&p->lock);
00616    owner = agent_lock_owner(p);
00617 
00618    CHECK_FORMATS(ast, p);
00619    if (!p->start) {
00620       p->start = cur_time;
00621    }
00622    if (p->chan) {
00623       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00624       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00625       f = ast_read(p->chan);
00626       ast->fdno = -1;
00627    } else
00628       f = &ast_null_frame;
00629    if (f) {
00630       /* if acknowledgement is not required, and the channel is up, we may have missed
00631          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00632       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00633          p->acknowledged = 1;
00634       }
00635 
00636       if (!p->acknowledged) {
00637          int howlong = cur_time - p->start;
00638          if (p->autologoff && (howlong >= p->autologoff)) {
00639             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00640             if (owner || p->chan) {
00641                if (owner) {
00642                   ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
00643                   ast_channel_unlock(owner);
00644                   owner = ast_channel_unref(owner);
00645                }
00646 
00647                while (p->chan && ast_channel_trylock(p->chan)) {
00648                   DEADLOCK_AVOIDANCE(&p->lock);
00649                }
00650                if (p->chan) {
00651                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00652                   ast_channel_unlock(p->chan);
00653                }
00654             }
00655          }
00656       }
00657       switch (f->frametype) {
00658       case AST_FRAME_CONTROL:
00659          if (f->subclass.integer == AST_CONTROL_ANSWER) {
00660             if (p->ackcall) {
00661                ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf);
00662                /* Don't pass answer along */
00663                ast_frfree(f);
00664                f = &ast_null_frame;
00665             } else {
00666                p->acknowledged = 1;
00667                /* Use the builtin answer frame for the 
00668                   recording start check below. */
00669                ast_frfree(f);
00670                f = &answer_frame;
00671             }
00672          }
00673          break;
00674       case AST_FRAME_DTMF_BEGIN:
00675          /*ignore DTMF begin's as it can cause issues with queue announce files*/
00676          if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){
00677             ast_frfree(f);
00678             f = &ast_null_frame;
00679          }
00680          break;
00681       case AST_FRAME_DTMF_END:
00682          if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) {
00683             if (p->chan) {
00684                ast_verb(3, "%s acknowledged\n", p->chan->name);
00685             }
00686             p->acknowledged = 1;
00687             ast_frfree(f);
00688             f = &answer_frame;
00689          } else if (f->subclass.integer == p->enddtmf && endcall) {
00690             /* terminates call */
00691             ast_frfree(f);
00692             f = NULL;
00693          }
00694          break;
00695       case AST_FRAME_VOICE:
00696       case AST_FRAME_VIDEO:
00697          /* don't pass voice or video until the call is acknowledged */
00698          if (!p->acknowledged) {
00699             ast_frfree(f);
00700             f = &ast_null_frame;
00701          }
00702       default:
00703          /* pass everything else on through */
00704          break;
00705       }
00706    }
00707 
00708    if (owner) {
00709       ast_channel_unlock(owner);
00710       owner = ast_channel_unref(owner);
00711    }
00712 
00713    CLEANUP(ast,p);
00714    if (p->chan && !p->chan->_bridge) {
00715       if (strcasecmp(p->chan->tech->type, "Local")) {
00716          p->chan->_bridge = ast;
00717          ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00718       }
00719    }
00720    ast_mutex_unlock(&p->lock);
00721    if (recordagentcalls && f == &answer_frame)
00722       agent_start_monitoring(ast,0);
00723    return f;
00724 }

static struct ast_channel * agent_request ( const char *  type,
format_t  format,
const struct ast_channel requestor,
void *  data,
int *  cause 
) [static, read]

Part of the Asterisk PBX interface.

Definition at line 1370 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_new(), agent_pvt_destroy(), agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, ast_hangup(), ast_indicate(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), AST_STATE_DOWN, ast_tv(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::login_wait_cond, agent_pvt::loginstart, agent_pvt::owner, and agent_pvt::pending.

01371 {
01372    struct agent_pvt *p;
01373    struct ast_channel *chan = NULL;
01374    char *s;
01375    ast_group_t groupmatch;
01376    int groupoff;
01377    int waitforagent=0;
01378    int hasagent = 0;
01379    struct timeval now;
01380 
01381    s = data;
01382    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01383       groupmatch = (1 << groupoff);
01384    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01385       groupmatch = (1 << groupoff);
01386       waitforagent = 1;
01387    } else 
01388       groupmatch = 0;
01389 
01390    /* Check actual logged in agents first */
01391    AST_LIST_LOCK(&agents);
01392    AST_LIST_TRAVERSE(&agents, p, list) {
01393       ast_mutex_lock(&p->lock);
01394       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01395          if (p->chan) {
01396             hasagent++;
01397          }
01398          now = ast_tvnow();
01399          if (p->loginstart
01400             && (!p->lastdisc.tv_sec || ast_tvdiff_ms(now, p->lastdisc) > 0)) {
01401             p->lastdisc = ast_tv(0, 0);
01402             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01403             if (!p->owner && p->chan) {
01404                /* Fixed agent */
01405                chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01406             }
01407             if (chan) {
01408                ast_mutex_unlock(&p->lock);
01409                break;
01410             }
01411          }
01412       }
01413       ast_mutex_unlock(&p->lock);
01414    }
01415 
01416    if (!chan && waitforagent) {
01417       /* No agent available -- but we're requesting to wait for one.
01418          Allocate a place holder */
01419       if (hasagent) {
01420          ast_debug(1, "Creating place holder for '%s'\n", s);
01421          p = add_agent(data, 1);
01422          if (p) {
01423             p->group = groupmatch;
01424             chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01425             if (!chan) {
01426                AST_LIST_REMOVE(&agents, p, list);
01427                agent_pvt_destroy(p);
01428             }
01429          }
01430       } else {
01431          ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
01432       }
01433    }
01434    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01435    AST_LIST_UNLOCK(&agents);
01436 
01437    if (chan) {
01438       ast_mutex_lock(&p->lock);
01439       if (p->pending) {
01440          ast_mutex_unlock(&p->lock);
01441          return chan;
01442       }
01443 
01444       if (!p->chan) {
01445          ast_debug(1, "Agent disconnected before we could connect the call\n");
01446          ast_mutex_unlock(&p->lock);
01447          ast_hangup(chan);
01448          *cause = AST_CAUSE_UNREGISTERED;
01449          return NULL;
01450       }
01451 
01452       /* we need to take control of the channel from the login app
01453        * thread */
01454       p->app_sleep_cond = 0;
01455       p->app_lock_flag = 1;
01456       ast_queue_frame(p->chan, &ast_null_frame);
01457       ast_cond_wait(&p->login_wait_cond, &p->lock);
01458 
01459       if (!p->chan) {
01460          ast_debug(1, "Agent disconnected while we were connecting the call\n");
01461          ast_mutex_unlock(&p->lock);
01462          ast_hangup(chan);
01463          *cause = AST_CAUSE_UNREGISTERED;
01464          return NULL;
01465       }
01466 
01467       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01468       ast_mutex_unlock(&p->lock);
01469    }
01470 
01471    return chan;
01472 }

static int agent_sendhtml ( struct ast_channel ast,
int  subclass,
const char *  data,
int  datalen 
) [static]

Definition at line 726 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.

00727 {
00728    struct agent_pvt *p = ast->tech_pvt;
00729    int res = -1;
00730    ast_mutex_lock(&p->lock);
00731    if (p->chan) 
00732       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00733    ast_mutex_unlock(&p->lock);
00734    return res;
00735 }

static int agent_sendtext ( struct ast_channel ast,
const char *  text 
) [static]

Definition at line 737 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.

00738 {
00739    struct agent_pvt *p = ast->tech_pvt;
00740    int res = -1;
00741    ast_mutex_lock(&p->lock);
00742    if (p->chan) 
00743       res = ast_sendtext(p->chan, text);
00744    ast_mutex_unlock(&p->lock);
00745    return res;
00746 }

static int agent_start_monitoring ( struct ast_channel ast,
int  needlock 
) [static]

Definition at line 602 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00603 {
00604    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00605 }

static int agent_write ( struct ast_channel ast,
struct ast_frame f 
) [static]

Definition at line 748 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_subclass::codec, ast_frame::frametype, agent_pvt::lock, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

00749 {
00750    struct agent_pvt *p = ast->tech_pvt;
00751    int res = -1;
00752    CHECK_FORMATS(ast, p);
00753    ast_mutex_lock(&p->lock);
00754    if (!p->chan) 
00755       res = 0;
00756    else {
00757       if ((f->frametype != AST_FRAME_VOICE) ||
00758           (f->frametype != AST_FRAME_VIDEO) ||
00759           (f->subclass.codec == p->chan->writeformat)) {
00760          res = ast_write(p->chan, f);
00761       } else {
00762          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00763             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00764             ast->name, p->chan->name);
00765          res = 0;
00766       }
00767    }
00768    CLEANUP(ast, p);
00769    ast_mutex_unlock(&p->lock);
00770    return res;
00771 }

static int agentmonitoroutgoing_exec ( struct ast_channel chan,
const char *  data 
) [static]

Called by the AgentMonitorOutgoing application (from the dial plan).

Parameters:
chan 
data 
Returns:
See also:
login_exec(), load_module().

Definition at line 2199 of file chan_agent.c.

References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_strlen_zero(), ast_channel::caller, ast_channel::cdr, ast_cdr::channel, GETAGENTBYCALLERID, ast_party_caller::id, LOG_WARNING, ast_party_id::number, pbx_builtin_getvar_helper(), ast_party_number::str, and ast_party_number::valid.

Referenced by load_module().

02200 {
02201    int exitifnoagentid = 0;
02202    int nowarnings = 0;
02203    int changeoutgoing = 0;
02204    int res = 0;
02205    char agent[AST_MAX_AGENT];
02206 
02207    if (data) {
02208       if (strchr(data, 'd'))
02209          exitifnoagentid = 1;
02210       if (strchr(data, 'n'))
02211          nowarnings = 1;
02212       if (strchr(data, 'c'))
02213          changeoutgoing = 1;
02214    }
02215    if (chan->caller.id.number.valid
02216       && !ast_strlen_zero(chan->caller.id.number.str)) {
02217       const char *tmp;
02218       char agentvar[AST_MAX_BUF];
02219       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
02220          chan->caller.id.number.str);
02221       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02222          struct agent_pvt *p;
02223          ast_copy_string(agent, tmp, sizeof(agent));
02224          AST_LIST_LOCK(&agents);
02225          AST_LIST_TRAVERSE(&agents, p, list) {
02226             if (!strcasecmp(p->agent, tmp)) {
02227                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02228                __agent_start_monitoring(chan, p, 1);
02229                break;
02230             }
02231          }
02232          AST_LIST_UNLOCK(&agents);
02233          
02234       } else {
02235          res = -1;
02236          if (!nowarnings)
02237             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);
02238       }
02239    } else {
02240       res = -1;
02241       if (!nowarnings)
02242          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");
02243    }
02244    if (res) {
02245       if (exitifnoagentid)
02246          return res;
02247    }
02248    return 0;
02249 }

static int agents_data_provider_get ( const struct ast_data_search search,
struct ast_data data_root 
) [static]

Definition at line 2383 of file chan_agent.c.

References agent_pvt::agent, agent_lock_owner(), ast_bridged_channel(), ast_channel_data_add_structure(), ast_channel_unlock, ast_channel_unref, ast_data_add_bool(), ast_data_add_node(), ast_data_add_str(), ast_data_add_structure, ast_data_remove_node(), ast_data_search_match(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::lock, agent_pvt::moh, agent_pvt::owner, and agent_pvt::pending.

02385 {
02386    struct agent_pvt *p;
02387    struct ast_data *data_agent, *data_channel, *data_talkingto;
02388 
02389    AST_LIST_LOCK(&agents);
02390    AST_LIST_TRAVERSE(&agents, p, list) {
02391       struct ast_channel *owner;
02392 
02393       data_agent = ast_data_add_node(data_root, "agent");
02394       if (!data_agent) {
02395          continue;
02396       }
02397 
02398       ast_mutex_lock(&p->lock);
02399       owner = agent_lock_owner(p);
02400 
02401       if (!(p->pending)) {
02402          ast_data_add_str(data_agent, "id", p->agent);
02403          ast_data_add_structure(agent_pvt, data_agent, p);
02404 
02405          ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
02406          if (p->chan) {
02407             data_channel = ast_data_add_node(data_agent, "loggedon");
02408             if (!data_channel) {
02409                ast_mutex_unlock(&p->lock);
02410                ast_data_remove_node(data_root, data_agent);
02411                if (owner) {
02412                   ast_channel_unlock(owner);
02413                   owner = ast_channel_unref(owner);
02414                }
02415                continue;
02416             }
02417             ast_channel_data_add_structure(data_channel, p->chan, 0);
02418             if (owner && ast_bridged_channel(owner)) {
02419                data_talkingto = ast_data_add_node(data_agent, "talkingto");
02420                if (!data_talkingto) {
02421                   ast_mutex_unlock(&p->lock);
02422                   ast_data_remove_node(data_root, data_agent);
02423                   if (owner) {
02424                      ast_channel_unlock(owner);
02425                      owner = ast_channel_unref(owner);
02426                   }
02427                   continue;
02428                }
02429                ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
02430             }
02431          } else {
02432             ast_data_add_node(data_agent, "talkingto");
02433             ast_data_add_node(data_agent, "loggedon");
02434          }
02435          ast_data_add_str(data_agent, "musiconhold", p->moh);
02436       }
02437 
02438       if (owner) {
02439          ast_channel_unlock(owner);
02440          owner = ast_channel_unref(owner);
02441       }
02442 
02443       ast_mutex_unlock(&p->lock);
02444 
02445       /* if this agent doesn't match remove the added agent. */
02446       if (!ast_data_search_match(search, data_agent)) {
02447          ast_data_remove_node(data_root, data_agent);
02448       }
02449    }
02450    AST_LIST_UNLOCK(&agents);
02451 
02452    return 0;
02453 }

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 1702 of file chan_agent.c.

References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, count_agents(), ast_cli_args::fd, agent_pvt::group, agent_pvt::lock, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.

01703 {
01704    struct agent_pvt *p;
01705    char username[AST_MAX_BUF];
01706    char location[AST_MAX_BUF] = "";
01707    char talkingto[AST_MAX_BUF] = "";
01708    char music[AST_MAX_BUF];
01709    int count_agents = 0;      /*!< Number of agents configured */
01710    int online_agents = 0;     /*!< Number of online agents */
01711    int offline_agents = 0;    /*!< Number of offline agents */
01712 
01713    switch (cmd) {
01714    case CLI_INIT:
01715       e->command = "agent show";
01716       e->usage =
01717          "Usage: agent show\n"
01718          "       Provides summary information on agents.\n";
01719       return NULL;
01720    case CLI_GENERATE:
01721       return NULL;
01722    }
01723 
01724    if (a->argc != 2)
01725       return CLI_SHOWUSAGE;
01726 
01727    AST_LIST_LOCK(&agents);
01728    AST_LIST_TRAVERSE(&agents, p, list) {
01729       struct ast_channel *owner;
01730       ast_mutex_lock(&p->lock);
01731       owner = agent_lock_owner(p);
01732       if (p->pending) {
01733          if (p->group)
01734             ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01735          else
01736             ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01737       } else {
01738          if (!ast_strlen_zero(p->name))
01739             snprintf(username, sizeof(username), "(%s) ", p->name);
01740          else
01741             username[0] = '\0';
01742          if (p->chan) {
01743             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01744             if (owner && ast_bridged_channel(owner)) {
01745                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01746             } else {
01747                strcpy(talkingto, " is idle");
01748             }
01749             online_agents++;
01750          } else {
01751             strcpy(location, "not logged in");
01752             talkingto[0] = '\0';
01753             offline_agents++;
01754          }
01755          if (!ast_strlen_zero(p->moh))
01756             snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01757          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
01758             username, location, talkingto, music);
01759          count_agents++;
01760       }
01761 
01762       if (owner) {
01763          ast_channel_unlock(owner);
01764          owner = ast_channel_unref(owner);
01765       }
01766       ast_mutex_unlock(&p->lock);
01767    }
01768    AST_LIST_UNLOCK(&agents);
01769    if ( !count_agents ) 
01770       ast_cli(a->fd, "No Agents are configured in %s\n",config);
01771    else 
01772       ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01773    ast_cli(a->fd, "\n");
01774                    
01775    return CLI_SUCCESS;
01776 }

static char* agents_show_online ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1779 of file chan_agent.c.

References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, count_agents(), ast_cli_args::fd, agent_pvt::lock, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.

01780 {
01781    struct agent_pvt *p;
01782    char username[AST_MAX_BUF];
01783    char location[AST_MAX_BUF] = "";
01784    char talkingto[AST_MAX_BUF] = "";
01785    char music[AST_MAX_BUF];
01786    int count_agents = 0;           /* Number of agents configured */
01787    int online_agents = 0;          /* Number of online agents */
01788    int agent_status = 0;           /* 0 means offline, 1 means online */
01789 
01790    switch (cmd) {
01791    case CLI_INIT:
01792       e->command = "agent show online";
01793       e->usage =
01794          "Usage: agent show online\n"
01795          "       Provides a list of all online agents.\n";
01796       return NULL;
01797    case CLI_GENERATE:
01798       return NULL;
01799    }
01800 
01801    if (a->argc != 3)
01802       return CLI_SHOWUSAGE;
01803 
01804    AST_LIST_LOCK(&agents);
01805    AST_LIST_TRAVERSE(&agents, p, list) {
01806       struct ast_channel *owner;
01807 
01808       agent_status = 0;       /* reset it to offline */
01809       ast_mutex_lock(&p->lock);
01810       owner = agent_lock_owner(p);
01811 
01812       if (!ast_strlen_zero(p->name))
01813          snprintf(username, sizeof(username), "(%s) ", p->name);
01814       else
01815          username[0] = '\0';
01816       if (p->chan) {
01817          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01818          if (owner && ast_bridged_channel(owner)) {
01819             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name);
01820          } else {
01821             strcpy(talkingto, " is idle");
01822          }
01823          agent_status = 1;
01824          online_agents++;
01825       }
01826 
01827       if (owner) {
01828          ast_channel_unlock(owner);
01829          owner = ast_channel_unref(owner);
01830       }
01831 
01832       if (!ast_strlen_zero(p->moh))
01833          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01834       if (agent_status)
01835          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01836       count_agents++;
01837       ast_mutex_unlock(&p->lock);
01838    }
01839    AST_LIST_UNLOCK(&agents);
01840    if (!count_agents) 
01841       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01842    else
01843       ast_cli(a->fd, "%d agents online\n", online_agents);
01844    ast_cli(a->fd, "\n");
01845    return CLI_SUCCESS;
01846 }

AST_DATA_STRUCTURE ( agent_pvt  ,
DATA_EXPORT_AGENT   
)
static AST_LIST_HEAD_STATIC ( agents  ,
agent_pvt   
) [static]

Holds the list of agents (loaded form agents.conf).

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_LOAD_ORDER  ,
"Agent Proxy Channel"  ,
load = load_module,
unload = unload_module,
reload = reload,
load_pri = AST_MODPRI_CHANNEL_DRIVER,
nonoptreq = "res_monitor,chan_local" 
)
static int check_availability ( struct agent_pvt newlyavailable,
int  needlock 
) [static]

Definition at line 1270 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_hangup(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.

Referenced by login_exec().

01271 {
01272    struct ast_channel *chan=NULL, *parent=NULL;
01273    struct agent_pvt *p;
01274    int res;
01275 
01276    ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
01277    if (needlock)
01278       AST_LIST_LOCK(&agents);
01279    AST_LIST_TRAVERSE(&agents, p, list) {
01280       if (p == newlyavailable) {
01281          continue;
01282       }
01283       ast_mutex_lock(&p->lock);
01284       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01285          ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01286          /* We found a pending call, time to merge */
01287          chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL);
01288          parent = p->owner;
01289          p->abouttograb = 1;
01290          ast_mutex_unlock(&p->lock);
01291          break;
01292       }
01293       ast_mutex_unlock(&p->lock);
01294    }
01295    if (needlock)
01296       AST_LIST_UNLOCK(&agents);
01297    if (parent && chan)  {
01298       if (newlyavailable->ackcall) {
01299          /* Don't do beep here */
01300          res = 0;
01301       } else {
01302          ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01303          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01304          ast_debug(3, "Played beep, result '%d'\n", res);
01305          if (!res) {
01306             res = ast_waitstream(newlyavailable->chan, "");
01307             ast_debug(1, "Waited for stream, result '%d'\n", res);
01308          }
01309       }
01310       if (!res) {
01311          /* Note -- parent may have disappeared */
01312          if (p->abouttograb) {
01313             newlyavailable->acknowledged = 1;
01314             /* Safe -- agent lock already held */
01315             ast_setstate(parent, AST_STATE_UP);
01316             ast_setstate(chan, AST_STATE_UP);
01317             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01318             ast_channel_masquerade(parent, chan);
01319             ast_hangup(chan);
01320             p->abouttograb = 0;
01321          } else {
01322             ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
01323             agent_cleanup(newlyavailable);
01324          }
01325       } else {
01326          ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
01327          agent_cleanup(newlyavailable);
01328       }
01329    }
01330    return 0;
01331 }

static int check_beep ( struct agent_pvt newlyavailable,
int  needlock 
) [static]

Definition at line 1333 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, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.

Referenced by login_exec().

01334 {
01335    struct agent_pvt *p;
01336    int res=0;
01337 
01338    ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01339    if (needlock)
01340       AST_LIST_LOCK(&agents);
01341    AST_LIST_TRAVERSE(&agents, p, list) {
01342       if (p == newlyavailable) {
01343          continue;
01344       }
01345       ast_mutex_lock(&p->lock);
01346       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01347          ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01348          ast_mutex_unlock(&p->lock);
01349          break;
01350       }
01351       ast_mutex_unlock(&p->lock);
01352    }
01353    if (needlock)
01354       AST_LIST_UNLOCK(&agents);
01355    if (p) {
01356       ast_mutex_unlock(&newlyavailable->lock);
01357       ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01358       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01359       ast_debug(1, "Played beep, result '%d'\n", res);
01360       if (!res) {
01361          res = ast_waitstream(newlyavailable->chan, "");
01362          ast_debug(1, "Waited for stream, result '%d'\n", res);
01363       }
01364       ast_mutex_lock(&newlyavailable->lock);
01365    }
01366    return res;
01367 }

static char * complete_agent_logoff_cmd ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 1675 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().

01676 {
01677    char *ret = NULL;
01678 
01679    if (pos == 2) {
01680       struct agent_pvt *p;
01681       char name[AST_MAX_AGENT];
01682       int which = 0, len = strlen(word);
01683 
01684       AST_LIST_LOCK(&agents);
01685       AST_LIST_TRAVERSE(&agents, p, list) {
01686          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01687          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01688             ret = ast_strdup(name);
01689             break;
01690          }
01691       }
01692       AST_LIST_UNLOCK(&agents);
01693    } else if (pos == 3 && state == 0) 
01694       return ast_strdup("soft");
01695    
01696    return ret;
01697 }

static struct agent_pvt* find_agent ( char *  agentid  )  [static, read]
Note:
This function expects the agent list to be locked

Definition at line 2292 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02293 {
02294    struct agent_pvt *cur;
02295 
02296    AST_LIST_TRAVERSE(&agents, cur, list) {
02297       if (!strcmp(cur->agent, agentid))
02298          break;   
02299    }
02300 
02301    return cur; 
02302 }

static int function_agent ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 2304 of file chan_agent.c.

References agent_pvt::agent, args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::chan, find_agent(), LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and status.

02305 {
02306    char *parse;    
02307    AST_DECLARE_APP_ARGS(args,
02308       AST_APP_ARG(agentid);
02309       AST_APP_ARG(item);
02310    );
02311    char *tmp;
02312    struct agent_pvt *agent;
02313 
02314    buf[0] = '\0';
02315 
02316    if (ast_strlen_zero(data)) {
02317       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02318       return -1;
02319    }
02320 
02321    parse = ast_strdupa(data);
02322 
02323    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02324    if (!args.item)
02325       args.item = "status";
02326 
02327    AST_LIST_LOCK(&agents);
02328 
02329    if (!(agent = find_agent(args.agentid))) {
02330       AST_LIST_UNLOCK(&agents);
02331       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02332       return -1;
02333    }
02334 
02335    if (!strcasecmp(args.item, "status")) {
02336       char *status = "LOGGEDOUT";
02337       if (agent->chan) {
02338          status = "LOGGEDIN";
02339       }
02340       ast_copy_string(buf, status, len);
02341    } else if (!strcasecmp(args.item, "password")) 
02342       ast_copy_string(buf, agent->password, len);
02343    else if (!strcasecmp(args.item, "name"))
02344       ast_copy_string(buf, agent->name, len);
02345    else if (!strcasecmp(args.item, "mohclass"))
02346       ast_copy_string(buf, agent->moh, len);
02347    else if (!strcasecmp(args.item, "channel")) {
02348       if (agent->chan) {
02349          ast_channel_lock(agent->chan);
02350          ast_copy_string(buf, agent->chan->name, len);
02351          ast_channel_unlock(agent->chan);
02352          tmp = strrchr(buf, '-');
02353          if (tmp)
02354             *tmp = '\0';
02355       } 
02356    } else if (!strcasecmp(args.item, "fullchannel")) {
02357       if (agent->chan) {
02358          ast_channel_lock(agent->chan);
02359          ast_copy_string(buf, agent->chan->name, len);
02360          ast_channel_unlock(agent->chan);
02361       } 
02362    } else if (!strcasecmp(args.item, "exten")) {
02363       buf[0] = '\0';
02364    }
02365 
02366    AST_LIST_UNLOCK(&agents);
02367 
02368    return 0;
02369 }

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.

Returns:
int Always 0.

Definition at line 2471 of file chan_agent.c.

References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), agents_data_providers, ARRAY_LEN, ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_data_register_multiple, ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), and read_agent_config().

02472 {
02473    /* Make sure we can register our agent channel type */
02474    if (ast_channel_register(&agent_tech)) {
02475       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02476       return AST_MODULE_LOAD_FAILURE;
02477    }
02478    /* Read in the config */
02479    if (!read_agent_config(0))
02480       return AST_MODULE_LOAD_DECLINE;
02481    /* Dialplan applications */
02482    ast_register_application_xml(app, login_exec);
02483    ast_register_application_xml(app3, agentmonitoroutgoing_exec);
02484 
02485    /* data tree */
02486    ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
02487 
02488    /* Manager commands */
02489    ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
02490    ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
02491 
02492    /* CLI Commands */
02493    ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
02494 
02495    /* Dialplan Functions */
02496    ast_custom_function_register(&agent_function);
02497 
02498    return AST_MODULE_LOAD_SUCCESS;
02499 }

static int login_exec ( struct ast_channel chan,
const char *  data 
) [static]

Log in agent application.

Called by the AgentLogin application (from the dial plan).

Parameters:
chan 
data 
Returns:
See also:
agentmonitoroutgoing_exec(), load_module().

Definition at line 1869 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_destroy(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_check_hangup(), ast_cond_signal, ast_cond_wait, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, ast_devstate_changed(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_mutex_lock, ast_mutex_unlock, ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::nativeformats, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, ast_channel::readformat, S_OR, update_cdr, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by load_module().

01870 {
01871    int res=0;
01872    int tries = 0;
01873    int max_login_tries = maxlogintries;
01874    struct agent_pvt *p;
01875    char user[AST_MAX_AGENT];
01876    char pass[AST_MAX_AGENT];
01877    char xpass[AST_MAX_AGENT];
01878    char *errmsg;
01879    char *parse;
01880    AST_DECLARE_APP_ARGS(args,
01881               AST_APP_ARG(agent_id);
01882               AST_APP_ARG(options);
01883               AST_APP_ARG(extension);
01884       );
01885    const char *tmpoptions = NULL;
01886    int play_announcement = 1;
01887    char agent_goodbye[AST_MAX_FILENAME_LEN];
01888    int update_cdr = updatecdr;
01889 
01890    user[0] = '\0';
01891    xpass[0] = '\0';
01892 
01893    parse = ast_strdupa(data);
01894 
01895    AST_STANDARD_APP_ARGS(args, parse);
01896 
01897    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
01898 
01899    ast_channel_lock(chan);
01900    /* Set Channel Specific Login Overrides */
01901    if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
01902       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
01903       if (max_login_tries < 0)
01904          max_login_tries = 0;
01905       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
01906       ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
01907    }
01908    if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
01909       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
01910          update_cdr = 1;
01911       else
01912          update_cdr = 0;
01913       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
01914       ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
01915    }
01916    if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
01917       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
01918       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
01919       ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
01920    }
01921    ast_channel_unlock(chan);
01922    /* End Channel Specific Login Overrides */
01923    
01924    if (!ast_strlen_zero(args.options)) {
01925       if (strchr(args.options, 's')) {
01926          play_announcement = 0;
01927       }
01928    }
01929 
01930    if (chan->_state != AST_STATE_UP)
01931       res = ast_answer(chan);
01932    if (!res) {
01933       if (!ast_strlen_zero(args.agent_id))
01934          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
01935       else
01936          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
01937    }
01938    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
01939       tries++;
01940       /* Check for password */
01941       AST_LIST_LOCK(&agents);
01942       AST_LIST_TRAVERSE(&agents, p, list) {
01943          if (!strcmp(p->agent, user) && !p->pending)
01944             ast_copy_string(xpass, p->password, sizeof(xpass));
01945       }
01946       AST_LIST_UNLOCK(&agents);
01947       if (!res) {
01948          if (!ast_strlen_zero(xpass))
01949             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
01950          else
01951             pass[0] = '\0';
01952       }
01953       errmsg = "agent-incorrect";
01954 
01955 #if 0
01956       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
01957 #endif      
01958 
01959       /* Check again for accuracy */
01960       AST_LIST_LOCK(&agents);
01961       AST_LIST_TRAVERSE(&agents, p, list) {
01962          int unlock_channel = 1;
01963 
01964          ast_channel_lock(chan);
01965          ast_mutex_lock(&p->lock);
01966          if (!strcmp(p->agent, user) &&
01967              !strcmp(p->password, pass) && !p->pending) {
01968 
01969             /* Set Channel Specific Agent Overrides */
01970             if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
01971                if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
01972                   p->ackcall = 1;
01973                } else {
01974                   p->ackcall = 0;
01975                }
01976                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
01977                ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
01978                ast_set_flag(p, AGENT_FLAG_ACKCALL);
01979             } else {
01980                p->ackcall = ackcall;
01981             }
01982             if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
01983                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
01984                if (p->autologoff < 0)
01985                   p->autologoff = 0;
01986                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
01987                ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
01988                ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
01989             } else {
01990                p->autologoff = autologoff;
01991             }
01992             if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
01993                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
01994                if (p->wrapuptime < 0)
01995                   p->wrapuptime = 0;
01996                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
01997                ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
01998                ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
01999             } else {
02000                p->wrapuptime = wrapuptime;
02001             }
02002             tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
02003             if (!ast_strlen_zero(tmpoptions)) {
02004                p->acceptdtmf = *tmpoptions;
02005                ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
02006                ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
02007             }
02008             tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
02009             if (!ast_strlen_zero(tmpoptions)) {
02010                p->enddtmf = *tmpoptions;
02011                ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
02012                ast_set_flag(p, AGENT_FLAG_ENDDTMF);
02013             }
02014             ast_channel_unlock(chan);
02015             unlock_channel = 0;
02016             /* End Channel Specific Agent Overrides */
02017 
02018             if (!p->chan) {
02019                /* Ensure nobody else can be this agent until we're done. */
02020                p->chan = chan;
02021 
02022                p->acknowledged = 0;
02023 
02024                if (!res) {
02025                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02026                   if (res)
02027                      ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats)));
02028                }
02029                if (!res) {
02030                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02031                   if (res)
02032                      ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats)));
02033                }
02034                if (!res && play_announcement == 1) {
02035                   ast_mutex_unlock(&p->lock);
02036                   AST_LIST_UNLOCK(&agents);
02037                   res = ast_streamfile(chan, "agent-loginok", chan->language);
02038                   if (!res) {
02039                      ast_waitstream(chan, "");
02040                   }
02041                   AST_LIST_LOCK(&agents);
02042                   ast_mutex_lock(&p->lock);
02043                }
02044 
02045                if (!res) {
02046                   long logintime;
02047                   char agent[AST_MAX_AGENT];
02048 
02049                   snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
02050 
02051                   /* Login this channel and wait for it to go away */
02052                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
02053                      S_OR(p->moh, NULL), 
02054                      !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02055 
02056                   /* Must be done after starting HOLD. */
02057                   p->lastdisc = ast_tvnow();
02058                   time(&p->loginstart);
02059 
02060                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02061                            "Agent: %s\r\n"
02062                            "Channel: %s\r\n"
02063                            "Uniqueid: %s\r\n",
02064                            p->agent, chan->name, chan->uniqueid);
02065                   if (update_cdr && chan->cdr)
02066                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "%s", agent);
02067                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02068                   ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
02069                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02070 
02071                   ast_mutex_unlock(&p->lock);
02072                   AST_LIST_UNLOCK(&agents);
02073 
02074                   while (res >= 0) {
02075                      ast_mutex_lock(&p->lock);
02076                      if (p->deferlogoff) {
02077                         p->deferlogoff = 0;
02078                         ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
02079                         ast_mutex_unlock(&p->lock);
02080                         break;
02081                      }
02082                      ast_mutex_unlock(&p->lock);
02083 
02084                      AST_LIST_LOCK(&agents);
02085                      ast_mutex_lock(&p->lock);
02086                      if (p->lastdisc.tv_sec) {
02087                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02088                            ast_debug(1, "Wrapup time for %s expired!\n", agent);
02089                            p->lastdisc = ast_tv(0, 0);
02090                            ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "%s", agent);
02091                            if (p->ackcall) {
02092                               check_beep(p, 0);
02093                            } else {
02094                               check_availability(p, 0);
02095                            }
02096                         }
02097                      }
02098                      ast_mutex_unlock(&p->lock);
02099                      AST_LIST_UNLOCK(&agents);
02100 
02101                      /* Synchronize channel ownership between call to agent and itself. */
02102                      ast_mutex_lock(&p->lock);
02103                      if (p->app_lock_flag) {
02104                         ast_cond_signal(&p->login_wait_cond);
02105                         ast_cond_wait(&p->app_complete_cond, &p->lock);
02106                         if (ast_check_hangup(chan)) {
02107                            /* Agent hungup */
02108                            ast_mutex_unlock(&p->lock);
02109                            break;
02110                         }
02111                      }
02112                      ast_mutex_unlock(&p->lock);
02113 
02114                      if (p->ackcall) {
02115                         res = agent_ack_sleep(p);
02116                         if (res == 1) {
02117                            AST_LIST_LOCK(&agents);
02118                            ast_mutex_lock(&p->lock);
02119                            check_availability(p, 0);
02120                            ast_mutex_unlock(&p->lock);
02121                            AST_LIST_UNLOCK(&agents);
02122                         }
02123                      } else {
02124                         res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02125                      }
02126                   }
02127                   ast_mutex_lock(&p->lock);
02128 
02129                   /* Logoff this channel */
02130                   p->chan = NULL;
02131                   logintime = time(NULL) - p->loginstart;
02132                   p->loginstart = 0;
02133 
02134                   /* Synchronize channel ownership between call to agent and itself. */
02135                   if (p->app_lock_flag) {
02136                      ast_cond_signal(&p->login_wait_cond);
02137                      ast_cond_wait(&p->app_complete_cond, &p->lock);
02138                   }
02139 
02140                   if (p->owner) {
02141                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
02142                   }
02143 
02144                   p->acknowledged = 0;
02145                   ast_mutex_unlock(&p->lock);
02146 
02147                   ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "%s", agent);
02148                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02149                            "Agent: %s\r\n"
02150                            "Logintime: %ld\r\n"
02151                            "Uniqueid: %s\r\n",
02152                            p->agent, logintime, chan->uniqueid);
02153                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02154                   ast_verb(2, "Agent '%s' logged out\n", p->agent);
02155 
02156                   /* If there is no owner, go ahead and kill it now */
02157                   if (p->dead && !p->owner) {
02158                      agent_pvt_destroy(p);
02159                   }
02160                   AST_LIST_LOCK(&agents);
02161                } else {
02162                   /* Agent hung up before could be logged in. */
02163                   p->chan = NULL;
02164 
02165                   ast_mutex_unlock(&p->lock);
02166                }
02167                res = -1;
02168             } else {
02169                ast_mutex_unlock(&p->lock);
02170                errmsg = "agent-alreadyon";
02171             }
02172             break;
02173          }
02174          ast_mutex_unlock(&p->lock);
02175          if (unlock_channel) {
02176             ast_channel_unlock(chan);
02177          }
02178       }
02179       AST_LIST_UNLOCK(&agents);
02180 
02181       if (!res && (max_login_tries==0 || tries < max_login_tries))
02182          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02183    }
02184       
02185    if (!res)
02186       res = ast_safe_sleep(chan, 500);
02187 
02188    return -1;
02189 }

static force_inline int powerof ( unsigned int  d  )  [static]

Definition at line 1474 of file chan_agent.c.

Referenced by agents_show().

01475 {
01476    int x = ffs(d);
01477 
01478    if (x)
01479       return x - 1;
01480 
01481    return 0;
01482 }

static int read_agent_config ( int  reload  )  [static]

Read configuration data. The file named agents.conf.

Returns:
Always 0, or so it seems.

Definition at line 1112 of file chan_agent.c.

References add_agent(), agent_pvt_destroy(), ast_category_browse(), ast_config_destroy(), ast_config_load, ast_copy_string(), 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_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, LOG_ERROR, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

01113 {
01114    struct ast_config *cfg;
01115    struct ast_config *ucfg;
01116    struct ast_variable *v;
01117    struct agent_pvt *p;
01118    const char *catname;
01119    const char *hasagent;
01120    int genhasagent;
01121    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01122 
01123    group = 0;
01124    autologoff = 0;
01125    wrapuptime = 0;
01126    ackcall = 0;
01127    endcall = 1;
01128    cfg = ast_config_load(config, config_flags);
01129    if (!cfg) {
01130       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01131       return 0;
01132    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
01133       return -1;
01134    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01135       ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
01136       return 0;
01137    }
01138    if ((ucfg = ast_config_load("users.conf", config_flags))) {
01139       if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
01140          ucfg = NULL;
01141       } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
01142          ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
01143          return 0;
01144       }
01145    }
01146 
01147    AST_LIST_LOCK(&agents);
01148    AST_LIST_TRAVERSE(&agents, p, list) {
01149       p->dead = 1;
01150    }
01151    strcpy(moh, "default");
01152    /* set the default recording values */
01153    recordagentcalls = 0;
01154    strcpy(recordformat, "wav");
01155    strcpy(recordformatext, "wav");
01156    urlprefix[0] = '\0';
01157    savecallsin[0] = '\0';
01158 
01159    /* Read in the [agents] section */
01160    v = ast_variable_browse(cfg, "agents");
01161    while(v) {
01162       /* Create the interface list */
01163       if (!strcasecmp(v->name, "agent")) {
01164          add_agent(v->value, 0);
01165       } else if (!strcasecmp(v->name, "group")) {
01166          group = ast_get_group(v->value);
01167       } else if (!strcasecmp(v->name, "autologoff")) {
01168          autologoff = atoi(v->value);
01169          if (autologoff < 0)
01170             autologoff = 0;
01171       } else if (!strcasecmp(v->name, "ackcall")) {
01172          if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
01173             ackcall = 1;
01174          }
01175       } else if (!strcasecmp(v->name, "endcall")) {
01176          endcall = ast_true(v->value);
01177       } else if (!strcasecmp(v->name, "acceptdtmf")) {
01178          acceptdtmf = *(v->value);
01179          ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
01180       } else if (!strcasecmp(v->name, "enddtmf")) {
01181          enddtmf = *(v->value);
01182       } else if (!strcasecmp(v->name, "wrapuptime")) {
01183          wrapuptime = atoi(v->value);
01184          if (wrapuptime < 0)
01185             wrapuptime = 0;
01186       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01187          maxlogintries = atoi(v->value);
01188          if (maxlogintries < 0)
01189             maxlogintries = 0;
01190       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01191          strcpy(agentgoodbye,v->value);
01192       } else if (!strcasecmp(v->name, "musiconhold")) {
01193          ast_copy_string(moh, v->value, sizeof(moh));
01194       } else if (!strcasecmp(v->name, "updatecdr")) {
01195          if (ast_true(v->value))
01196             updatecdr = 1;
01197          else
01198             updatecdr = 0;
01199       } else if (!strcasecmp(v->name, "autologoffunavail")) {
01200          if (ast_true(v->value))
01201             autologoffunavail = 1;
01202          else
01203             autologoffunavail = 0;
01204       } else if (!strcasecmp(v->name, "recordagentcalls")) {
01205          recordagentcalls = ast_true(v->value);
01206       } else if (!strcasecmp(v->name, "recordformat")) {
01207          ast_copy_string(recordformat, v->value, sizeof(recordformat));
01208          if (!strcasecmp(v->value, "wav49"))
01209             strcpy(recordformatext, "WAV");
01210          else
01211             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01212       } else if (!strcasecmp(v->name, "urlprefix")) {
01213          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01214          if (urlprefix[strlen(urlprefix) - 1] != '/')
01215             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01216       } else if (!strcasecmp(v->name, "savecallsin")) {
01217          if (v->value[0] == '/')
01218             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01219          else
01220             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01221          if (savecallsin[strlen(savecallsin) - 1] != '/')
01222             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01223       } else if (!strcasecmp(v->name, "custom_beep")) {
01224          ast_copy_string(beep, v->value, sizeof(beep));
01225       }
01226       v = v->next;
01227    }
01228    if (ucfg) {
01229       genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01230       catname = ast_category_browse(ucfg, NULL);
01231       while(catname) {
01232          if (strcasecmp(catname, "general")) {
01233             hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01234             if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01235                char tmp[256];
01236                const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01237                const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01238                if (!fullname)
01239                   fullname = "";
01240                if (!secret)
01241                   secret = "";
01242                snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01243                add_agent(tmp, 0);
01244             }
01245          }
01246          catname = ast_category_browse(ucfg, catname);
01247       }
01248       ast_config_destroy(ucfg);
01249    }
01250    AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01251       if (p->dead) {
01252          AST_LIST_REMOVE_CURRENT(list);
01253          /* Destroy if  appropriate */
01254          if (!p->owner) {
01255             if (!p->chan) {
01256                agent_pvt_destroy(p);
01257             } else {
01258                /* Cause them to hang up */
01259                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01260             }
01261          }
01262       }
01263    }
01264    AST_LIST_TRAVERSE_SAFE_END;
01265    AST_LIST_UNLOCK(&agents);
01266    ast_config_destroy(cfg);
01267    return 1;
01268 }

static int reload ( void   )  [static]

Definition at line 2501 of file chan_agent.c.

References read_agent_config().

02502 {
02503    return read_agent_config(1);
02504 }

static int unload_module ( void   )  [static]

Definition at line 2506 of file chan_agent.c.

References agent_function, agent_tech, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_data_unregister, ast_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.

02507 {
02508    struct agent_pvt *p;
02509    /* First, take us out of the channel loop */
02510    ast_channel_unregister(&agent_tech);
02511    /* Unregister dialplan functions */
02512    ast_custom_function_unregister(&agent_function);   
02513    /* Unregister CLI commands */
02514    ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
02515    /* Unregister dialplan applications */
02516    ast_unregister_application(app);
02517    ast_unregister_application(app3);
02518    /* Unregister manager command */
02519    ast_manager_unregister("Agents");
02520    ast_manager_unregister("AgentLogoff");
02521    /* Unregister the data tree */
02522    ast_data_unregister(NULL);
02523    /* Unregister channel */
02524    AST_LIST_LOCK(&agents);
02525    /* Hangup all interfaces if they have an owner */
02526    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02527       if (p->owner)
02528          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02529       ast_free(p);
02530    }
02531    AST_LIST_UNLOCK(&agents);
02532    return 0;
02533 }


Variable Documentation

char acceptdtmf = DEFAULT_ACCEPTDTMF [static]

Definition at line 227 of file chan_agent.c.

Referenced by play_record_review().

int ackcall [static]

Definition at line 224 of file chan_agent.c.

Initial value:
 {
   .name = "AGENT",
   .read = function_agent,
}

Definition at line 2371 of file chan_agent.c.

Referenced by load_module(), and unload_module().

const char agent_logoff_usage[] [static]
Initial value:
"Usage: agent logoff <channel> [soft]\n"
"       Sets an agent as no longer logged in.\n"
"       If 'soft' is specified, do not hangup existing calls.\n"

Definition at line 1848 of file chan_agent.c.

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

Definition at line 349 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 231 of file chan_agent.c.

Initial value:

Definition at line 2455 of file chan_agent.c.

Initial value:
 {
   AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
}

Definition at line 2460 of file chan_agent.c.

Referenced by load_module().

const char app[] = "AgentLogin" [static]

Definition at line 206 of file chan_agent.c.

const char app3[] = "AgentMonitorOutgoing" [static]

Definition at line 207 of file chan_agent.c.

int autologoff [static]

Definition at line 222 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 226 of file chan_agent.c.

char beep[AST_MAX_BUF] = "beep" [static]

Definition at line 239 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]
Initial value:
 {
   AST_CLI_DEFINE(agents_show, "Show status of agents"),
   AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
   AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
}

Definition at line 1853 of file chan_agent.c.

Referenced by load_module(), and unload_module().

const char config[] = "agents.conf" [static]

Definition at line 204 of file chan_agent.c.

int endcall [static]

Definition at line 225 of file chan_agent.c.

char enddtmf = DEFAULT_ENDDTMF [static]

Definition at line 228 of file chan_agent.c.

ast_group_t group [static]

Definition at line 221 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 230 of file chan_agent.c.

char moh[80] = "default" [static]
const char pa_family[] = "Agents" [static]

Persistent Agents astdb family

Definition at line 215 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 233 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 234 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 235 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 237 of file chan_agent.c.

const char tdesc[] = "Call Agent Proxy Channel" [static]

Definition at line 203 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 238 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 236 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 223 of file chan_agent.c.


Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1