Sat Feb 11 06:34:27 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"

Include dependency graph for chan_agent.c:

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, const char *dest, int timeout)
static int agent_cleanup (struct agent_pvt *p)
static int agent_cont_sleep (void *data)
static int agent_devicestate (const char *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, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *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 = AST_BUILDOPT_SUM, .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

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

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

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

static void __reg_module ( void   )  [static]

Definition at line 2625 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

Referenced by load_module().

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

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

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

Referenced by load_module().

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

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

Adds an agent to the global list of agents.

Parameters:
agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
pending If it is pending or not.
Returns:
The just created agent.
See also:
agent_pvt, agents.

Definition at line 421 of file chan_agent.c.

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

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 1038 of file chan_agent.c.

References agent_pvt::acceptdtmf, agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_waitfor(), agent_pvt::chan, f, ast_frame::frametype, ast_frame_subclass::integer, agent_pvt::lock, and ast_frame::subclass.

Referenced by login_exec().

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

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 548 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

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

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

Definition at line 1079 of file chan_agent.c.

References ast_channel::_bridge, ast_channel_name(), ast_debug, agent_pvt::chan, and ast_channel::tech_pvt.

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

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

Definition at line 819 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_start_monitoring(), ast_channel_language(), ast_channel_name(), ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_getformatname(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_set_read_format_from_cap(), ast_set_write_format_from_cap(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_verb, ast_waitstream(), agent_pvt::chan, CLEANUP, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, ast_channel::nativeformats, agent_pvt::pending, and ast_channel::tech_pvt.

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

static int agent_cleanup ( struct agent_pvt p  )  [static]

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

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

Definition at line 522 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::chan, agent_pvt::dead, agent_pvt::lock, agent_pvt::login_wait_cond, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

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

static int agent_cont_sleep ( void *  data  )  [static]

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

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

static int agent_devicestate ( const char *  data  )  [static]

Part of PBX channel interface.

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 899 of file chan_agent.c.

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

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

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 932 of file chan_agent.c.

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

Referenced by agent_request().

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

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

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

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

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

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

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

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

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

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

Definition at line 1635 of file chan_agent.c.

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

Referenced by action_agent_logoff(), and agent_logoff_cmd().

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

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

Definition at line 1676 of file chan_agent.c.

References agent_pvt::agent, agent_logoff(), ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_agent_logoff_cmd(), ast_cli_args::fd, ast_cli_args::line, ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

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

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

Create new agent channel.

Definition at line 1096 of file chan_agent.c.

References agent_pvt::agent, agent_tech, ast_channel_alloc, ast_channel_language(), ast_copy_string(), ast_format_cap_add(), ast_format_cap_copy(), ast_format_copy(), ast_format_set(), AST_FORMAT_SLINEAR, ast_log(), ast_random(), agent_pvt::chan, ast_channel::context, ast_channel::exten, 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().

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

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

Definition at line 587 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_name(), 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, ast_frame::frametype, ast_frame_subclass::integer, agent_pvt::lock, LOG_NOTICE, agent_pvt::name, agent_pvt::owner, agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.

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

static struct ast_channel * agent_request ( const char *  type,
struct ast_format_cap cap,
const struct ast_channel requestor,
const char *  data,
int *  cause 
) [static, read]

Part of the Asterisk PBX interface.

Definition at line 1409 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_channel_linkedid(), 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, agent_pvt::lock, LOG_DEBUG, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::owner, and agent_pvt::pending.

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

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

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

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

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

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

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_sendtext(p->chan, text);
00730    ast_mutex_unlock(&p->lock);
00731    return res;
00732 }

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

Definition at line 915 of file chan_agent.c.

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

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

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

Definition at line 582 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

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

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

Definition at line 734 of file chan_agent.c.

References ast_channel_name(), ast_debug, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_mutex_lock, ast_mutex_unlock, ast_write(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, ast_frame_subclass::format, ast_frame::frametype, agent_pvt::lock, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

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

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

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

Referenced by load_module().

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

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

Definition at line 2460 of file chan_agent.c.

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

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

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

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

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

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

Definition at line 1840 of file chan_agent.c.

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

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

AST_DATA_STRUCTURE ( agent_pvt  ,
DATA_EXPORT_AGENT   
)

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

Definition at line 1309 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_cleanup(), agent_new(), ast_channel_language(), ast_channel_linkedid(), ast_channel_masquerade(), ast_channel_name(), ast_copy_string(), ast_debug, ast_hangup(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_setstate(), AST_STATE_DOWN, AST_STATE_UP, ast_streamfile(), ast_waitstream(), agent_pvt::chan, ast_channel::context, agent_pvt::group, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.

Referenced by login_exec().

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

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

Definition at line 1372 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::agent, ast_channel_language(), ast_channel_name(), ast_debug, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock, ast_mutex_unlock, ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, agent_pvt::owner, and agent_pvt::pending.

Referenced by login_exec().

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

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

Definition at line 1736 of file chan_agent.c.

References agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, AST_MAX_AGENT, ast_strdup, len(), agent_pvt::loginstart, and agent_pvt::name.

Referenced by agent_logoff_cmd().

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

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

Note:
This function expects the agent list to be locked

Definition at line 2369 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

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

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

Definition at line 2381 of file chan_agent.c.

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

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

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 2548 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_format_cap_add_all(), ast_format_cap_alloc(), ast_log(), ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application_xml, ast_channel_tech::capabilities, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), and read_agent_config().

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

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 1930 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_channel_language(), ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), 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_from_cap(), ast_set_write_format_from_cap(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::login_wait_cond, agent_pvt::logincallerid, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::nativeformats, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, ast_channel::readformat, S_OR, update_cdr, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by load_module().

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

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

Definition at line 1535 of file chan_agent.c.

Referenced by agents_show().

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

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

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

static int reload ( void   )  [static]

Definition at line 2583 of file chan_agent.c.

References read_agent_config().

02584 {
02585    return read_agent_config(1);
02586 }

static int unload_module ( void   )  [static]

Definition at line 2588 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_format_cap_destroy(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), ast_channel_tech::capabilities, cli_agents, and agent_pvt::owner.

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


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

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

Initial value:

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

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

Initial value:

Definition at line 2532 of file chan_agent.c.

Initial value:

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

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

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

 {
   AST_CLI_DEFINE(agents_show, "Show status of agents"),
   AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
   AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
}

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

int maxlogintries = 3 [static]

Definition at line 231 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 226 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 215 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 234 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 235 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 236 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 238 of file chan_agent.c.

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

Definition at line 203 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 239 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 237 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 223 of file chan_agent.c.


Generated on Sat Feb 11 06:34:28 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6