Wed Apr 6 11:29:54 2011

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...
struct  agents

Defines

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

Enumerations

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

Functions

static int __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static void __reg_module (void)
static void __unreg_module (void)
static int action_agent_logoff (struct mansession *s, const struct message *m)
static int action_agents (struct mansession *s, const struct message *m)
static struct agent_pvtadd_agent (const char *agent, int pending)
static int agent_ack_sleep (void *data)
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 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 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_set_base_channel (struct ast_channel *chan, struct ast_channel *base)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, const char *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static int agents_data_provider_get (const struct ast_data_search *search, struct ast_data *data_root)
static char * agents_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * agents_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 AST_DATA_STRUCTURE (agent_pvt, DATA_EXPORT_AGENT)
static int check_availability (struct agent_pvt *newlyavailable, int needlock)
static int check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state)
static struct agent_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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", }
static char acceptdtmf = DEFAULT_ACCEPTDTMF
static int ackcall
static struct ast_custom_function agent_function
static const char agent_logoff_usage []
static struct ast_channel_tech agent_tech
 Channel interface description for PBX integration.
static char agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static struct ast_data_handler agents_data_provider
static struct ast_data_entry agents_data_providers []
static const char app [] = "AgentLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static struct ast_module_infoast_module_info = &__mod_info
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static const char config [] = "agents.conf"
static int endcall
static char enddtmf = DEFAULT_ENDDTMF
static ast_group_t group
static int maxlogintries = 3
static char moh [80] = "default"
static int multiplelogin = 1
static const char pa_family [] = "Agents"
static int recordagentcalls = 0
static char recordformat [AST_MAX_BUF] = ""
static char recordformatext [AST_MAX_BUF] = ""
static char savecallsin [AST_MAX_BUF] = ""
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int wrapuptime


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

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

#define AST_MAX_BUF   256

Definition at line 211 of file chan_agent.c.

Referenced by __agent_start_monitoring(), agentmonitoroutgoing_exec(), agents_show(), and agents_show_online().

#define AST_MAX_FILENAME_LEN   256

Definition at line 212 of file chan_agent.c.

Referenced by login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define DATA_EXPORT_AGENT ( MEMBER   ) 

Definition at line 283 of file chan_agent.c.

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 217 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 218 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 215 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 514 of file chan_agent.c.

References agent_pvt::agent, ast_cdr_alloc(), ast_cdr_setuserfield(), ast_log(), AST_MAX_BUF, ast_monitor_setjoinfiles(), ast_monitor_start(), ast_verbose, ast_channel::cdr, LOG_ERROR, ast_channel::monitor, ast_channel::uniqueid, X_REC_IN, and X_REC_OUT.

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

00515 {
00516    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00517    char filename[AST_MAX_BUF];
00518    int res = -1;
00519    if (!p)
00520       return -1;
00521    if (!ast->monitor) {
00522       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00523       /* substitute . for - */
00524       if ((pointer = strchr(filename, '.')))
00525          *pointer = '-';
00526       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00527       ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
00528       ast_monitor_setjoinfiles(ast, 1);
00529       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00530 #if 0
00531       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00532 #endif
00533       if (!ast->cdr)
00534          ast->cdr = ast_cdr_alloc();
00535       ast_cdr_setuserfield(ast, tmp2);
00536       res = 0;
00537    } else
00538       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00539    return res;
00540 }

static void __reg_module ( void   )  [static]

Definition at line 2489 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

Definition at line 2489 of file chan_agent.c.

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

Sets an agent as no longer logged in in the Manager API. It is registered on load_module() and it gets called by the manager backend.

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

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

01633 {
01634    const char *agent = astman_get_header(m, "Agent");
01635    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01636    int soft;
01637    int ret; /* return value of agent_logoff */
01638 
01639    if (ast_strlen_zero(agent)) {
01640       astman_send_error(s, m, "No agent specified");
01641       return 0;
01642    }
01643 
01644    soft = ast_true(soft_s) ? 1 : 0;
01645    ret = agent_logoff(agent, soft);
01646    if (ret == 0)
01647       astman_send_ack(s, m, "Agent logged out");
01648    else
01649       astman_send_error(s, m, "No such agent");
01650 
01651    return 0;
01652 }

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.

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

Definition at line 1482 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::agent, ast_bridged_channel(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), ast_channel::caller, agent_pvt::chan, ast_party_caller::id, agent_pvt::list, agent_pvt::lock, agent_pvt::loginstart, ast_channel::name, 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().

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

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

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 384 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, 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::lastdisc, agent_pvt::list, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

00385 {
00386    char *parse;
00387    AST_DECLARE_APP_ARGS(args,
00388       AST_APP_ARG(agt);
00389       AST_APP_ARG(password);
00390       AST_APP_ARG(name);
00391    );
00392    char *password = NULL;
00393    char *name = NULL;
00394    char *agt = NULL;
00395    struct agent_pvt *p;
00396 
00397    parse = ast_strdupa(agent);
00398 
00399    /* Extract username (agt), password and name from agent (args). */
00400    AST_STANDARD_APP_ARGS(args, parse);
00401 
00402    if(args.argc == 0) {
00403       ast_log(LOG_WARNING, "A blank agent line!\n");
00404       return NULL;
00405    }
00406 
00407    if(ast_strlen_zero(args.agt) ) {
00408       ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00409       return NULL;
00410    } else
00411       agt = args.agt;
00412 
00413    if(!ast_strlen_zero(args.password)) {
00414       password = args.password;
00415       while (*password && *password < 33) password++;
00416    }
00417    if(!ast_strlen_zero(args.name)) {
00418       name = args.name;
00419       while (*name && *name < 33) name++;
00420    }
00421    
00422    /* Are we searching for the agent here ? To see if it exists already ? */
00423    AST_LIST_TRAVERSE(&agents, p, list) {
00424       if (!pending && !strcmp(p->agent, agt))
00425          break;
00426    }
00427    if (!p) {
00428       // Build the agent.
00429       if (!(p = ast_calloc(1, sizeof(*p))))
00430          return NULL;
00431       ast_copy_string(p->agent, agt, sizeof(p->agent));
00432       ast_mutex_init(&p->lock);
00433       ast_mutex_init(&p->app_lock);
00434       ast_cond_init(&p->app_complete_cond, NULL);
00435       p->app_lock_flag = 0;
00436       p->app_sleep_cond = 1;
00437       p->group = group;
00438       p->pending = pending;
00439       AST_LIST_INSERT_TAIL(&agents, p, list);
00440    }
00441    
00442    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00443    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00444    ast_copy_string(p->moh, moh, sizeof(p->moh));
00445    if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) {
00446       p->ackcall = ackcall;
00447    }
00448    if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) {
00449       p->autologoff = autologoff;
00450    }
00451    if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) {
00452       p->acceptdtmf = acceptdtmf;
00453    }
00454    if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) {
00455       p->enddtmf = enddtmf;
00456    }
00457 
00458    /* If someone reduces the wrapuptime and reloads, we want it
00459     * to change the wrapuptime immediately on all calls */
00460    if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) {
00461       struct timeval now = ast_tvnow();
00462       /* XXX check what is this exactly */
00463 
00464       /* We won't be pedantic and check the tv_usec val */
00465       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00466          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00467          p->lastdisc.tv_usec = now.tv_usec;
00468       }
00469    }
00470    p->wrapuptime = wrapuptime;
00471 
00472    if (pending)
00473       p->dead = 1;
00474    else
00475       p->dead = 0;
00476    return p;
00477 }

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 971 of file chan_agent.c.

References agent_pvt::acceptdtmf, agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_waitfor(), agent_pvt::chan, f, and agent_pvt::lock.

Referenced by login_exec().

00972 {
00973    struct agent_pvt *p;
00974    int res=0;
00975    int to = 1000;
00976    struct ast_frame *f;
00977 
00978    /* Wait a second and look for something */
00979 
00980    p = (struct agent_pvt *) data;
00981    if (!p->chan) 
00982       return -1;
00983 
00984    for(;;) {
00985       to = ast_waitfor(p->chan, to);
00986       if (to < 0) 
00987          return -1;
00988       if (!to) 
00989          return 0;
00990       f = ast_read(p->chan);
00991       if (!f) 
00992          return -1;
00993       if (f->frametype == AST_FRAME_DTMF)
00994          res = f->subclass.integer;
00995       else
00996          res = 0;
00997       ast_frfree(f);
00998       ast_mutex_lock(&p->lock);
00999       if (!p->app_sleep_cond) {
01000          ast_mutex_unlock(&p->lock);
01001          return 0;
01002       } else if (res == p->acceptdtmf) {
01003          ast_mutex_unlock(&p->lock);
01004          return 1;
01005       }
01006       ast_mutex_unlock(&p->lock);
01007       res = 0;
01008    }
01009    return res;
01010 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 508 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00509 {
00510    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00511    return -1;
00512 }

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

Definition at line 1012 of file chan_agent.c.

References ast_debug, ast_channel::bridge, agent_pvt::chan, ast_channel::name, and ast_channel::tech_pvt.

01013 {
01014    struct agent_pvt *p = bridge->tech_pvt;
01015    struct ast_channel *ret = NULL;
01016 
01017    if (p) {
01018       if (chan == p->chan)
01019          ret = bridge->_bridge;
01020       else if (chan == bridge->_bridge)
01021          ret = p->chan;
01022    }
01023 
01024    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01025    return ret;
01026 }

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

Definition at line 772 of file chan_agent.c.

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

00773 {
00774    struct agent_pvt *p = ast->tech_pvt;
00775    int res = -1;
00776    int newstate=0;
00777    ast_mutex_lock(&p->lock);
00778    p->acknowledged = 0;
00779    if (!p->chan) {
00780       if (p->pending) {
00781          ast_debug(1, "Pretending to dial on pending agent\n");
00782          newstate = AST_STATE_DIALING;
00783          res = 0;
00784       } else {
00785          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00786          res = -1;
00787       }
00788       ast_mutex_unlock(&p->lock);
00789       if (newstate)
00790          ast_setstate(ast, newstate);
00791       return res;
00792    }
00793    ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00794    ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
00795    res = ast_streamfile(p->chan, beep, p->chan->language);
00796    ast_debug(3, "Played beep, result '%d'\n", res);
00797    if (!res) {
00798       res = ast_waitstream(p->chan, "");
00799       ast_debug(3, "Waited for stream, result '%d'\n", res);
00800    }
00801    if (!res) {
00802       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00803       ast_debug(3, "Set read format, result '%d'\n", res);
00804       if (res)
00805          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00806    } else {
00807       /* Agent hung-up */
00808       p->chan = NULL;
00809       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00810    }
00811 
00812    if (!res) {
00813       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00814       ast_debug(3, "Set write format, result '%d'\n", res);
00815       if (res)
00816          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00817    }
00818    if(!res) {
00819       /* Call is immediately up, or might need ack */
00820       if (p->ackcall) {
00821          newstate = AST_STATE_RINGING;
00822       } else {
00823          newstate = AST_STATE_UP;
00824          if (recordagentcalls)
00825             agent_start_monitoring(ast, 0);
00826          p->acknowledged = 1;
00827       }
00828       res = 0;
00829    }
00830    CLEANUP(ast, p);
00831    ast_mutex_unlock(&p->lock);
00832    if (newstate)
00833       ast_setstate(ast, newstate);
00834    return res;
00835 }

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.

Parameters:
p Agent to be deleted.
Returns:
Always 0.

Definition at line 485 of file chan_agent.c.

References agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_release(), ast_cond_destroy, ast_cond_signal, ast_free, ast_mutex_destroy, agent_pvt::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

00486 {
00487    struct ast_channel *chan = p->owner;
00488    p->owner = NULL;
00489    chan->tech_pvt = NULL;
00490    p->app_sleep_cond = 1;
00491    /* Release ownership of the agent to other threads (presumably running the login app). */
00492    p->app_lock_flag = 0;
00493    ast_cond_signal(&p->app_complete_cond);
00494    if (chan) {
00495       chan = ast_channel_release(chan);
00496    }
00497    if (p->dead) {
00498       ast_mutex_destroy(&p->lock);
00499       ast_mutex_destroy(&p->app_lock);
00500       ast_cond_destroy(&p->app_complete_cond);
00501       ast_free(p);
00502         }
00503    return 0;
00504 }

static int agent_cont_sleep ( void *  data  )  [static]

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

00951 {
00952    struct agent_pvt *p;
00953    int res;
00954 
00955    p = (struct agent_pvt *)data;
00956 
00957    ast_mutex_lock(&p->lock);
00958    res = p->app_sleep_cond;
00959    if (p->lastdisc.tv_sec) {
00960       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00961          res = 1;
00962    }
00963    ast_mutex_unlock(&p->lock);
00964 
00965    if (!res)
00966       ast_debug(5, "agent_cont_sleep() returning %d\n", res );
00967 
00968    return res;
00969 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2211 of file chan_agent.c.

References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, agent_pvt::group, agent_pvt::list, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.

02212 {
02213    struct agent_pvt *p;
02214    char *s;
02215    ast_group_t groupmatch;
02216    int groupoff;
02217    int res = AST_DEVICE_INVALID;
02218    
02219    s = data;
02220    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02221       groupmatch = (1 << groupoff);
02222    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02223       groupmatch = (1 << groupoff);
02224    } else 
02225       groupmatch = 0;
02226 
02227    /* Check actual logged in agents first */
02228    AST_LIST_LOCK(&agents);
02229    AST_LIST_TRAVERSE(&agents, p, list) {
02230       ast_mutex_lock(&p->lock);
02231       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02232          if (p->owner) {
02233             if (res != AST_DEVICE_INUSE)
02234                res = AST_DEVICE_BUSY;
02235          } else {
02236             if (res == AST_DEVICE_BUSY)
02237                res = AST_DEVICE_INUSE;
02238             if (p->chan) {
02239                if (res == AST_DEVICE_INVALID)
02240                   res = AST_DEVICE_UNKNOWN;
02241             } else if (res == AST_DEVICE_INVALID)  
02242                res = AST_DEVICE_UNAVAILABLE;
02243          }
02244          if (!strcmp(data, p->agent)) {
02245             ast_mutex_unlock(&p->lock);
02246             break;
02247          }
02248       }
02249       ast_mutex_unlock(&p->lock);
02250    }
02251    AST_LIST_UNLOCK(&agents);
02252    return res;
02253 }

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

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

00751 {
00752    struct agent_pvt *p = ast->tech_pvt;
00753    ast_mutex_lock(&p->lock);
00754    if (p->chan) {
00755       ast_senddigit_begin(p->chan, digit);
00756    }
00757    ast_mutex_unlock(&p->lock);
00758    return 0;
00759 }

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

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

00762 {
00763    struct agent_pvt *p = ast->tech_pvt;
00764    ast_mutex_lock(&p->lock);
00765    if (p->chan) {
00766       ast_senddigit_end(p->chan, digit, duration);
00767    }
00768    ast_mutex_unlock(&p->lock);
00769    return 0;
00770 }

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

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

00713 {
00714    struct agent_pvt *p = newchan->tech_pvt;
00715    ast_mutex_lock(&p->lock);
00716    if (p->owner != oldchan) {
00717       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00718       ast_mutex_unlock(&p->lock);
00719       return -1;
00720    }
00721    p->owner = newchan;
00722    ast_mutex_unlock(&p->lock);
00723    return 0;
00724 }

struct ast_channel * agent_get_base_channel ( struct ast_channel chan  )  [static]

return the channel or base channel if one exists. This function assumes the channel it is called on is already locked

Definition at line 838 of file chan_agent.c.

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

00839 {
00840    struct agent_pvt *p = NULL;
00841    struct ast_channel *base = chan;
00842 
00843    /* chan is locked by the calling function */
00844    if (!chan || !chan->tech_pvt) {
00845       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);
00846       return NULL;
00847    }
00848    p = chan->tech_pvt;
00849    if (p->chan) 
00850       base = p->chan;
00851    return base;
00852 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 871 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_signal, AST_CONTROL_HOLD, ast_debug, AST_DEVICE_NOT_INUSE, ast_devstate_changed(), ast_free, ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), ast_tvnow(), agent_pvt::chan, agent_pvt::dead, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, agent_pvt::logincallerid, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::owner, agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.

00872 {
00873    struct agent_pvt *p = ast->tech_pvt;
00874    int howlong = 0;
00875 
00876    ast_mutex_lock(&p->lock);
00877    p->owner = NULL;
00878    ast->tech_pvt = NULL;
00879    p->app_sleep_cond = 1;
00880    p->acknowledged = 0;
00881 
00882    /* if they really are hung up then set start to 0 so the test
00883     * later if we're called on an already downed channel
00884     * doesn't cause an agent to be logged out like when
00885     * agent_request() is followed immediately by agent_hangup()
00886     * as in apps/app_chanisavail.c:chanavail_exec()
00887     */
00888 
00889    ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
00890    if (p->start && (ast->_state != AST_STATE_UP)) {
00891       howlong = time(NULL) - p->start;
00892       p->start = 0;
00893    } else if (ast->_state == AST_STATE_RESERVED) 
00894       howlong = 0;
00895    else
00896       p->start = 0; 
00897    if (p->chan) {
00898       p->chan->_bridge = NULL;
00899       /* If they're dead, go ahead and hang up on the agent now */
00900       if (p->dead) {
00901          ast_channel_lock(p->chan);
00902          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00903          ast_channel_unlock(p->chan);
00904       } else if (p->loginstart) {
00905          ast_channel_lock(p->chan);
00906          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00907             S_OR(p->moh, NULL),
00908             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00909          ast_channel_unlock(p->chan);
00910       }
00911    }
00912    ast_mutex_unlock(&p->lock);
00913 
00914    /* Only register a device state change if the agent is still logged in */
00915    if (!p->loginstart) {
00916       p->logincallerid[0] = '\0';
00917    } else {
00918       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
00919    }
00920 
00921    if (p->pending) {
00922       AST_LIST_LOCK(&agents);
00923       AST_LIST_REMOVE(&agents, p, list);
00924       AST_LIST_UNLOCK(&agents);
00925    }
00926    if (p->abouttograb) {
00927       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00928          kill it later */
00929       p->abouttograb = 0;
00930    } else if (p->dead) {
00931       ast_mutex_destroy(&p->lock);
00932       ast_mutex_destroy(&p->app_lock);
00933       ast_cond_destroy(&p->app_complete_cond);
00934       ast_free(p);
00935    } else {
00936       if (p->chan) {
00937          /* Not dead -- check availability now */
00938          ast_mutex_lock(&p->lock);
00939          /* Store last disconnect time */
00940          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00941          ast_mutex_unlock(&p->lock);
00942       }
00943       /* Release ownership of the agent to other threads (presumably running the login app). */
00944       p->app_lock_flag = 0;
00945       ast_cond_signal(&p->app_complete_cond);
00946    }
00947    return 0;
00948 }

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

Definition at line 726 of file chan_agent.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_log(), ast_mutex_lock, ast_mutex_unlock, agent_pvt::chan, ast_channel_tech::indicate, agent_pvt::lock, LOG_ERROR, ast_channel::tech, and ast_channel::tech_pvt.

00727 {
00728    struct agent_pvt *p = ast->tech_pvt;
00729    int res = -1;
00730    ast_mutex_lock(&p->lock);
00731    if (p->chan && !ast_check_hangup(p->chan)) {
00732       while (ast_channel_trylock(p->chan)) {
00733          int res;
00734          if ((res = ast_channel_unlock(ast))) {
00735             ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res));
00736             ast_mutex_unlock(&p->lock);
00737             return -1;
00738          }
00739          usleep(1);
00740          ast_channel_lock(ast);
00741       }
00742       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00743       ast_channel_unlock(p->chan);
00744    } else
00745       res = 0;
00746    ast_mutex_unlock(&p->lock);
00747    return res;
00748 }

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

Definition at line 1553 of file chan_agent.c.

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

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01554 {
01555    struct agent_pvt *p;
01556    int ret = -1; /* Return -1 if no agent if found */
01557 
01558    AST_LIST_LOCK(&agents);
01559    AST_LIST_TRAVERSE(&agents, p, list) {
01560       if (!strcasecmp(p->agent, agent)) {
01561          ret = 0;
01562          if (p->owner || p->chan) {
01563             if (!soft) {
01564                ast_mutex_lock(&p->lock);
01565 
01566                while (p->owner && ast_channel_trylock(p->owner)) {
01567                   DEADLOCK_AVOIDANCE(&p->lock);
01568                }
01569                if (p->owner) {
01570                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01571                   ast_channel_unlock(p->owner);
01572                }
01573 
01574                while (p->chan && ast_channel_trylock(p->chan)) {
01575                   DEADLOCK_AVOIDANCE(&p->lock);
01576                }
01577                if (p->chan) {
01578                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01579                   ast_channel_unlock(p->chan);
01580                }
01581 
01582                ast_mutex_unlock(&p->lock);
01583             } else
01584                p->deferlogoff = 1;
01585          }
01586          break;
01587       }
01588    }
01589    AST_LIST_UNLOCK(&agents);
01590 
01591    return ret;
01592 }

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

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

01595 {
01596    int ret;
01597    const char *agent;
01598 
01599    switch (cmd) {
01600    case CLI_INIT:
01601       e->command = "agent logoff";
01602       e->usage =
01603          "Usage: agent logoff <channel> [soft]\n"
01604          "       Sets an agent as no longer logged in.\n"
01605          "       If 'soft' is specified, do not hangup existing calls.\n";
01606       return NULL;
01607    case CLI_GENERATE:
01608       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01609    }
01610 
01611    if (a->argc < 3 || a->argc > 4)
01612       return CLI_SHOWUSAGE;
01613    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01614       return CLI_SHOWUSAGE;
01615 
01616    agent = a->argv[2] + 6;
01617    ret = agent_logoff(agent, a->argc == 4);
01618    if (ret == 0)
01619       ast_cli(a->fd, "Logging out %s\n", agent);
01620 
01621    return CLI_SUCCESS;
01622 }

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

Create new agent channel.

Definition at line 1029 of file chan_agent.c.

References agent_pvt::agent, agent_tech, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_alloc, ast_channel_release(), ast_cond_signal, AST_CONTROL_UNHOLD, ast_copy_string(), AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::pending, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by agent_request(), and check_availability().

01030 {
01031    struct ast_channel *tmp;
01032    int alreadylocked;
01033 #if 0
01034    if (!p->chan) {
01035       ast_log(LOG_WARNING, "No channel? :(\n");
01036       return NULL;
01037    }
01038 #endif   
01039    if (p->pending)
01040       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);
01041    else
01042       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent);
01043    if (!tmp) {
01044       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01045       return NULL;
01046    }
01047 
01048    tmp->tech = &agent_tech;
01049    if (p->chan) {
01050       tmp->nativeformats = p->chan->nativeformats;
01051       tmp->writeformat = p->chan->writeformat;
01052       tmp->rawwriteformat = p->chan->writeformat;
01053       tmp->readformat = p->chan->readformat;
01054       tmp->rawreadformat = p->chan->readformat;
01055       ast_string_field_set(tmp, language, p->chan->language);
01056       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01057       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01058       /* XXX Is this really all we copy form the originating channel?? */
01059    } else {
01060       tmp->nativeformats = AST_FORMAT_SLINEAR;
01061       tmp->writeformat = AST_FORMAT_SLINEAR;
01062       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01063       tmp->readformat = AST_FORMAT_SLINEAR;
01064       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01065    }
01066    /* Safe, agentlock already held */
01067    tmp->tech_pvt = p;
01068    p->owner = tmp;
01069    tmp->priority = 1;
01070    /* Wake up and wait for other applications (by definition the login app)
01071     * to release this channel). Takes ownership of the agent channel
01072     * to this thread only.
01073     * For signalling the other thread, ast_queue_frame is used until we
01074     * can safely use signals for this purpose. The pselect() needs to be
01075     * implemented in the kernel for this.
01076     */
01077    p->app_sleep_cond = 0;
01078 
01079    alreadylocked = p->app_lock_flag;
01080    p->app_lock_flag = 1;
01081 
01082    if (alreadylocked) {
01083       if (p->chan) {
01084          ast_queue_frame(p->chan, &ast_null_frame);
01085          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01086          p->app_lock_flag = 1;
01087          ast_mutex_lock(&p->lock);
01088       } else {
01089          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01090          p->owner = NULL;
01091          tmp->tech_pvt = NULL;
01092          p->app_sleep_cond = 1;
01093          tmp = ast_channel_release(tmp);
01094          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01095          p->app_lock_flag = 0;
01096          ast_cond_signal(&p->app_complete_cond);
01097          return NULL;
01098       }
01099    } 
01100    if (p->chan)
01101       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01102    return tmp;
01103 }

static struct ast_frame * agent_read ( struct ast_channel ast  )  [static]

Definition at line 547 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_ANSWER, ast_copy_flags, ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_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, agent_pvt::lock, LOG_NOTICE, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::start, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.

00548 {
00549    struct agent_pvt *p = ast->tech_pvt;
00550    struct ast_frame *f = NULL;
00551    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
00552    int cur_time = time(NULL);
00553    ast_mutex_lock(&p->lock);
00554    CHECK_FORMATS(ast, p);
00555    if (!p->start) {
00556       p->start = cur_time;
00557    }
00558    if (p->chan) {
00559       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00560       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00561       f = ast_read(p->chan);
00562    } else
00563       f = &ast_null_frame;
00564    if (!f) {
00565       /* If there's a channel, make it NULL */
00566       if (p->chan) {
00567          p->chan->_bridge = NULL;
00568          p->chan = NULL;
00569          ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00570          p->acknowledged = 0;
00571       }
00572    } else {
00573       /* if acknowledgement is not required, and the channel is up, we may have missed
00574          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00575       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00576          p->acknowledged = 1;
00577       }
00578 
00579       if (!p->acknowledged) {
00580          int howlong = cur_time - p->start;
00581          if (p->autologoff && (howlong >= p->autologoff)) {
00582             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00583             if (p->owner || p->chan) {
00584                while (p->owner && ast_channel_trylock(p->owner)) {
00585                   DEADLOCK_AVOIDANCE(&p->lock);
00586                }
00587                if (p->owner) {
00588                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
00589                   ast_channel_unlock(p->owner);
00590                }
00591 
00592                while (p->chan && ast_channel_trylock(p->chan)) {
00593                   DEADLOCK_AVOIDANCE(&p->lock);
00594                }
00595                if (p->chan) {
00596                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00597                   ast_channel_unlock(p->chan);
00598                }
00599             }
00600          }
00601       }
00602       switch (f->frametype) {
00603       case AST_FRAME_CONTROL:
00604          if (f->subclass.integer == AST_CONTROL_ANSWER) {
00605             if (p->ackcall) {
00606                ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf);
00607                /* Don't pass answer along */
00608                ast_frfree(f);
00609                f = &ast_null_frame;
00610             } else {
00611                p->acknowledged = 1;
00612                /* Use the builtin answer frame for the 
00613                   recording start check below. */
00614                ast_frfree(f);
00615                f = &answer_frame;
00616             }
00617          }
00618          break;
00619       case AST_FRAME_DTMF_BEGIN:
00620          /*ignore DTMF begin's as it can cause issues with queue announce files*/
00621          if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){
00622             ast_frfree(f);
00623             f = &ast_null_frame;
00624          }
00625          break;
00626       case AST_FRAME_DTMF_END:
00627          if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) {
00628             ast_verb(3, "%s acknowledged\n", p->chan->name);
00629             p->acknowledged = 1;
00630             ast_frfree(f);
00631             f = &answer_frame;
00632          } else if (f->subclass.integer == p->enddtmf && endcall) {
00633             /* terminates call */
00634             ast_frfree(f);
00635             f = NULL;
00636          }
00637          break;
00638       case AST_FRAME_VOICE:
00639       case AST_FRAME_VIDEO:
00640          /* don't pass voice or video until the call is acknowledged */
00641          if (!p->acknowledged) {
00642             ast_frfree(f);
00643             f = &ast_null_frame;
00644          }
00645       default:
00646          /* pass everything else on through */
00647          break;
00648       }
00649    }
00650 
00651    CLEANUP(ast,p);
00652    if (p->chan && !p->chan->_bridge) {
00653       if (strcasecmp(p->chan->tech->type, "Local")) {
00654          p->chan->_bridge = ast;
00655          if (p->chan)
00656             ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00657       }
00658    }
00659    ast_mutex_unlock(&p->lock);
00660    if (recordagentcalls && f == &answer_frame)
00661       agent_start_monitoring(ast,0);
00662    return f;
00663 }

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

Part of the Asterisk PBX interface.

Definition at line 1377 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, AST_STATE_DOWN, ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, ast_channel::linkedid, agent_pvt::list, agent_pvt::lock, LOG_WARNING, agent_pvt::owner, and agent_pvt::pending.

01378 {
01379    struct agent_pvt *p;
01380    struct ast_channel *chan = NULL;
01381    char *s;
01382    ast_group_t groupmatch;
01383    int groupoff;
01384    int waitforagent=0;
01385    int hasagent = 0;
01386    struct timeval now;
01387 
01388    s = data;
01389    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01390       groupmatch = (1 << groupoff);
01391    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01392       groupmatch = (1 << groupoff);
01393       waitforagent = 1;
01394    } else 
01395       groupmatch = 0;
01396 
01397    /* Check actual logged in agents first */
01398    AST_LIST_LOCK(&agents);
01399    AST_LIST_TRAVERSE(&agents, p, list) {
01400       ast_mutex_lock(&p->lock);
01401       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01402          if (p->chan)
01403             hasagent++;
01404          now = ast_tvnow();
01405          if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01406             p->lastdisc = ast_tv(0, 0);
01407             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01408             if (!p->owner && p->chan) {
01409                /* Fixed agent */
01410                chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01411             }
01412             if (chan) {
01413                ast_mutex_unlock(&p->lock);
01414                break;
01415             }
01416          }
01417       }
01418       ast_mutex_unlock(&p->lock);
01419    }
01420    if (!p) {
01421       AST_LIST_TRAVERSE(&agents, p, list) {
01422          ast_mutex_lock(&p->lock);
01423          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01424             if (p->chan) {
01425                hasagent++;
01426             }
01427             now = ast_tvnow();
01428             if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01429                p->lastdisc = ast_tv(0, 0);
01430                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01431                if (!p->owner && p->chan) {
01432                   /* Could still get a fixed agent */
01433                   chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01434                }
01435                if (chan) {
01436                   ast_mutex_unlock(&p->lock);
01437                   break;
01438                }
01439             }
01440          }
01441          ast_mutex_unlock(&p->lock);
01442       }
01443    }
01444 
01445    if (!chan && waitforagent) {
01446       /* No agent available -- but we're requesting to wait for one.
01447          Allocate a place holder */
01448       if (hasagent) {
01449          ast_debug(1, "Creating place holder for '%s'\n", s);
01450          p = add_agent(data, 1);
01451          p->group = groupmatch;
01452          chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01453          if (!chan) 
01454             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01455       } else {
01456          ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
01457       }
01458    }
01459    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01460    AST_LIST_UNLOCK(&agents);
01461    return chan;
01462 }

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

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

00666 {
00667    struct agent_pvt *p = ast->tech_pvt;
00668    int res = -1;
00669    ast_mutex_lock(&p->lock);
00670    if (p->chan) 
00671       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00672    ast_mutex_unlock(&p->lock);
00673    return res;
00674 }

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

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

00677 {
00678    struct agent_pvt *p = ast->tech_pvt;
00679    int res = -1;
00680    ast_mutex_lock(&p->lock);
00681    if (p->chan) 
00682       res = ast_sendtext(p->chan, text);
00683    ast_mutex_unlock(&p->lock);
00684    return res;
00685 }

int agent_set_base_channel ( struct ast_channel chan,
struct ast_channel base 
) [static]

Definition at line 854 of file chan_agent.c.

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

00855 {
00856    struct agent_pvt *p = NULL;
00857    
00858    if (!chan || !base) {
00859       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00860       return -1;
00861    }
00862    p = chan->tech_pvt;
00863    if (!p) {
00864       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00865       return -1;
00866    }
00867    p->chan = base;
00868    return 0;
00869 }

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

Definition at line 542 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00543 {
00544    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00545 }

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

Definition at line 687 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, f, agent_pvt::lock, ast_channel::name, ast_channel::tech_pvt, and ast_channel::writeformat.

00688 {
00689    struct agent_pvt *p = ast->tech_pvt;
00690    int res = -1;
00691    CHECK_FORMATS(ast, p);
00692    ast_mutex_lock(&p->lock);
00693    if (!p->chan) 
00694       res = 0;
00695    else {
00696       if ((f->frametype != AST_FRAME_VOICE) ||
00697           (f->frametype != AST_FRAME_VIDEO) ||
00698           (f->subclass.codec == p->chan->writeformat)) {
00699          res = ast_write(p->chan, f);
00700       } else {
00701          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00702             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00703             ast->name, p->chan->name);
00704          res = 0;
00705       }
00706    }
00707    CLEANUP(ast, p);
00708    ast_mutex_unlock(&p->lock);
00709    return res;
00710 }

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 2158 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, agent_pvt::chan, ast_cdr::channel, GETAGENTBYCALLERID, ast_party_caller::id, agent_pvt::list, LOG_WARNING, ast_party_id::number, pbx_builtin_getvar_helper(), ast_party_number::str, and ast_party_number::valid.

Referenced by load_module().

02159 {
02160    int exitifnoagentid = 0;
02161    int nowarnings = 0;
02162    int changeoutgoing = 0;
02163    int res = 0;
02164    char agent[AST_MAX_AGENT];
02165 
02166    if (data) {
02167       if (strchr(data, 'd'))
02168          exitifnoagentid = 1;
02169       if (strchr(data, 'n'))
02170          nowarnings = 1;
02171       if (strchr(data, 'c'))
02172          changeoutgoing = 1;
02173    }
02174    if (chan->caller.id.number.valid
02175       && !ast_strlen_zero(chan->caller.id.number.str)) {
02176       const char *tmp;
02177       char agentvar[AST_MAX_BUF];
02178       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
02179          chan->caller.id.number.str);
02180       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02181          struct agent_pvt *p;
02182          ast_copy_string(agent, tmp, sizeof(agent));
02183          AST_LIST_LOCK(&agents);
02184          AST_LIST_TRAVERSE(&agents, p, list) {
02185             if (!strcasecmp(p->agent, tmp)) {
02186                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02187                __agent_start_monitoring(chan, p, 1);
02188                break;
02189             }
02190          }
02191          AST_LIST_UNLOCK(&agents);
02192          
02193       } else {
02194          res = -1;
02195          if (!nowarnings)
02196             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);
02197       }
02198    } else {
02199       res = -1;
02200       if (!nowarnings)
02201          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");
02202    }
02203    if (res) {
02204       if (exitifnoagentid)
02205          return res;
02206    }
02207    return 0;
02208 }

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

Definition at line 2349 of file chan_agent.c.

References agent_pvt::agent, ast_bridged_channel(), ast_channel_data_add_structure(), 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::list, agent_pvt::lock, agent_pvt::moh, agent_pvt::owner, and agent_pvt::pending.

02351 {
02352    struct agent_pvt *p;
02353    struct ast_data *data_agent, *data_channel, *data_talkingto;
02354 
02355    AST_LIST_LOCK(&agents);
02356    AST_LIST_TRAVERSE(&agents, p, list) {
02357       data_agent = ast_data_add_node(data_root, "agent");
02358       if (!data_agent) {
02359          continue;
02360       }
02361 
02362       ast_mutex_lock(&p->lock);
02363       if (!(p->pending)) {
02364          ast_data_add_str(data_agent, "id", p->agent);
02365          ast_data_add_structure(agent_pvt, data_agent, p);
02366 
02367          ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
02368          if (p->chan) {
02369             data_channel = ast_data_add_node(data_agent, "loggedon");
02370             if (!data_channel) {
02371                ast_mutex_unlock(&p->lock);
02372                ast_data_remove_node(data_root, data_agent);
02373                continue;
02374             }
02375             ast_channel_data_add_structure(data_channel, p->chan, 0);
02376             if (p->owner && ast_bridged_channel(p->owner)) {
02377                data_talkingto = ast_data_add_node(data_agent, "talkingto");
02378                if (!data_talkingto) {
02379                   ast_mutex_unlock(&p->lock);
02380                   ast_data_remove_node(data_root, data_agent);
02381                   continue;
02382                }
02383                ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(p->owner), 0);
02384             }
02385          } else {
02386             ast_data_add_node(data_agent, "talkingto");
02387             ast_data_add_node(data_agent, "loggedon");
02388          }
02389          ast_data_add_str(data_agent, "musiconhold", p->moh);
02390       }
02391       ast_mutex_unlock(&p->lock);
02392 
02393       /* if this agent doesn't match remove the added agent. */
02394       if (!ast_data_search_match(search, data_agent)) {
02395          ast_data_remove_node(data_root, data_agent);
02396       }
02397    }
02398    AST_LIST_UNLOCK(&agents);
02399 
02400    return 0;
02401 }

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

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

01682 {
01683    struct agent_pvt *p;
01684    char username[AST_MAX_BUF];
01685    char location[AST_MAX_BUF] = "";
01686    char talkingto[AST_MAX_BUF] = "";
01687    char music[AST_MAX_BUF];
01688    int count_agents = 0;      /*!< Number of agents configured */
01689    int online_agents = 0;     /*!< Number of online agents */
01690    int offline_agents = 0;    /*!< Number of offline agents */
01691 
01692    switch (cmd) {
01693    case CLI_INIT:
01694       e->command = "agent show";
01695       e->usage =
01696          "Usage: agent show\n"
01697          "       Provides summary information on agents.\n";
01698       return NULL;
01699    case CLI_GENERATE:
01700       return NULL;
01701    }
01702 
01703    if (a->argc != 2)
01704       return CLI_SHOWUSAGE;
01705 
01706    AST_LIST_LOCK(&agents);
01707    AST_LIST_TRAVERSE(&agents, p, list) {
01708       ast_mutex_lock(&p->lock);
01709       if (p->pending) {
01710          if (p->group)
01711             ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01712          else
01713             ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01714       } else {
01715          if (!ast_strlen_zero(p->name))
01716             snprintf(username, sizeof(username), "(%s) ", p->name);
01717          else
01718             username[0] = '\0';
01719          if (p->chan) {
01720             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01721             if (p->owner && ast_bridged_channel(p->owner))
01722                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01723              else 
01724                strcpy(talkingto, " is idle");
01725             online_agents++;
01726          } else {
01727             strcpy(location, "not logged in");
01728             talkingto[0] = '\0';
01729             offline_agents++;
01730          }
01731          if (!ast_strlen_zero(p->moh))
01732             snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01733          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
01734             username, location, talkingto, music);
01735          count_agents++;
01736       }
01737       ast_mutex_unlock(&p->lock);
01738    }
01739    AST_LIST_UNLOCK(&agents);
01740    if ( !count_agents ) 
01741       ast_cli(a->fd, "No Agents are configured in %s\n",config);
01742    else 
01743       ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01744    ast_cli(a->fd, "\n");
01745                    
01746    return CLI_SUCCESS;
01747 }

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

Definition at line 1750 of file chan_agent.c.

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

01751 {
01752    struct agent_pvt *p;
01753    char username[AST_MAX_BUF];
01754    char location[AST_MAX_BUF] = "";
01755    char talkingto[AST_MAX_BUF] = "";
01756    char music[AST_MAX_BUF];
01757    int count_agents = 0;           /* Number of agents configured */
01758    int online_agents = 0;          /* Number of online agents */
01759    int agent_status = 0;           /* 0 means offline, 1 means online */
01760 
01761    switch (cmd) {
01762    case CLI_INIT:
01763       e->command = "agent show online";
01764       e->usage =
01765          "Usage: agent show online\n"
01766          "       Provides a list of all online agents.\n";
01767       return NULL;
01768    case CLI_GENERATE:
01769       return NULL;
01770    }
01771 
01772    if (a->argc != 3)
01773       return CLI_SHOWUSAGE;
01774 
01775    AST_LIST_LOCK(&agents);
01776    AST_LIST_TRAVERSE(&agents, p, list) {
01777       agent_status = 0;       /* reset it to offline */
01778       ast_mutex_lock(&p->lock);
01779       if (!ast_strlen_zero(p->name))
01780          snprintf(username, sizeof(username), "(%s) ", p->name);
01781       else
01782          username[0] = '\0';
01783       if (p->chan) {
01784          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01785          if (p->owner && ast_bridged_channel(p->owner)) 
01786             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01787          else 
01788             strcpy(talkingto, " is idle");
01789          agent_status = 1;
01790          online_agents++;
01791       }
01792       if (!ast_strlen_zero(p->moh))
01793          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01794       if (agent_status)
01795          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01796       count_agents++;
01797       ast_mutex_unlock(&p->lock);
01798    }
01799    AST_LIST_UNLOCK(&agents);
01800    if (!count_agents) 
01801       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01802    else
01803       ast_cli(a->fd, "%d agents online\n", online_agents);
01804    ast_cli(a->fd, "\n");
01805    return CLI_SUCCESS;
01806 }

AST_DATA_STRUCTURE ( agent_pvt  ,
DATA_EXPORT_AGENT   
)

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

Definition at line 1275 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), ast_copy_string(), ast_debug, AST_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_set_flag, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, ast_channel::language, ast_channel::linkedid, agent_pvt::list, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.

Referenced by login_exec().

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

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

Definition at line 1340 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::agent, ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, ast_channel::language, agent_pvt::list, agent_pvt::lock, ast_channel::name, agent_pvt::owner, and agent_pvt::pending.

Referenced by login_exec().

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

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

Definition at line 1654 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::list, agent_pvt::loginstart, and agent_pvt::name.

Referenced by agent_logoff_cmd().

01655 {
01656    char *ret = NULL;
01657 
01658    if (pos == 2) {
01659       struct agent_pvt *p;
01660       char name[AST_MAX_AGENT];
01661       int which = 0, len = strlen(word);
01662 
01663       AST_LIST_LOCK(&agents);
01664       AST_LIST_TRAVERSE(&agents, p, list) {
01665          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01666          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01667             ret = ast_strdup(name);
01668             break;
01669          }
01670       }
01671       AST_LIST_UNLOCK(&agents);
01672    } else if (pos == 3 && state == 0) 
01673       return ast_strdup("soft");
01674    
01675    return ret;
01676 }

static struct agent_pvt* find_agent ( char *  agentid  )  [static]

Note:
This function expects the agent list to be locked

Definition at line 2258 of file chan_agent.c.

References agent_pvt::agent, AST_LIST_TRAVERSE, and agent_pvt::list.

Referenced by function_agent().

02259 {
02260    struct agent_pvt *cur;
02261 
02262    AST_LIST_TRAVERSE(&agents, cur, list) {
02263       if (!strcmp(cur->agent, agentid))
02264          break;   
02265    }
02266 
02267    return cur; 
02268 }

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

Definition at line 2270 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(), find_agent(), LOG_WARNING, parse(), and status.

02271 {
02272    char *parse;    
02273    AST_DECLARE_APP_ARGS(args,
02274       AST_APP_ARG(agentid);
02275       AST_APP_ARG(item);
02276    );
02277    char *tmp;
02278    struct agent_pvt *agent;
02279 
02280    buf[0] = '\0';
02281 
02282    if (ast_strlen_zero(data)) {
02283       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02284       return -1;
02285    }
02286 
02287    parse = ast_strdupa(data);
02288 
02289    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02290    if (!args.item)
02291       args.item = "status";
02292 
02293    AST_LIST_LOCK(&agents);
02294 
02295    if (!(agent = find_agent(args.agentid))) {
02296       AST_LIST_UNLOCK(&agents);
02297       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02298       return -1;
02299    }
02300 
02301    if (!strcasecmp(args.item, "status")) {
02302       char *status = "LOGGEDOUT";
02303       if (agent->chan) {
02304          status = "LOGGEDIN";
02305       }
02306       ast_copy_string(buf, status, len);
02307    } else if (!strcasecmp(args.item, "password")) 
02308       ast_copy_string(buf, agent->password, len);
02309    else if (!strcasecmp(args.item, "name"))
02310       ast_copy_string(buf, agent->name, len);
02311    else if (!strcasecmp(args.item, "mohclass"))
02312       ast_copy_string(buf, agent->moh, len);
02313    else if (!strcasecmp(args.item, "channel")) {
02314       if (agent->chan) {
02315          ast_channel_lock(agent->chan);
02316          ast_copy_string(buf, agent->chan->name, len);
02317          ast_channel_unlock(agent->chan);
02318          tmp = strrchr(buf, '-');
02319          if (tmp)
02320             *tmp = '\0';
02321       } 
02322    } else if (!strcasecmp(args.item, "fullchannel")) {
02323       if (agent->chan) {
02324          ast_channel_lock(agent->chan);
02325          ast_copy_string(buf, agent->chan->name, len);
02326          ast_channel_unlock(agent->chan);
02327       } 
02328    } else if (!strcasecmp(args.item, "exten")) {
02329       buf[0] = '\0';
02330    }
02331 
02332    AST_LIST_UNLOCK(&agents);
02333 
02334    return 0;
02335 }

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 2419 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().

02420 {
02421    /* Make sure we can register our agent channel type */
02422    if (ast_channel_register(&agent_tech)) {
02423       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02424       return AST_MODULE_LOAD_FAILURE;
02425    }
02426    /* Read in the config */
02427    if (!read_agent_config(0))
02428       return AST_MODULE_LOAD_DECLINE;
02429    /* Dialplan applications */
02430    ast_register_application_xml(app, login_exec);
02431    ast_register_application_xml(app3, agentmonitoroutgoing_exec);
02432 
02433    /* data tree */
02434    ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
02435 
02436    /* Manager commands */
02437    ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
02438    ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
02439 
02440    /* CLI Commands */
02441    ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
02442 
02443    /* Dialplan Functions */
02444    ast_custom_function_register(&agent_function);
02445 
02446    return AST_MODULE_LOAD_SUCCESS;
02447 }

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

References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_wait, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, agent_pvt::chan, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::name, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, update_cdr, and agent_pvt::wrapuptime.

Referenced by load_module().

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

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

Definition at line 1464 of file chan_agent.c.

Referenced by __ast_register_translator(), agents_show(), ast_translate_available_formats(), ast_translate_path_steps(), ast_translator_build_path(), and handle_cli_core_show_translation().

01465 {
01466    int x = ffs(d);
01467 
01468    if (x)
01469       return x - 1;
01470 
01471    return 0;
01472 }

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

References add_agent(), agent_pvt::app_complete_cond, agent_pvt::app_lock, ast_category_browse(), ast_cond_destroy, ast_config_destroy(), ast_config_load, ast_copy_string(), ast_free, ast_get_group(), AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_strlen_zero(), ast_true(), ast_variable_browse(), ast_variable_retrieve(), agent_pvt::chan, CONFIG_FLAG_FILEUNCHANGED, config_flags, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, agent_pvt::dead, agent_pvt::list, agent_pvt::lock, LOG_ERROR, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

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

static int reload ( void   )  [static]

Definition at line 2449 of file chan_agent.c.

References read_agent_config().

02450 {
02451    return read_agent_config(1);
02452 }

static int unload_module ( void   )  [static]

Definition at line 2454 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, agent_pvt::list, and agent_pvt::owner.

02455 {
02456    struct agent_pvt *p;
02457    /* First, take us out of the channel loop */
02458    ast_channel_unregister(&agent_tech);
02459    /* Unregister dialplan functions */
02460    ast_custom_function_unregister(&agent_function);   
02461    /* Unregister CLI commands */
02462    ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
02463    /* Unregister dialplan applications */
02464    ast_unregister_application(app);
02465    ast_unregister_application(app3);
02466    /* Unregister manager command */
02467    ast_manager_unregister("Agents");
02468    ast_manager_unregister("AgentLogoff");
02469    /* Unregister the data tree */
02470    ast_data_unregister(NULL);
02471    /* Unregister channel */
02472    AST_LIST_LOCK(&agents);
02473    /* Hangup all interfaces if they have an owner */
02474    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02475       if (p->owner)
02476          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02477       ast_free(p);
02478    }
02479    AST_LIST_UNLOCK(&agents);
02480    return 0;
02481 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } [static]

Definition at line 2489 of file chan_agent.c.

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

struct ast_custom_function agent_function [static]

Initial value:

 {
   .name = "AGENT",
   .read = function_agent,
}

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

struct ast_data_handler agents_data_provider [static]

Initial value:

Definition at line 2403 of file chan_agent.c.

struct ast_data_entry agents_data_providers[] [static]

Initial value:

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

Definition at line 2408 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 205 of file chan_agent.c.

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

Definition at line 206 of file chan_agent.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2489 of file chan_agent.c.

int autologoff [static]

Definition at line 221 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:

 {
   { .handler =  agents_show , .summary =  "Show status of agents" ,__VA_ARGS__ },
   { .handler =  agents_show_online , .summary =  "Show all online agents" ,__VA_ARGS__ },
   { .handler =  agent_logoff_cmd , .summary =  "Sets an agent offline" ,__VA_ARGS__ },
}

Definition at line 1813 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

Definition at line 203 of file chan_agent.c.

int endcall [static]

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

Referenced by group_destroy().

int maxlogintries = 3 [static]

Definition at line 230 of file chan_agent.c.

char moh[80] = "default" [static]

Definition at line 208 of file chan_agent.c.

Referenced by _get_mohbyname(), _moh_register(), dial_exec_full(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().

int multiplelogin = 1 [static]

Definition at line 225 of file chan_agent.c.

const char pa_family[] = "Agents" [static]

Persistent Agents astdb family

Definition at line 214 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 202 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 222 of file chan_agent.c.


Generated on Wed Apr 6 11:29:54 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7