Sat Mar 10 01:54:50 2012

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 struct ast_channelagent_lock_owner (struct agent_pvt *pvt)
 Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt must enter this function locked and will be returned locked, but this function will unlock the pvt for a short time, so it can't be used while expecting the pvt to remain static. If function returns a non NULL channel, it will need to be unlocked and unrefed once it is no longer needed.
static int agent_logoff (const char *agent, int soft)
static char * agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_channelagent_new (struct agent_pvt *p, int state, const char *linkedid)
 Create new agent channel.
static 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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 211 of file chan_agent.c.

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

#define AST_MAX_BUF   256

Definition at line 212 of file chan_agent.c.

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

#define AST_MAX_FILENAME_LEN   256

Definition at line 213 of file chan_agent.c.

Referenced by login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define DATA_EXPORT_AGENT ( MEMBER   ) 

Definition at line 284 of file chan_agent.c.

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 218 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 219 of file chan_agent.c.

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 242 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec().

#define PA_MAX_LEN   2048

The maximum length of each persistent member agent database entry

Definition at line 216 of file chan_agent.c.


Enumeration Type Documentation

anonymous enum

Enumerator:
AGENT_FLAG_ACKCALL 
AGENT_FLAG_AUTOLOGOFF 
AGENT_FLAG_WRAPUPTIME 
AGENT_FLAG_ACCEPTDTMF 
AGENT_FLAG_ENDDTMF 

Definition at line 244 of file chan_agent.c.

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


Function Documentation

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

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

00556 {
00557    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00558    char filename[AST_MAX_BUF];
00559    int res = -1;
00560    if (!p)
00561       return -1;
00562    if (!ast->monitor) {
00563       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00564       /* substitute . for - */
00565       if ((pointer = strchr(filename, '.')))
00566          *pointer = '-';
00567       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00568       ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
00569       ast_monitor_setjoinfiles(ast, 1);
00570       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00571 #if 0
00572       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00573 #endif
00574       if (!ast->cdr)
00575          ast->cdr = ast_cdr_alloc();
00576       ast_cdr_setuserfield(ast, tmp2);
00577       res = 0;
00578    } else
00579       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00580    return res;
00581 }

static void __reg_module ( void   )  [static]

Definition at line 2613 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

References agent_logoff(), ast_strlen_zero(), ast_true(), astman_get_header(), astman_send_ack(), and astman_send_error().

Referenced by load_module().

01714 {
01715    const char *agent = astman_get_header(m, "Agent");
01716    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01717    int soft;
01718    int ret; /* return value of agent_logoff */
01719 
01720    if (ast_strlen_zero(agent)) {
01721       astman_send_error(s, m, "No agent specified");
01722       return 0;
01723    }
01724 
01725    soft = ast_true(soft_s) ? 1 : 0;
01726    ret = agent_logoff(agent, soft);
01727    if (ret == 0)
01728       astman_send_ack(s, m, "Agent logged out");
01729    else
01730       astman_send_error(s, m, "No such agent");
01731 
01732    return 0;
01733 }

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

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

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

Definition at line 1554 of file chan_agent.c.

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

Referenced by load_module().

01555 {
01556    const char *id = astman_get_header(m,"ActionID");
01557    char idText[256] = "";
01558    struct agent_pvt *p;
01559    char *username = NULL;
01560    char *loginChan = NULL;
01561    char *talkingto = NULL;
01562    char *talkingtoChan = NULL;
01563    char *status = NULL;
01564    struct ast_channel *bridge;
01565 
01566    if (!ast_strlen_zero(id))
01567       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01568    astman_send_ack(s, m, "Agents will follow");
01569    AST_LIST_LOCK(&agents);
01570    AST_LIST_TRAVERSE(&agents, p, list) {
01571       struct ast_channel *owner;
01572       ast_mutex_lock(&p->lock);
01573       owner = agent_lock_owner(p);
01574 
01575       /* Status Values:
01576          AGENT_LOGGEDOFF - Agent isn't logged in
01577          AGENT_IDLE      - Agent is logged in, and waiting for call
01578          AGENT_ONCALL    - Agent is logged in, and on a call
01579          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01580 
01581       username = S_OR(p->name, "None");
01582 
01583       /* Set a default status. It 'should' get changed. */
01584       status = "AGENT_UNKNOWN";
01585 
01586       if (p->chan) {
01587          loginChan = ast_strdupa(p->chan->name);
01588          if (owner && owner->_bridge) {
01589             talkingto = S_COR(p->chan->caller.id.number.valid,
01590                p->chan->caller.id.number.str, "n/a");
01591             if ((bridge = ast_bridged_channel(owner))) {
01592                talkingtoChan = ast_strdupa(bridge->name);
01593             } else {
01594                talkingtoChan = "n/a";
01595             }
01596             status = "AGENT_ONCALL";
01597          } else {
01598             talkingto = "n/a";
01599             talkingtoChan = "n/a";
01600             status = "AGENT_IDLE";
01601          }
01602       } else {
01603          loginChan = "n/a";
01604          talkingto = "n/a";
01605          talkingtoChan = "n/a";
01606          status = "AGENT_LOGGEDOFF";
01607       }
01608 
01609       if (owner) {
01610          ast_channel_unlock(owner);
01611          owner = ast_channel_unref(owner);
01612       }
01613 
01614       astman_append(s, "Event: Agents\r\n"
01615          "Agent: %s\r\n"
01616          "Name: %s\r\n"
01617          "Status: %s\r\n"
01618          "LoggedInChan: %s\r\n"
01619          "LoggedInTime: %d\r\n"
01620          "TalkingTo: %s\r\n"
01621          "TalkingToChan: %s\r\n"
01622          "%s"
01623          "\r\n",
01624          p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
01625       ast_mutex_unlock(&p->lock);
01626    }
01627    AST_LIST_UNLOCK(&agents);
01628    astman_append(s, "Event: AgentsComplete\r\n"
01629       "%s"
01630       "\r\n",idText);
01631    return 0;
01632 }

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 422 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, name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

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

01038 {
01039    struct agent_pvt *p;
01040    int res=0;
01041    int to = 1000;
01042    struct ast_frame *f;
01043 
01044    /* Wait a second and look for something */
01045 
01046    p = (struct agent_pvt *) data;
01047    if (!p->chan) 
01048       return -1;
01049 
01050    for(;;) {
01051       to = ast_waitfor(p->chan, to);
01052       if (to < 0) 
01053          return -1;
01054       if (!to) 
01055          return 0;
01056       f = ast_read(p->chan);
01057       if (!f) 
01058          return -1;
01059       if (f->frametype == AST_FRAME_DTMF)
01060          res = f->subclass.integer;
01061       else
01062          res = 0;
01063       ast_frfree(f);
01064       ast_mutex_lock(&p->lock);
01065       if (!p->app_sleep_cond) {
01066          ast_mutex_unlock(&p->lock);
01067          return 0;
01068       } else if (res == p->acceptdtmf) {
01069          ast_mutex_unlock(&p->lock);
01070          return 1;
01071       }
01072       ast_mutex_unlock(&p->lock);
01073       res = 0;
01074    }
01075    return res;
01076 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 549 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00550 {
00551    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00552    return -1;
00553 }

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

Definition at line 1078 of file chan_agent.c.

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

01079 {
01080    struct agent_pvt *p = bridge->tech_pvt;
01081    struct ast_channel *ret = NULL;
01082 
01083    if (p) {
01084       if (chan == p->chan)
01085          ret = bridge->_bridge;
01086       else if (chan == bridge->_bridge)
01087          ret = p->chan;
01088    }
01089 
01090    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01091    return ret;
01092 }

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

Definition at line 820 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_DEBUG, LOG_WARNING, ast_channel::name, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.

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

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

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

Referenced by check_availability().

00524 {
00525    struct ast_channel *chan = NULL;
00526    ast_mutex_lock(&p->lock);
00527    chan = p->owner;
00528    p->owner = NULL;
00529    chan->tech_pvt = NULL;
00530    /* Release ownership of the agent to other threads (presumably running the login app). */
00531    p->app_sleep_cond = 1;
00532    p->app_lock_flag = 0;
00533    ast_cond_signal(&p->app_complete_cond);
00534    if (chan) {
00535       chan = ast_channel_release(chan);
00536    }
00537    if (p->dead) {
00538       ast_mutex_unlock(&p->lock);
00539       ast_mutex_destroy(&p->lock);
00540       ast_cond_destroy(&p->app_complete_cond);
00541       ast_cond_destroy(&p->login_wait_cond);
00542       ast_free(p);
00543         }
00544    return 0;
00545 }

static int agent_cont_sleep ( void *  data  )  [static]

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

01017 {
01018    struct agent_pvt *p;
01019    int res;
01020 
01021    p = (struct agent_pvt *)data;
01022 
01023    ast_mutex_lock(&p->lock);
01024    res = p->app_sleep_cond;
01025    if (p->lastdisc.tv_sec) {
01026       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
01027          res = 1;
01028    }
01029    ast_mutex_unlock(&p->lock);
01030 
01031    if (!res)
01032       ast_debug(5, "agent_cont_sleep() returning %d\n", res );
01033 
01034    return res;
01035 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

02318 {
02319    struct agent_pvt *p;
02320    char *s;
02321    ast_group_t groupmatch;
02322    int groupoff;
02323    int res = AST_DEVICE_INVALID;
02324    
02325    s = data;
02326    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02327       groupmatch = (1 << groupoff);
02328    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02329       groupmatch = (1 << groupoff);
02330    } else 
02331       groupmatch = 0;
02332 
02333    /* Check actual logged in agents first */
02334    AST_LIST_LOCK(&agents);
02335    AST_LIST_TRAVERSE(&agents, p, list) {
02336       ast_mutex_lock(&p->lock);
02337       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02338          if (p->owner) {
02339             if (res != AST_DEVICE_INUSE)
02340                res = AST_DEVICE_BUSY;
02341          } else {
02342             if (res == AST_DEVICE_BUSY)
02343                res = AST_DEVICE_INUSE;
02344             if (p->chan) {
02345                if (res == AST_DEVICE_INVALID)
02346                   res = AST_DEVICE_UNKNOWN;
02347             } else if (res == AST_DEVICE_INVALID)  
02348                res = AST_DEVICE_UNAVAILABLE;
02349          }
02350          if (!strcmp(data, p->agent)) {
02351             ast_mutex_unlock(&p->lock);
02352             break;
02353          }
02354       }
02355       ast_mutex_unlock(&p->lock);
02356    }
02357    AST_LIST_UNLOCK(&agents);
02358    return res;
02359 }

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

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

00799 {
00800    struct agent_pvt *p = ast->tech_pvt;
00801    ast_mutex_lock(&p->lock);
00802    if (p->chan) {
00803       ast_senddigit_begin(p->chan, digit);
00804    }
00805    ast_mutex_unlock(&p->lock);
00806    return 0;
00807 }

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

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

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

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

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

00761 {
00762    struct agent_pvt *p = newchan->tech_pvt;
00763    ast_mutex_lock(&p->lock);
00764    if (p->owner != oldchan) {
00765       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00766       ast_mutex_unlock(&p->lock);
00767       return -1;
00768    }
00769    p->owner = newchan;
00770    ast_mutex_unlock(&p->lock);
00771    return 0;
00772 }

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

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

00899 {
00900    struct agent_pvt *p = NULL;
00901    struct ast_channel *base = chan;
00902 
00903    /* chan is locked by the calling function */
00904    if (!chan || !chan->tech_pvt) {
00905       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);
00906       return NULL;
00907    }
00908    p = chan->tech_pvt;
00909    if (p->chan) 
00910       base = p->chan;
00911    return base;
00912 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 931 of file chan_agent.c.

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

Referenced by agent_request().

00932 {
00933    struct agent_pvt *p = ast->tech_pvt;
00934    struct ast_channel *indicate_chan = NULL;
00935    char *tmp_moh; /* moh buffer for indicating after unlocking p */
00936 
00937    if (p->pending) {
00938       AST_LIST_LOCK(&agents);
00939       AST_LIST_REMOVE(&agents, p, list);
00940       AST_LIST_UNLOCK(&agents);
00941    }
00942 
00943    ast_mutex_lock(&p->lock);
00944    p->owner = NULL;
00945    ast->tech_pvt = NULL;
00946    p->app_sleep_cond = 1;
00947    p->acknowledged = 0;
00948 
00949    /* Release ownership of the agent to other threads (presumably running the login app). */
00950    p->app_lock_flag = 0;
00951    ast_cond_signal(&p->app_complete_cond);
00952 
00953    /* if they really are hung up then set start to 0 so the test
00954     * later if we're called on an already downed channel
00955     * doesn't cause an agent to be logged out like when
00956     * agent_request() is followed immediately by agent_hangup()
00957     * as in apps/app_chanisavail.c:chanavail_exec()
00958     */
00959 
00960    ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
00961    if (p->start && (ast->_state != AST_STATE_UP)) {
00962       p->start = 0;
00963    } else
00964       p->start = 0;
00965    if (p->chan) {
00966       p->chan->_bridge = NULL;
00967       /* If they're dead, go ahead and hang up on the agent now */
00968       if (p->dead) {
00969          ast_channel_lock(p->chan);
00970          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00971          ast_channel_unlock(p->chan);
00972       } else if (p->loginstart) {
00973          indicate_chan = ast_channel_ref(p->chan);
00974          tmp_moh = ast_strdupa(p->moh);
00975       }
00976    }
00977    ast_mutex_unlock(&p->lock);
00978 
00979    if (indicate_chan) {
00980       ast_channel_lock(indicate_chan);
00981       ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
00982          S_OR(tmp_moh, NULL),
00983          !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
00984       ast_channel_unlock(indicate_chan);
00985       indicate_chan = ast_channel_unref(indicate_chan);
00986    }
00987 
00988    /* Only register a device state change if the agent is still logged in */
00989    if (!p->loginstart) {
00990       p->logincallerid[0] = '\0';
00991    } else {
00992       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
00993    }
00994 
00995    if (p->abouttograb) {
00996       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00997          kill it later */
00998       p->abouttograb = 0;
00999    } else if (p->dead) {
01000       ast_mutex_destroy(&p->lock);
01001       ast_cond_destroy(&p->app_complete_cond);
01002       ast_cond_destroy(&p->login_wait_cond);
01003       ast_free(p);
01004    } else {
01005       if (p->chan) {
01006          /* Not dead -- check availability now */
01007          ast_mutex_lock(&p->lock);
01008          /* Store last disconnect time */
01009          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
01010          ast_mutex_unlock(&p->lock);
01011       }
01012    }
01013    return 0;
01014 }

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

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

00775 {
00776    struct agent_pvt *p = ast->tech_pvt;
00777    int res = -1;
00778    ast_mutex_lock(&p->lock);
00779    if (p->chan && !ast_check_hangup(p->chan)) {
00780       while (ast_channel_trylock(p->chan)) {
00781          int res;
00782          if ((res = ast_channel_unlock(ast))) {
00783             ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", strerror(res));
00784             ast_mutex_unlock(&p->lock);
00785             return -1;
00786          }
00787          usleep(1);
00788          ast_channel_lock(ast);
00789       }
00790       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00791       ast_channel_unlock(p->chan);
00792    } else
00793       res = 0;
00794    ast_mutex_unlock(&p->lock);
00795    return res;
00796 }

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

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

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

Definition at line 387 of file chan_agent.c.

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

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

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

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

Definition at line 1634 of file chan_agent.c.

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

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01635 {
01636    struct agent_pvt *p;
01637    int ret = -1; /* Return -1 if no agent if found */
01638 
01639    AST_LIST_LOCK(&agents);
01640    AST_LIST_TRAVERSE(&agents, p, list) {
01641       if (!strcasecmp(p->agent, agent)) {
01642          ret = 0;
01643          if (p->owner || p->chan) {
01644             if (!soft) {
01645                struct ast_channel *owner;
01646                ast_mutex_lock(&p->lock);
01647                owner = agent_lock_owner(p);
01648 
01649                if (owner) {
01650                   ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
01651                   ast_channel_unlock(owner);
01652                   owner = ast_channel_unref(owner);
01653                }
01654 
01655                while (p->chan && ast_channel_trylock(p->chan)) {
01656                   DEADLOCK_AVOIDANCE(&p->lock);
01657                }
01658                if (p->chan) {
01659                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01660                   ast_channel_unlock(p->chan);
01661                }
01662 
01663                ast_mutex_unlock(&p->lock);
01664             } else
01665                p->deferlogoff = 1;
01666          }
01667          break;
01668       }
01669    }
01670    AST_LIST_UNLOCK(&agents);
01671 
01672    return ret;
01673 }

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

Definition at line 1675 of file chan_agent.c.

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

01676 {
01677    int ret;
01678    const char *agent;
01679 
01680    switch (cmd) {
01681    case CLI_INIT:
01682       e->command = "agent logoff";
01683       e->usage =
01684          "Usage: agent logoff <channel> [soft]\n"
01685          "       Sets an agent as no longer logged in.\n"
01686          "       If 'soft' is specified, do not hangup existing calls.\n";
01687       return NULL;
01688    case CLI_GENERATE:
01689       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01690    }
01691 
01692    if (a->argc < 3 || a->argc > 4)
01693       return CLI_SHOWUSAGE;
01694    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01695       return CLI_SHOWUSAGE;
01696 
01697    agent = a->argv[2] + 6;
01698    ret = agent_logoff(agent, a->argc == 4);
01699    if (ret == 0)
01700       ast_cli(a->fd, "Logging out %s\n", agent);
01701 
01702    return CLI_SUCCESS;
01703 }

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

Create new agent channel.

Definition at line 1095 of file chan_agent.c.

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

Referenced by agent_request(), and check_availability().

01096 {
01097    struct ast_channel *tmp;
01098 #if 0
01099    if (!p->chan) {
01100       ast_log(LOG_WARNING, "No channel? :(\n");
01101       return NULL;
01102    }
01103 #endif   
01104    if (p->pending)
01105       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);
01106    else
01107       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent);
01108    if (!tmp) {
01109       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01110       return NULL;
01111    }
01112 
01113    tmp->tech = &agent_tech;
01114    if (p->chan) {
01115       tmp->nativeformats = p->chan->nativeformats;
01116       tmp->writeformat = p->chan->writeformat;
01117       tmp->rawwriteformat = p->chan->writeformat;
01118       tmp->readformat = p->chan->readformat;
01119       tmp->rawreadformat = p->chan->readformat;
01120       ast_string_field_set(tmp, language, p->chan->language);
01121       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01122       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01123       /* XXX Is this really all we copy form the originating channel?? */
01124    } else {
01125       tmp->nativeformats = AST_FORMAT_SLINEAR;
01126       tmp->writeformat = AST_FORMAT_SLINEAR;
01127       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01128       tmp->readformat = AST_FORMAT_SLINEAR;
01129       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01130    }
01131    /* Safe, agentlock already held */
01132    tmp->tech_pvt = p;
01133    p->owner = tmp;
01134    tmp->priority = 1;
01135    return tmp;
01136 }

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

Definition at line 588 of file chan_agent.c.

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

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

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

References add_agent(), agent_pvt::agent, agent_hangup(), agent_new(), agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, ast_cond_signal, ast_cond_wait, AST_CONTROL_UNHOLD, ast_debug, ast_indicate(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_null_frame, ast_queue_frame(), AST_STATE_DOWN, ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, ast_channel::linkedid, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::owner, and agent_pvt::pending.

01409 {
01410    struct agent_pvt *p;
01411    struct ast_channel *chan = NULL;
01412    char *s;
01413    ast_group_t groupmatch;
01414    int groupoff;
01415    int waitforagent=0;
01416    int hasagent = 0;
01417    struct timeval now;
01418 
01419    s = data;
01420    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01421       groupmatch = (1 << groupoff);
01422    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01423       groupmatch = (1 << groupoff);
01424       waitforagent = 1;
01425    } else 
01426       groupmatch = 0;
01427 
01428    /* Check actual logged in agents first */
01429    AST_LIST_LOCK(&agents);
01430    AST_LIST_TRAVERSE(&agents, p, list) {
01431       ast_mutex_lock(&p->lock);
01432       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01433          if (p->chan)
01434             hasagent++;
01435          now = ast_tvnow();
01436          if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01437             p->lastdisc = ast_tv(0, 0);
01438             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01439             if (!p->owner && p->chan) {
01440                /* Fixed agent */
01441                chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01442             }
01443             if (chan) {
01444                ast_mutex_unlock(&p->lock);
01445                break;
01446             }
01447          }
01448       }
01449       ast_mutex_unlock(&p->lock);
01450    }
01451    if (!p) {
01452       AST_LIST_TRAVERSE(&agents, p, list) {
01453          ast_mutex_lock(&p->lock);
01454          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01455             if (p->chan) {
01456                hasagent++;
01457             }
01458             now = ast_tvnow();
01459             if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01460                p->lastdisc = ast_tv(0, 0);
01461                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01462                if (!p->owner && p->chan) {
01463                   /* Could still get a fixed agent */
01464                   chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01465                }
01466                if (chan) {
01467                   ast_mutex_unlock(&p->lock);
01468                   break;
01469                }
01470             }
01471          }
01472          ast_mutex_unlock(&p->lock);
01473       }
01474    }
01475 
01476    if (!chan && waitforagent) {
01477       /* No agent available -- but we're requesting to wait for one.
01478          Allocate a place holder */
01479       if (hasagent) {
01480          ast_debug(1, "Creating place holder for '%s'\n", s);
01481          p = add_agent(data, 1);
01482          p->group = groupmatch;
01483          chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01484          if (!chan) 
01485             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01486       } else {
01487          ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
01488       }
01489    }
01490    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01491    AST_LIST_UNLOCK(&agents);
01492 
01493    if (chan) {
01494       ast_mutex_lock(&p->lock);
01495       if (p->pending) {
01496          ast_mutex_unlock(&p->lock);
01497          return chan;
01498       }
01499 
01500       if (!p->chan) {
01501          ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01502          *cause = AST_CAUSE_UNREGISTERED;
01503          ast_mutex_unlock(&p->lock);
01504          agent_hangup(chan);
01505          return NULL;
01506       }
01507 
01508       /* we need to take control of the channel from the login app
01509        * thread */
01510       p->app_sleep_cond = 0;
01511       p->app_lock_flag = 1;
01512 
01513       ast_queue_frame(p->chan, &ast_null_frame);
01514       ast_cond_wait(&p->login_wait_cond, &p->lock);
01515 
01516       if (!p->chan) {
01517          ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
01518          p->app_sleep_cond = 1;
01519          p->app_lock_flag = 0;
01520          ast_cond_signal(&p->app_complete_cond);
01521          ast_mutex_unlock(&p->lock);
01522          *cause = AST_CAUSE_UNREGISTERED;
01523          agent_hangup(chan);
01524          return NULL;
01525       }
01526 
01527       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01528       ast_mutex_unlock(&p->lock);
01529    }
01530 
01531    return chan;
01532 }

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

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

00714 {
00715    struct agent_pvt *p = ast->tech_pvt;
00716    int res = -1;
00717    ast_mutex_lock(&p->lock);
00718    if (p->chan) 
00719       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00720    ast_mutex_unlock(&p->lock);
00721    return res;
00722 }

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

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

00725 {
00726    struct agent_pvt *p = ast->tech_pvt;
00727    int res = -1;
00728    ast_mutex_lock(&p->lock);
00729    if (p->chan) 
00730       res = ast_sendtext(p->chan, text);
00731    ast_mutex_unlock(&p->lock);
00732    return res;
00733 }

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

Definition at line 914 of file chan_agent.c.

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

00915 {
00916    struct agent_pvt *p = NULL;
00917    
00918    if (!chan || !base) {
00919       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00920       return -1;
00921    }
00922    p = chan->tech_pvt;
00923    if (!p) {
00924       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00925       return -1;
00926    }
00927    p->chan = base;
00928    return 0;
00929 }

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

Definition at line 583 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00584 {
00585    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00586 }

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

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

00736 {
00737    struct agent_pvt *p = ast->tech_pvt;
00738    int res = -1;
00739    CHECK_FORMATS(ast, p);
00740    ast_mutex_lock(&p->lock);
00741    if (!p->chan) 
00742       res = 0;
00743    else {
00744       if ((f->frametype != AST_FRAME_VOICE) ||
00745           (f->frametype != AST_FRAME_VIDEO) ||
00746           (f->subclass.codec == p->chan->writeformat)) {
00747          res = ast_write(p->chan, f);
00748       } else {
00749          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00750             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00751             ast->name, p->chan->name);
00752          res = 0;
00753       }
00754    }
00755    CLEANUP(ast, p);
00756    ast_mutex_unlock(&p->lock);
00757    return res;
00758 }

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 2264 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_module_user::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().

02265 {
02266    int exitifnoagentid = 0;
02267    int nowarnings = 0;
02268    int changeoutgoing = 0;
02269    int res = 0;
02270    char agent[AST_MAX_AGENT];
02271 
02272    if (data) {
02273       if (strchr(data, 'd'))
02274          exitifnoagentid = 1;
02275       if (strchr(data, 'n'))
02276          nowarnings = 1;
02277       if (strchr(data, 'c'))
02278          changeoutgoing = 1;
02279    }
02280    if (chan->caller.id.number.valid
02281       && !ast_strlen_zero(chan->caller.id.number.str)) {
02282       const char *tmp;
02283       char agentvar[AST_MAX_BUF];
02284       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
02285          chan->caller.id.number.str);
02286       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02287          struct agent_pvt *p;
02288          ast_copy_string(agent, tmp, sizeof(agent));
02289          AST_LIST_LOCK(&agents);
02290          AST_LIST_TRAVERSE(&agents, p, list) {
02291             if (!strcasecmp(p->agent, tmp)) {
02292                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02293                __agent_start_monitoring(chan, p, 1);
02294                break;
02295             }
02296          }
02297          AST_LIST_UNLOCK(&agents);
02298          
02299       } else {
02300          res = -1;
02301          if (!nowarnings)
02302             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);
02303       }
02304    } else {
02305       res = -1;
02306       if (!nowarnings)
02307          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");
02308    }
02309    if (res) {
02310       if (exitifnoagentid)
02311          return res;
02312    }
02313    return 0;
02314 }

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

Definition at line 2455 of file chan_agent.c.

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

02457 {
02458    struct agent_pvt *p;
02459    struct ast_data *data_agent, *data_channel, *data_talkingto;
02460 
02461    AST_LIST_LOCK(&agents);
02462    AST_LIST_TRAVERSE(&agents, p, list) {
02463       struct ast_channel *owner;
02464 
02465       data_agent = ast_data_add_node(data_root, "agent");
02466       if (!data_agent) {
02467          continue;
02468       }
02469 
02470       ast_mutex_lock(&p->lock);
02471       owner = agent_lock_owner(p);
02472 
02473       if (!(p->pending)) {
02474          ast_data_add_str(data_agent, "id", p->agent);
02475          ast_data_add_structure(agent_pvt, data_agent, p);
02476 
02477          ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
02478          if (p->chan) {
02479             data_channel = ast_data_add_node(data_agent, "loggedon");
02480             if (!data_channel) {
02481                ast_mutex_unlock(&p->lock);
02482                ast_data_remove_node(data_root, data_agent);
02483                if (owner) {
02484                   ast_channel_unlock(owner);
02485                   owner = ast_channel_unref(owner);
02486                }
02487                continue;
02488             }
02489             ast_channel_data_add_structure(data_channel, p->chan, 0);
02490             if (owner && ast_bridged_channel(owner)) {
02491                data_talkingto = ast_data_add_node(data_agent, "talkingto");
02492                if (!data_talkingto) {
02493                   ast_mutex_unlock(&p->lock);
02494                   ast_data_remove_node(data_root, data_agent);
02495                   if (owner) {
02496                      ast_channel_unlock(owner);
02497                      owner = ast_channel_unref(owner);
02498                   }
02499                   continue;
02500                }
02501                ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
02502             }
02503          } else {
02504             ast_data_add_node(data_agent, "talkingto");
02505             ast_data_add_node(data_agent, "loggedon");
02506          }
02507          ast_data_add_str(data_agent, "musiconhold", p->moh);
02508       }
02509 
02510       if (owner) {
02511          ast_channel_unlock(owner);
02512          owner = ast_channel_unref(owner);
02513       }
02514 
02515       ast_mutex_unlock(&p->lock);
02516 
02517       /* if this agent doesn't match remove the added agent. */
02518       if (!ast_data_search_match(search, data_agent)) {
02519          ast_data_remove_node(data_root, data_agent);
02520       }
02521    }
02522    AST_LIST_UNLOCK(&agents);
02523 
02524    return 0;
02525 }

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

References agent_pvt::agent, agent_lock_owner(), ast_cli_args::argc, ast_bridged_channel(), ast_channel_unlock, ast_channel_unref, ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_BUF, ast_mutex_lock, ast_mutex_unlock, ast_strlen_zero(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, count_agents(), ast_cli_args::fd, agent_pvt::group, agent_pvt::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.

01763 {
01764    struct agent_pvt *p;
01765    char username[AST_MAX_BUF];
01766    char location[AST_MAX_BUF] = "";
01767    char talkingto[AST_MAX_BUF] = "";
01768    char music[AST_MAX_BUF];
01769    int count_agents = 0;      /*!< Number of agents configured */
01770    int online_agents = 0;     /*!< Number of online agents */
01771    int offline_agents = 0;    /*!< Number of offline agents */
01772 
01773    switch (cmd) {
01774    case CLI_INIT:
01775       e->command = "agent show";
01776       e->usage =
01777          "Usage: agent show\n"
01778          "       Provides summary information on agents.\n";
01779       return NULL;
01780    case CLI_GENERATE:
01781       return NULL;
01782    }
01783 
01784    if (a->argc != 2)
01785       return CLI_SHOWUSAGE;
01786 
01787    AST_LIST_LOCK(&agents);
01788    AST_LIST_TRAVERSE(&agents, p, list) {
01789       struct ast_channel *owner;
01790       ast_mutex_lock(&p->lock);
01791       owner = agent_lock_owner(p);
01792       if (p->pending) {
01793          if (p->group)
01794             ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01795          else
01796             ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01797       } else {
01798          if (!ast_strlen_zero(p->name))
01799             snprintf(username, sizeof(username), "(%s) ", p->name);
01800          else
01801             username[0] = '\0';
01802          if (p->chan) {
01803             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01804             if (owner && ast_bridged_channel(owner)) {
01805                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01806             } else {
01807                strcpy(talkingto, " is idle");
01808             }
01809             online_agents++;
01810          } else {
01811             strcpy(location, "not logged in");
01812             talkingto[0] = '\0';
01813             offline_agents++;
01814          }
01815          if (!ast_strlen_zero(p->moh))
01816             snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01817          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
01818             username, location, talkingto, music);
01819          count_agents++;
01820       }
01821 
01822       if (owner) {
01823          ast_channel_unlock(owner);
01824          owner = ast_channel_unref(owner);
01825       }
01826       ast_mutex_unlock(&p->lock);
01827    }
01828    AST_LIST_UNLOCK(&agents);
01829    if ( !count_agents ) 
01830       ast_cli(a->fd, "No Agents are configured in %s\n",config);
01831    else 
01832       ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01833    ast_cli(a->fd, "\n");
01834                    
01835    return CLI_SUCCESS;
01836 }

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

Definition at line 1839 of file chan_agent.c.

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

01840 {
01841    struct agent_pvt *p;
01842    char username[AST_MAX_BUF];
01843    char location[AST_MAX_BUF] = "";
01844    char talkingto[AST_MAX_BUF] = "";
01845    char music[AST_MAX_BUF];
01846    int count_agents = 0;           /* Number of agents configured */
01847    int online_agents = 0;          /* Number of online agents */
01848    int agent_status = 0;           /* 0 means offline, 1 means online */
01849 
01850    switch (cmd) {
01851    case CLI_INIT:
01852       e->command = "agent show online";
01853       e->usage =
01854          "Usage: agent show online\n"
01855          "       Provides a list of all online agents.\n";
01856       return NULL;
01857    case CLI_GENERATE:
01858       return NULL;
01859    }
01860 
01861    if (a->argc != 3)
01862       return CLI_SHOWUSAGE;
01863 
01864    AST_LIST_LOCK(&agents);
01865    AST_LIST_TRAVERSE(&agents, p, list) {
01866       struct ast_channel *owner;
01867 
01868       agent_status = 0;       /* reset it to offline */
01869       ast_mutex_lock(&p->lock);
01870       owner = agent_lock_owner(p);
01871 
01872       if (!ast_strlen_zero(p->name))
01873          snprintf(username, sizeof(username), "(%s) ", p->name);
01874       else
01875          username[0] = '\0';
01876       if (p->chan) {
01877          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01878          if (owner && ast_bridged_channel(owner)) {
01879             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(owner)->name);
01880          } else {
01881             strcpy(talkingto, " is idle");
01882          }
01883          agent_status = 1;
01884          online_agents++;
01885       }
01886 
01887       if (owner) {
01888          ast_channel_unlock(owner);
01889          owner = ast_channel_unref(owner);
01890       }
01891 
01892       if (!ast_strlen_zero(p->moh))
01893          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01894       if (agent_status)
01895          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01896       count_agents++;
01897       ast_mutex_unlock(&p->lock);
01898    }
01899    AST_LIST_UNLOCK(&agents);
01900    if (!count_agents) 
01901       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01902    else
01903       ast_cli(a->fd, "%d agents online\n", online_agents);
01904    ast_cli(a->fd, "\n");
01905    return CLI_SUCCESS;
01906 }

AST_DATA_STRUCTURE ( agent_pvt  ,
DATA_EXPORT_AGENT   
)

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

Definition at line 1308 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_masquerade(), ast_copy_string(), ast_debug, ast_hangup(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, 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().

01309 {
01310    struct ast_channel *chan=NULL, *parent=NULL;
01311    struct agent_pvt *p;
01312    int res;
01313 
01314    ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
01315    if (needlock)
01316       AST_LIST_LOCK(&agents);
01317    AST_LIST_TRAVERSE(&agents, p, list) {
01318       if (p == newlyavailable) {
01319          continue;
01320       }
01321       ast_mutex_lock(&p->lock);
01322       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01323          ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01324          /* We found a pending call, time to merge */
01325          chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL);
01326          parent = p->owner;
01327          p->abouttograb = 1;
01328          ast_mutex_unlock(&p->lock);
01329          break;
01330       }
01331       ast_mutex_unlock(&p->lock);
01332    }
01333    if (needlock)
01334       AST_LIST_UNLOCK(&agents);
01335    if (parent && chan)  {
01336       if (newlyavailable->ackcall) {
01337          /* Don't do beep here */
01338          res = 0;
01339       } else {
01340          ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01341          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01342          ast_debug(3, "Played beep, result '%d'\n", res);
01343          if (!res) {
01344             res = ast_waitstream(newlyavailable->chan, "");
01345             ast_debug(1, "Waited for stream, result '%d'\n", res);
01346          }
01347       }
01348       if (!res) {
01349          /* Note -- parent may have disappeared */
01350          if (p->abouttograb) {
01351             newlyavailable->acknowledged = 1;
01352             /* Safe -- agent lock already held */
01353             ast_setstate(parent, AST_STATE_UP);
01354             ast_setstate(chan, AST_STATE_UP);
01355             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01356             ast_channel_masquerade(parent, chan);
01357             ast_hangup(chan);
01358             p->abouttograb = 0;
01359          } else {
01360             ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
01361             agent_cleanup(newlyavailable);
01362          }
01363       } else {
01364          ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
01365          agent_cleanup(newlyavailable);
01366       }
01367    }
01368    return 0;
01369 }

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

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

01372 {
01373    struct agent_pvt *p;
01374    int res=0;
01375 
01376    ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01377    if (needlock)
01378       AST_LIST_LOCK(&agents);
01379    AST_LIST_TRAVERSE(&agents, p, list) {
01380       if (p == newlyavailable) {
01381          continue;
01382       }
01383       ast_mutex_lock(&p->lock);
01384       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01385          ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01386          ast_mutex_unlock(&p->lock);
01387          break;
01388       }
01389       ast_mutex_unlock(&p->lock);
01390    }
01391    if (needlock)
01392       AST_LIST_UNLOCK(&agents);
01393    if (p) {
01394       ast_mutex_unlock(&newlyavailable->lock);
01395       ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01396       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01397       ast_debug(1, "Played beep, result '%d'\n", res);
01398       if (!res) {
01399          res = ast_waitstream(newlyavailable->chan, "");
01400          ast_debug(1, "Waited for stream, result '%d'\n", res);
01401       }
01402       ast_mutex_lock(&newlyavailable->lock);
01403    }
01404    return res;
01405 }

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

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

Referenced by agent_logoff_cmd().

01736 {
01737    char *ret = NULL;
01738 
01739    if (pos == 2) {
01740       struct agent_pvt *p;
01741       char name[AST_MAX_AGENT];
01742       int which = 0, len = strlen(word);
01743 
01744       AST_LIST_LOCK(&agents);
01745       AST_LIST_TRAVERSE(&agents, p, list) {
01746          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01747          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01748             ret = ast_strdup(name);
01749             break;
01750          }
01751       }
01752       AST_LIST_UNLOCK(&agents);
01753    } else if (pos == 3 && state == 0) 
01754       return ast_strdup("soft");
01755    
01756    return ret;
01757 }

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

Note:
This function expects the agent list to be locked

Definition at line 2364 of file chan_agent.c.

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

Referenced by function_agent().

02365 {
02366    struct agent_pvt *cur;
02367 
02368    AST_LIST_TRAVERSE(&agents, cur, list) {
02369       if (!strcmp(cur->agent, agentid))
02370          break;   
02371    }
02372 
02373    return cur; 
02374 }

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

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

02377 {
02378    char *parse;    
02379    AST_DECLARE_APP_ARGS(args,
02380       AST_APP_ARG(agentid);
02381       AST_APP_ARG(item);
02382    );
02383    char *tmp;
02384    struct agent_pvt *agent;
02385 
02386    buf[0] = '\0';
02387 
02388    if (ast_strlen_zero(data)) {
02389       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02390       return -1;
02391    }
02392 
02393    parse = ast_strdupa(data);
02394 
02395    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02396    if (!args.item)
02397       args.item = "status";
02398 
02399    AST_LIST_LOCK(&agents);
02400 
02401    if (!(agent = find_agent(args.agentid))) {
02402       AST_LIST_UNLOCK(&agents);
02403       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02404       return -1;
02405    }
02406 
02407    if (!strcasecmp(args.item, "status")) {
02408       char *status = "LOGGEDOUT";
02409       if (agent->chan) {
02410          status = "LOGGEDIN";
02411       }
02412       ast_copy_string(buf, status, len);
02413    } else if (!strcasecmp(args.item, "password")) 
02414       ast_copy_string(buf, agent->password, len);
02415    else if (!strcasecmp(args.item, "name"))
02416       ast_copy_string(buf, agent->name, len);
02417    else if (!strcasecmp(args.item, "mohclass"))
02418       ast_copy_string(buf, agent->moh, len);
02419    else if (!strcasecmp(args.item, "channel")) {
02420       if (agent->chan) {
02421          ast_channel_lock(agent->chan);
02422          ast_copy_string(buf, agent->chan->name, len);
02423          ast_channel_unlock(agent->chan);
02424          tmp = strrchr(buf, '-');
02425          if (tmp)
02426             *tmp = '\0';
02427       } 
02428    } else if (!strcasecmp(args.item, "fullchannel")) {
02429       if (agent->chan) {
02430          ast_channel_lock(agent->chan);
02431          ast_copy_string(buf, agent->chan->name, len);
02432          ast_channel_unlock(agent->chan);
02433       } 
02434    } else if (!strcasecmp(args.item, "exten")) {
02435       buf[0] = '\0';
02436    }
02437 
02438    AST_LIST_UNLOCK(&agents);
02439 
02440    return 0;
02441 }

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

02544 {
02545    /* Make sure we can register our agent channel type */
02546    if (ast_channel_register(&agent_tech)) {
02547       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02548       return AST_MODULE_LOAD_FAILURE;
02549    }
02550    /* Read in the config */
02551    if (!read_agent_config(0))
02552       return AST_MODULE_LOAD_DECLINE;
02553    /* Dialplan applications */
02554    ast_register_application_xml(app, login_exec);
02555    ast_register_application_xml(app3, agentmonitoroutgoing_exec);
02556 
02557    /* data tree */
02558    ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
02559 
02560    /* Manager commands */
02561    ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
02562    ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
02563 
02564    /* CLI Commands */
02565    ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
02566 
02567    /* Dialplan Functions */
02568    ast_custom_function_register(&agent_function);
02569 
02570    return AST_MODULE_LOAD_SUCCESS;
02571 }

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

References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock_flag, args, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_signal, ast_cond_wait, AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy, ast_mutex_lock, ast_mutex_unlock, ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), 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, ast_module_user::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::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, 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().

01930 {
01931    int res=0;
01932    int tries = 0;
01933    int max_login_tries = maxlogintries;
01934    struct agent_pvt *p;
01935    struct ast_module_user *u;
01936    char user[AST_MAX_AGENT] = "";
01937    char pass[AST_MAX_AGENT];
01938    char agent[AST_MAX_AGENT] = "";
01939    char xpass[AST_MAX_AGENT] = "";
01940    char *errmsg;
01941    char *parse;
01942    AST_DECLARE_APP_ARGS(args,
01943               AST_APP_ARG(agent_id);
01944               AST_APP_ARG(options);
01945               AST_APP_ARG(extension);
01946       );
01947    const char *tmpoptions = NULL;
01948    int play_announcement = 1;
01949    char agent_goodbye[AST_MAX_FILENAME_LEN];
01950    int update_cdr = updatecdr;
01951    char *filename = "agent-loginok";
01952 
01953    u = ast_module_user_add(chan);
01954 
01955    parse = ast_strdupa(data);
01956 
01957    AST_STANDARD_APP_ARGS(args, parse);
01958 
01959    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
01960 
01961    ast_channel_lock(chan);
01962    /* Set Channel Specific Login Overrides */
01963    if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
01964       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
01965       if (max_login_tries < 0)
01966          max_login_tries = 0;
01967       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
01968       ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
01969    }
01970    if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
01971       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
01972          update_cdr = 1;
01973       else
01974          update_cdr = 0;
01975       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
01976       ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
01977    }
01978    if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
01979       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
01980       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
01981       ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
01982    }
01983    ast_channel_unlock(chan);
01984    /* End Channel Specific Login Overrides */
01985    
01986    if (!ast_strlen_zero(args.options)) {
01987       if (strchr(args.options, 's')) {
01988          play_announcement = 0;
01989       }
01990    }
01991 
01992    if (chan->_state != AST_STATE_UP)
01993       res = ast_answer(chan);
01994    if (!res) {
01995       if (!ast_strlen_zero(args.agent_id))
01996          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
01997       else
01998          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
01999    }
02000    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
02001       tries++;
02002       /* Check for password */
02003       AST_LIST_LOCK(&agents);
02004       AST_LIST_TRAVERSE(&agents, p, list) {
02005          if (!strcmp(p->agent, user) && !p->pending)
02006             ast_copy_string(xpass, p->password, sizeof(xpass));
02007       }
02008       AST_LIST_UNLOCK(&agents);
02009       if (!res) {
02010          if (!ast_strlen_zero(xpass))
02011             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
02012          else
02013             pass[0] = '\0';
02014       }
02015       errmsg = "agent-incorrect";
02016 
02017 #if 0
02018       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
02019 #endif      
02020 
02021       /* Check again for accuracy */
02022       AST_LIST_LOCK(&agents);
02023       AST_LIST_TRAVERSE(&agents, p, list) {
02024          int unlock_channel = 1;
02025          ast_channel_lock(chan);
02026          ast_mutex_lock(&p->lock);
02027          if (!strcmp(p->agent, user) &&
02028              !strcmp(p->password, pass) && !p->pending) {
02029 
02030             /* Ensure we can't be gotten until we're done */
02031             p->lastdisc = ast_tvnow();
02032             p->lastdisc.tv_sec++;
02033 
02034             /* Set Channel Specific Agent Overrides */
02035             if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02036                if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02037                   p->ackcall = 1;
02038                } else {
02039                   p->ackcall = 0;
02040                }
02041                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
02042                ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
02043                ast_set_flag(p, AGENT_FLAG_ACKCALL);
02044             } else {
02045                p->ackcall = ackcall;
02046             }
02047             if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
02048                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
02049                if (p->autologoff < 0)
02050                   p->autologoff = 0;
02051                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
02052                ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
02053                ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
02054             } else {
02055                p->autologoff = autologoff;
02056             }
02057             if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
02058                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
02059                if (p->wrapuptime < 0)
02060                   p->wrapuptime = 0;
02061                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
02062                ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
02063                ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
02064             } else {
02065                p->wrapuptime = wrapuptime;
02066             }
02067             tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
02068             if (!ast_strlen_zero(tmpoptions)) {
02069                p->acceptdtmf = *tmpoptions;
02070                ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
02071                ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
02072             }
02073             tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
02074             if (!ast_strlen_zero(tmpoptions)) {
02075                p->enddtmf = *tmpoptions;
02076                ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
02077                ast_set_flag(p, AGENT_FLAG_ENDDTMF);
02078             }
02079             ast_channel_unlock(chan);
02080             unlock_channel = 0;
02081             /* End Channel Specific Agent Overrides */
02082             if (!p->chan) {
02083                long logintime;
02084                snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
02085 
02086                p->logincallerid[0] = '\0';
02087                p->acknowledged = 0;
02088                
02089                ast_mutex_unlock(&p->lock);
02090                AST_LIST_UNLOCK(&agents);
02091                if( !res && play_announcement==1 )
02092                   res = ast_streamfile(chan, filename, chan->language);
02093                if (!res)
02094                   ast_waitstream(chan, "");
02095                AST_LIST_LOCK(&agents);
02096                ast_mutex_lock(&p->lock);
02097                if (!res) {
02098                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02099                   if (res)
02100                      ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats)));
02101                }
02102                if (!res) {
02103                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02104                   if (res)
02105                      ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(chan->nativeformats)));
02106                }
02107                /* Check once more just in case */
02108                if (p->chan)
02109                   res = -1;
02110                if (!res) {
02111                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
02112                      S_OR(p->moh, NULL), 
02113                      !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02114                   if (p->loginstart == 0)
02115                      time(&p->loginstart);
02116                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02117                            "Agent: %s\r\n"
02118                            "Channel: %s\r\n"
02119                            "Uniqueid: %s\r\n",
02120                            p->agent, chan->name, chan->uniqueid);
02121                   if (update_cdr && chan->cdr)
02122                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02123                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02124                   ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
02125                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02126                   /* Login this channel and wait for it to go away */
02127                   p->chan = chan;
02128                   if (p->ackcall) {
02129                      check_beep(p, 0);
02130                   } else {
02131                      check_availability(p, 0);
02132                   }
02133                   ast_mutex_unlock(&p->lock);
02134                   AST_LIST_UNLOCK(&agents);
02135                   ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
02136                   while (res >= 0) {
02137                      ast_mutex_lock(&p->lock);
02138                      if (p->deferlogoff && p->chan) {
02139                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
02140                         p->deferlogoff = 0;
02141                      }
02142                      if (p->chan != chan)
02143                         res = -1;
02144                      ast_mutex_unlock(&p->lock);
02145                      /* Yield here so other interested threads can kick in. */
02146                      sched_yield();
02147                      if (res)
02148                         break;
02149 
02150                      AST_LIST_LOCK(&agents);
02151                      ast_mutex_lock(&p->lock);
02152                      if (p->lastdisc.tv_sec) {
02153                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02154                            ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
02155                            p->lastdisc = ast_tv(0, 0);
02156                            ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
02157                            if (p->ackcall) {
02158                               check_beep(p, 0);
02159                            } else {
02160                               check_availability(p, 0);
02161                            }
02162                         }
02163                      }
02164                      ast_mutex_unlock(&p->lock);
02165                      AST_LIST_UNLOCK(&agents);
02166 
02167                      /* Synchronize channel ownership between call to agent and itself. */
02168                      ast_mutex_lock(&p->lock);
02169                      if (p->app_lock_flag == 1) {
02170                         ast_cond_signal(&p->login_wait_cond);
02171                         ast_cond_wait(&p->app_complete_cond, &p->lock);
02172                      }
02173                      ast_mutex_unlock(&p->lock);
02174                      if (p->ackcall) {
02175                         res = agent_ack_sleep(p);
02176                      } else {
02177                         res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02178                      }
02179                      if (p->ackcall && (res == 1)) {
02180                         AST_LIST_LOCK(&agents);
02181                         ast_mutex_lock(&p->lock);
02182                         check_availability(p, 0);
02183                         ast_mutex_unlock(&p->lock);
02184                         AST_LIST_UNLOCK(&agents);
02185                         res = 0;
02186                      }
02187                      sched_yield();
02188                   }
02189                   ast_mutex_lock(&p->lock);
02190                   /* Log us off if appropriate */
02191                   if (p->chan == chan) {
02192                      p->chan = NULL;
02193                   }
02194 
02195                   /* Synchronize channel ownership between call to agent and itself. */
02196                   if (p->app_lock_flag == 1) {
02197                      ast_cond_signal(&p->login_wait_cond);
02198                      ast_cond_wait(&p->app_complete_cond, &p->lock);
02199                   }
02200 
02201                   if (res && p->owner)
02202                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
02203 
02204                   p->acknowledged = 0;
02205                   logintime = time(NULL) - p->loginstart;
02206                   p->loginstart = 0;
02207                   ast_mutex_unlock(&p->lock);
02208                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02209                            "Agent: %s\r\n"
02210                            "Logintime: %ld\r\n"
02211                            "Uniqueid: %s\r\n",
02212                            p->agent, logintime, chan->uniqueid);
02213                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02214                   ast_verb(2, "Agent '%s' logged out\n", p->agent);
02215                   /* If there is no owner, go ahead and kill it now */
02216                   ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
02217                   if (p->dead && !p->owner) {
02218                      ast_mutex_destroy(&p->lock);
02219                      ast_cond_destroy(&p->app_complete_cond);
02220                      ast_cond_destroy(&p->login_wait_cond);
02221                      ast_free(p);
02222                   }
02223                }
02224                else {
02225                   ast_mutex_unlock(&p->lock);
02226                   p = NULL;
02227                }
02228                res = -1;
02229             } else {
02230                ast_mutex_unlock(&p->lock);
02231                errmsg = "agent-alreadyon";
02232                p = NULL;
02233             }
02234             break;
02235          }
02236          ast_mutex_unlock(&p->lock);
02237          if (unlock_channel) {
02238             ast_channel_unlock(chan);
02239          }
02240       }
02241       if (!p)
02242          AST_LIST_UNLOCK(&agents);
02243 
02244       if (!res && (max_login_tries==0 || tries < max_login_tries))
02245          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02246    }
02247       
02248    if (!res)
02249       res = ast_safe_sleep(chan, 500);
02250 
02251    ast_module_user_remove(u);
02252    
02253    return -1;
02254 }

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

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

01535 {
01536    int x = ffs(d);
01537 
01538    if (x)
01539       return x - 1;
01540 
01541    return 0;
01542 }

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

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

Referenced by load_module(), and reload().

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

static int reload ( void   )  [static]

Definition at line 2573 of file chan_agent.c.

References read_agent_config().

02574 {
02575    return read_agent_config(1);
02576 }

static int unload_module ( void   )  [static]

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

02579 {
02580    struct agent_pvt *p;
02581    /* First, take us out of the channel loop */
02582    ast_channel_unregister(&agent_tech);
02583    /* Unregister dialplan functions */
02584    ast_custom_function_unregister(&agent_function);   
02585    /* Unregister CLI commands */
02586    ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
02587    /* Unregister dialplan applications */
02588    ast_unregister_application(app);
02589    ast_unregister_application(app3);
02590    /* Unregister manager command */
02591    ast_manager_unregister("Agents");
02592    ast_manager_unregister("AgentLogoff");
02593    /* Unregister the data tree */
02594    ast_data_unregister(NULL);
02595    /* Unregister channel */
02596    AST_LIST_LOCK(&agents);
02597    /* Hangup all interfaces if they have an owner */
02598    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02599       if (p->owner)
02600          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02601       ast_free(p);
02602    }
02603    AST_LIST_UNLOCK(&agents);
02604    return 0;
02605 }


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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DRIVER, .nonoptreq = "res_monitor,chan_local", } [static]

Definition at line 2613 of file chan_agent.c.

char acceptdtmf = DEFAULT_ACCEPTDTMF [static]

Definition at line 228 of file chan_agent.c.

Referenced by play_record_review().

int ackcall [static]

Definition at line 224 of file chan_agent.c.

struct ast_custom_function agent_function [static]

Initial value:

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

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

Definition at line 353 of file chan_agent.c.

Referenced by agent_new(), load_module(), and unload_module().

char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye" [static]

Definition at line 232 of file chan_agent.c.

struct ast_data_handler agents_data_provider [static]

Initial value:

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

Referenced by load_module().

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

Definition at line 206 of file chan_agent.c.

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

Definition at line 207 of file chan_agent.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2613 of file chan_agent.c.

int autologoff [static]

Definition at line 222 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 227 of file chan_agent.c.

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

Definition at line 240 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]

Initial value:

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

Referenced by load_module(), and unload_module().

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

Definition at line 204 of file chan_agent.c.

int endcall [static]

Definition at line 225 of file chan_agent.c.

char enddtmf = DEFAULT_ENDDTMF [static]

Definition at line 229 of file chan_agent.c.

ast_group_t group [static]

Definition at line 221 of file chan_agent.c.

Referenced by group_destroy().

int maxlogintries = 3 [static]

Definition at line 231 of file chan_agent.c.

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

Definition at line 209 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 226 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 215 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 234 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 235 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 236 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 238 of file chan_agent.c.

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

Definition at line 203 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 239 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 237 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 223 of file chan_agent.c.


Generated on Sat Mar 10 01:54:50 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7