Mon Oct 8 12:39:12 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 = "ac1f6a56484a8820659555499174e588" , .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 563 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().

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

static void __reg_module ( void   )  [static]

Definition at line 2619 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

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

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

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

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

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 557 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00558 {
00559    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00560    return -1;
00561 }

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

Definition at line 1084 of file chan_agent.c.

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

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

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

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

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

static int agent_cleanup ( struct agent_pvt p  )  [static]

Deletes an agent after doing some clean up. Further documentation: How safe is this function ? What state should the agent be to be cleaned.

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

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

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

static int agent_cont_sleep ( void *  data  )  [static]

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

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

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

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

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

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

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

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

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

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

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

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

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

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

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

00909 {
00910    struct agent_pvt *p = NULL;
00911    struct ast_channel *base = chan;
00912 
00913    /* chan is locked by the calling function */
00914    if (!chan || !chan->tech_pvt) {
00915       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);
00916       return NULL;
00917    }
00918    p = chan->tech_pvt;
00919    if (p->chan) 
00920       base = p->chan;
00921    return base;
00922 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 941 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_ref, 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().

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

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

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

00785 {
00786    struct agent_pvt *p = ast->tech_pvt;
00787    int res = -1;
00788    ast_mutex_lock(&p->lock);
00789    if (p->chan && !ast_check_hangup(p->chan)) {
00790       while (ast_channel_trylock(p->chan)) {
00791          int res;
00792          if ((res = ast_channel_unlock(ast))) {
00793             ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", res > 0 ? strerror(res) : "Bad ao2obj data");
00794             ast_mutex_unlock(&p->lock);
00795             return -1;
00796          }
00797          usleep(1);
00798          ast_channel_lock(ast);
00799       }
00800       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00801       ast_channel_unlock(p->chan);
00802    } else
00803       res = 0;
00804    ast_mutex_unlock(&p->lock);
00805    return res;
00806 }

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

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

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

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

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

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

Create new agent channel.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 924 of file chan_agent.c.

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

00925 {
00926    struct agent_pvt *p = NULL;
00927    
00928    if (!chan || !base) {
00929       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00930       return -1;
00931    }
00932    p = chan->tech_pvt;
00933    if (!p) {
00934       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00935       return -1;
00936    }
00937    p->chan = base;
00938    return 0;
00939 }

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

Definition at line 591 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00592 {
00593    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00594 }

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

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

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

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

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

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

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

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

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

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

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

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

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

AST_DATA_STRUCTURE ( agent_pvt  ,
DATA_EXPORT_AGENT   
)

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

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

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

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

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

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

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

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

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

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

Note:
This function expects the agent list to be locked

Definition at line 2370 of file chan_agent.c.

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

Referenced by function_agent().

02371 {
02372    struct agent_pvt *cur;
02373 
02374    AST_LIST_TRAVERSE(&agents, cur, list) {
02375       if (!strcmp(cur->agent, agentid))
02376          break;   
02377    }
02378 
02379    return cur; 
02380 }

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

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

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

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

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

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

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

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

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

01541 {
01542    int x = ffs(d);
01543 
01544    if (x)
01545       return x - 1;
01546 
01547    return 0;
01548 }

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

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

Referenced by load_module(), and reload().

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

static int reload ( void   )  [static]

Definition at line 2579 of file chan_agent.c.

References read_agent_config().

02580 {
02581    return read_agent_config(1);
02582 }

static int unload_module ( void   )  [static]

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

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


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

Definition at line 2619 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 2449 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 1914 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 2533 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 2538 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 2619 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 1919 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 Mon Oct 8 12:39:12 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7