Wed Oct 28 13:31:56 2009

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 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 DEFAULT_ACCEPTDTMF   '#'
#define DEFAULT_ENDDTMF   '*'
#define GETAGENTBYCALLERID   "AGENTBYCALLERID"
#define PA_MAX_LEN   2048

Enumerations

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

Functions

static int __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static void __reg_module (void)
static void __unreg_module (void)
static int action_agent_logoff (struct mansession *s, const struct message *m)
static int action_agents (struct mansession *s, const struct message *m)
static struct agent_pvtadd_agent (const char *agent, int pending)
static int agent_ack_sleep (void *data)
static int agent_answer (struct ast_channel *ast)
static struct ast_channelagent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge)
static int agent_call (struct ast_channel *ast, char *dest, int timeout)
static int agent_cleanup (struct agent_pvt *p)
static int agent_cont_sleep (void *data)
static int agent_devicestate (void *data)
 Part of PBX channel interface.
static int agent_digit_begin (struct ast_channel *ast, char digit)
static int agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
static int agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static struct ast_channelagent_get_base_channel (struct ast_channel *chan)
 return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
static int agent_hangup (struct ast_channel *ast)
static int agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
static int agent_logoff (const char *agent, int soft)
static char * agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static struct ast_channelagent_new (struct agent_pvt *p, int state, const char *linkedid)
 Create new agent channel.
static struct ast_frameagent_read (struct ast_channel *ast)
static struct ast_channelagent_request (const char *type, int format, const struct ast_channel *requestor, void *data, int *cause)
 Part of the Asterisk PBX interface.
static int agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int agent_sendtext (struct ast_channel *ast, const char *text)
static int agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, const char *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static 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)
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_DEFAULT , .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, }
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 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 205 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 207 of file chan_agent.c.

Referenced by login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 212 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 213 of file chan_agent.c.

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 236 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 210 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 238 of file chan_agent.c.

00238      {
00239    AGENT_FLAG_ACKCALL = (1 << 0),
00240    AGENT_FLAG_AUTOLOGOFF = (1 << 1),
00241    AGENT_FLAG_WRAPUPTIME = (1 << 2),
00242    AGENT_FLAG_ACCEPTDTMF = (1 << 3),
00243    AGENT_FLAG_ENDDTMF = (1 << 4),
00244 };


Function Documentation

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

Definition at line 495 of file chan_agent.c.

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

00496 {
00497    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00498    char filename[AST_MAX_BUF];
00499    int res = -1;
00500    if (!p)
00501       return -1;
00502    if (!ast->monitor) {
00503       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00504       /* substitute . for - */
00505       if ((pointer = strchr(filename, '.')))
00506          *pointer = '-';
00507       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00508       ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
00509       ast_monitor_setjoinfiles(ast, 1);
00510       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00511 #if 0
00512       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00513 #endif
00514       if (!ast->cdr)
00515          ast->cdr = ast_cdr_alloc();
00516       ast_cdr_setuserfield(ast, tmp2);
00517       res = 0;
00518    } else
00519       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00520    return res;
00521 }

static void __reg_module ( void   )  [static]

Definition at line 2362 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

01592 {
01593    const char *agent = astman_get_header(m, "Agent");
01594    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01595    int soft;
01596    int ret; /* return value of agent_logoff */
01597 
01598    if (ast_strlen_zero(agent)) {
01599       astman_send_error(s, m, "No agent specified");
01600       return 0;
01601    }
01602 
01603    soft = ast_true(soft_s) ? 1 : 0;
01604    ret = agent_logoff(agent, soft);
01605    if (ret == 0)
01606       astman_send_ack(s, m, "Agent logged out");
01607    else
01608       astman_send_error(s, m, "No such agent");
01609 
01610    return 0;
01611 }

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

Lists agents and their status to the Manager API. It is registered on load_module() and it gets called by the manager backend.

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

Definition at line 1442 of file chan_agent.c.

References ast_channel::_bridge, agent_pvt::agent, ast_bridged_channel(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strdupa, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::lock, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, S_OR, and status.

Referenced by load_module().

01443 {
01444    const char *id = astman_get_header(m,"ActionID");
01445    char idText[256] = "";
01446    struct agent_pvt *p;
01447    char *username = NULL;
01448    char *loginChan = NULL;
01449    char *talkingto = NULL;
01450    char *talkingtoChan = NULL;
01451    char *status = NULL;
01452 
01453    if (!ast_strlen_zero(id))
01454       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01455    astman_send_ack(s, m, "Agents will follow");
01456    AST_LIST_LOCK(&agents);
01457    AST_LIST_TRAVERSE(&agents, p, list) {
01458          ast_mutex_lock(&p->lock);
01459 
01460       /* Status Values:
01461          AGENT_LOGGEDOFF - Agent isn't logged in
01462          AGENT_IDLE      - Agent is logged in, and waiting for call
01463          AGENT_ONCALL    - Agent is logged in, and on a call
01464          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01465 
01466       username = S_OR(p->name, "None");
01467 
01468       /* Set a default status. It 'should' get changed. */
01469       status = "AGENT_UNKNOWN";
01470 
01471       if (p->chan) {
01472          loginChan = ast_strdupa(p->chan->name);
01473          if (p->owner && p->owner->_bridge) {
01474             talkingto = p->chan->cid.cid_num;
01475             if (ast_bridged_channel(p->owner))
01476                talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name);
01477             else
01478                talkingtoChan = "n/a";
01479                status = "AGENT_ONCALL";
01480          } else {
01481             talkingto = "n/a";
01482             talkingtoChan = "n/a";
01483                status = "AGENT_IDLE";
01484          }
01485       } else {
01486          loginChan = "n/a";
01487          talkingto = "n/a";
01488          talkingtoChan = "n/a";
01489          status = "AGENT_LOGGEDOFF";
01490       }
01491 
01492       astman_append(s, "Event: Agents\r\n"
01493          "Agent: %s\r\n"
01494          "Name: %s\r\n"
01495          "Status: %s\r\n"
01496          "LoggedInChan: %s\r\n"
01497          "LoggedInTime: %d\r\n"
01498          "TalkingTo: %s\r\n"
01499          "TalkingToChan: %s\r\n"
01500          "%s"
01501          "\r\n",
01502          p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
01503       ast_mutex_unlock(&p->lock);
01504    }
01505    AST_LIST_UNLOCK(&agents);
01506    astman_append(s, "Event: AgentsComplete\r\n"
01507       "%s"
01508       "\r\n",idText);
01509    return 0;
01510 }

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 365 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, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, 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::moh, agent_pvt::name, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 931 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, agent_pvt::lock, and ast_frame::subclass.

Referenced by login_exec().

00932 {
00933    struct agent_pvt *p;
00934    int res=0;
00935    int to = 1000;
00936    struct ast_frame *f;
00937 
00938    /* Wait a second and look for something */
00939 
00940    p = (struct agent_pvt *) data;
00941    if (!p->chan) 
00942       return -1;
00943 
00944    for(;;) {
00945       to = ast_waitfor(p->chan, to);
00946       if (to < 0) 
00947          return -1;
00948       if (!to) 
00949          return 0;
00950       f = ast_read(p->chan);
00951       if (!f) 
00952          return -1;
00953       if (f->frametype == AST_FRAME_DTMF)
00954          res = f->subclass;
00955       else
00956          res = 0;
00957       ast_frfree(f);
00958       ast_mutex_lock(&p->lock);
00959       if (!p->app_sleep_cond) {
00960          ast_mutex_unlock(&p->lock);
00961          return 0;
00962       } else if (res == p->acceptdtmf) {
00963          ast_mutex_unlock(&p->lock);
00964          return 1;
00965       }
00966       ast_mutex_unlock(&p->lock);
00967       res = 0;
00968    }
00969    return res;
00970 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 489 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00490 {
00491    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00492    return -1;
00493 }

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

Definition at line 972 of file chan_agent.c.

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

00973 {
00974    struct agent_pvt *p = bridge->tech_pvt;
00975    struct ast_channel *ret = NULL;
00976 
00977    if (p) {
00978       if (chan == p->chan)
00979          ret = bridge->_bridge;
00980       else if (chan == bridge->_bridge)
00981          ret = p->chan;
00982    }
00983 
00984    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
00985    return ret;
00986 }

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

Definition at line 732 of file chan_agent.c.

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

00733 {
00734    struct agent_pvt *p = ast->tech_pvt;
00735    int res = -1;
00736    int newstate=0;
00737    ast_mutex_lock(&p->lock);
00738    p->acknowledged = 0;
00739    if (!p->chan) {
00740       if (p->pending) {
00741          ast_debug(1, "Pretending to dial on pending agent\n");
00742          newstate = AST_STATE_DIALING;
00743          res = 0;
00744       } else {
00745          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00746          res = -1;
00747       }
00748       ast_mutex_unlock(&p->lock);
00749       if (newstate)
00750          ast_setstate(ast, newstate);
00751       return res;
00752    }
00753    ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00754    ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
00755    res = ast_streamfile(p->chan, beep, p->chan->language);
00756    ast_debug(3, "Played beep, result '%d'\n", res);
00757    if (!res) {
00758       res = ast_waitstream(p->chan, "");
00759       ast_debug(3, "Waited for stream, result '%d'\n", res);
00760    }
00761    if (!res) {
00762       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00763       ast_debug(3, "Set read format, result '%d'\n", res);
00764       if (res)
00765          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00766    } else {
00767       /* Agent hung-up */
00768       p->chan = NULL;
00769       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00770    }
00771 
00772    if (!res) {
00773       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00774       ast_debug(3, "Set write format, result '%d'\n", res);
00775       if (res)
00776          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00777    }
00778    if(!res) {
00779       /* Call is immediately up, or might need ack */
00780       if (p->ackcall) {
00781          newstate = AST_STATE_RINGING;
00782       } else {
00783          newstate = AST_STATE_UP;
00784          if (recordagentcalls)
00785             agent_start_monitoring(ast, 0);
00786          p->acknowledged = 1;
00787       }
00788       res = 0;
00789    }
00790    CLEANUP(ast, p);
00791    ast_mutex_unlock(&p->lock);
00792    if (newstate)
00793       ast_setstate(ast, newstate);
00794    return res;
00795 }

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

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

Referenced by check_availability().

00467 {
00468    struct ast_channel *chan = p->owner;
00469    p->owner = NULL;
00470    chan->tech_pvt = NULL;
00471    p->app_sleep_cond = 1;
00472    /* Release ownership of the agent to other threads (presumably running the login app). */
00473    p->app_lock_flag = 0;
00474    ast_cond_signal(&p->app_complete_cond);
00475    if (chan) {
00476       chan = ast_channel_release(chan);
00477    }
00478    if (p->dead) {
00479       ast_mutex_destroy(&p->lock);
00480       ast_mutex_destroy(&p->app_lock);
00481       ast_cond_destroy(&p->app_complete_cond);
00482       ast_free(p);
00483         }
00484    return 0;
00485 }

static int agent_cont_sleep ( void *  data  )  [static]

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

00911 {
00912    struct agent_pvt *p;
00913    int res;
00914 
00915    p = (struct agent_pvt *)data;
00916 
00917    ast_mutex_lock(&p->lock);
00918    res = p->app_sleep_cond;
00919    if (p->lastdisc.tv_sec) {
00920       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00921          res = 1;
00922    }
00923    ast_mutex_unlock(&p->lock);
00924 
00925    if (!res)
00926       ast_debug(5, "agent_cont_sleep() returning %d\n", res );
00927 
00928    return res;
00929 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2168 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, agent_pvt::pending, and s.

02169 {
02170    struct agent_pvt *p;
02171    char *s;
02172    ast_group_t groupmatch;
02173    int groupoff;
02174    int res = AST_DEVICE_INVALID;
02175    
02176    s = data;
02177    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02178       groupmatch = (1 << groupoff);
02179    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02180       groupmatch = (1 << groupoff);
02181    } else 
02182       groupmatch = 0;
02183 
02184    /* Check actual logged in agents first */
02185    AST_LIST_LOCK(&agents);
02186    AST_LIST_TRAVERSE(&agents, p, list) {
02187       ast_mutex_lock(&p->lock);
02188       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02189          if (p->owner) {
02190             if (res != AST_DEVICE_INUSE)
02191                res = AST_DEVICE_BUSY;
02192          } else {
02193             if (res == AST_DEVICE_BUSY)
02194                res = AST_DEVICE_INUSE;
02195             if (p->chan) {
02196                if (res == AST_DEVICE_INVALID)
02197                   res = AST_DEVICE_UNKNOWN;
02198             } else if (res == AST_DEVICE_INVALID)  
02199                res = AST_DEVICE_UNAVAILABLE;
02200          }
02201          if (!strcmp(data, p->agent)) {
02202             ast_mutex_unlock(&p->lock);
02203             break;
02204          }
02205       }
02206       ast_mutex_unlock(&p->lock);
02207    }
02208    AST_LIST_UNLOCK(&agents);
02209    return res;
02210 }

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

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

00711 {
00712    struct agent_pvt *p = ast->tech_pvt;
00713    ast_mutex_lock(&p->lock);
00714    if (p->chan) {
00715       ast_senddigit_begin(p->chan, digit);
00716    }
00717    ast_mutex_unlock(&p->lock);
00718    return 0;
00719 }

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

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

00722 {
00723    struct agent_pvt *p = ast->tech_pvt;
00724    ast_mutex_lock(&p->lock);
00725    if (p->chan) {
00726       ast_senddigit_end(p->chan, digit, duration);
00727    }
00728    ast_mutex_unlock(&p->lock);
00729    return 0;
00730 }

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

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

00678 {
00679    struct agent_pvt *p = newchan->tech_pvt;
00680    ast_mutex_lock(&p->lock);
00681    if (p->owner != oldchan) {
00682       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00683       ast_mutex_unlock(&p->lock);
00684       return -1;
00685    }
00686    p->owner = newchan;
00687    ast_mutex_unlock(&p->lock);
00688    return 0;
00689 }

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

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

00799 {
00800    struct agent_pvt *p = NULL;
00801    struct ast_channel *base = chan;
00802 
00803    /* chan is locked by the calling function */
00804    if (!chan || !chan->tech_pvt) {
00805       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);
00806       return NULL;
00807    }
00808    p = chan->tech_pvt;
00809    if (p->chan) 
00810       base = p->chan;
00811    return base;
00812 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 831 of file chan_agent.c.

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

00832 {
00833    struct agent_pvt *p = ast->tech_pvt;
00834    int howlong = 0;
00835 
00836    ast_mutex_lock(&p->lock);
00837    p->owner = NULL;
00838    ast->tech_pvt = NULL;
00839    p->app_sleep_cond = 1;
00840    p->acknowledged = 0;
00841 
00842    /* if they really are hung up then set start to 0 so the test
00843     * later if we're called on an already downed channel
00844     * doesn't cause an agent to be logged out like when
00845     * agent_request() is followed immediately by agent_hangup()
00846     * as in apps/app_chanisavail.c:chanavail_exec()
00847     */
00848 
00849    ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
00850    if (p->start && (ast->_state != AST_STATE_UP)) {
00851       howlong = time(NULL) - p->start;
00852       p->start = 0;
00853    } else if (ast->_state == AST_STATE_RESERVED) 
00854       howlong = 0;
00855    else
00856       p->start = 0; 
00857    if (p->chan) {
00858       p->chan->_bridge = NULL;
00859       /* If they're dead, go ahead and hang up on the agent now */
00860       if (p->dead) {
00861          ast_channel_lock(p->chan);
00862          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00863          ast_channel_unlock(p->chan);
00864       } else if (p->loginstart) {
00865          ast_channel_lock(p->chan);
00866          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00867             S_OR(p->moh, NULL),
00868             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00869          ast_channel_unlock(p->chan);
00870       }
00871    }
00872    ast_mutex_unlock(&p->lock);
00873 
00874    /* Only register a device state change if the agent is still logged in */
00875    if (!p->loginstart) {
00876       p->logincallerid[0] = '\0';
00877    } else {
00878       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
00879    }
00880 
00881    if (p->pending) {
00882       AST_LIST_LOCK(&agents);
00883       AST_LIST_REMOVE(&agents, p, list);
00884       AST_LIST_UNLOCK(&agents);
00885    }
00886    if (p->abouttograb) {
00887       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00888          kill it later */
00889       p->abouttograb = 0;
00890    } else if (p->dead) {
00891       ast_mutex_destroy(&p->lock);
00892       ast_mutex_destroy(&p->app_lock);
00893       ast_cond_destroy(&p->app_complete_cond);
00894       ast_free(p);
00895    } else {
00896       if (p->chan) {
00897          /* Not dead -- check availability now */
00898          ast_mutex_lock(&p->lock);
00899          /* Store last disconnect time */
00900          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00901          ast_mutex_unlock(&p->lock);
00902       }
00903       /* Release ownership of the agent to other threads (presumably running the login app). */
00904       p->app_lock_flag = 0;
00905       ast_cond_signal(&p->app_complete_cond);
00906    }
00907    return 0;
00908 }

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

Definition at line 691 of file chan_agent.c.

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

00692 {
00693    struct agent_pvt *p = ast->tech_pvt;
00694    int res = -1;
00695    ast_mutex_lock(&p->lock);
00696    if (p->chan && !ast_check_hangup(p->chan)) {
00697       while (ast_channel_trylock(p->chan)) {
00698          ast_channel_unlock(ast);
00699          usleep(1);
00700          ast_channel_lock(ast);
00701       }
00702       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00703       ast_channel_unlock(p->chan);
00704    } else
00705       res = 0;
00706    ast_mutex_unlock(&p->lock);
00707    return res;
00708 }

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

Definition at line 1512 of file chan_agent.c.

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

Referenced by action_agent_logoff(), agent_logoff_cmd(), and agent_read().

01513 {
01514    struct agent_pvt *p;
01515    int ret = -1; /* Return -1 if no agent if found */
01516 
01517    AST_LIST_LOCK(&agents);
01518    AST_LIST_TRAVERSE(&agents, p, list) {
01519       if (!strcasecmp(p->agent, agent)) {
01520          ret = 0;
01521          if (p->owner || p->chan) {
01522             if (!soft) {
01523                ast_mutex_lock(&p->lock);
01524 
01525                while (p->owner && ast_channel_trylock(p->owner)) {
01526                   DEADLOCK_AVOIDANCE(&p->lock);
01527                }
01528                if (p->owner) {
01529                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01530                   ast_channel_unlock(p->owner);
01531                }
01532 
01533                while (p->chan && ast_channel_trylock(p->chan)) {
01534                   DEADLOCK_AVOIDANCE(&p->lock);
01535                }
01536                if (p->chan) {
01537                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01538                   ast_channel_unlock(p->chan);
01539                }
01540 
01541                ast_mutex_unlock(&p->lock);
01542             } else
01543                p->deferlogoff = 1;
01544          }
01545          break;
01546       }
01547    }
01548    AST_LIST_UNLOCK(&agents);
01549 
01550    return ret;
01551 }

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

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

01554 {
01555    int ret;
01556    const char *agent;
01557 
01558    switch (cmd) {
01559    case CLI_INIT:
01560       e->command = "agent logoff";
01561       e->usage =
01562          "Usage: agent logoff <channel> [soft]\n"
01563          "       Sets an agent as no longer logged in.\n"
01564          "       If 'soft' is specified, do not hangup existing calls.\n";
01565       return NULL;
01566    case CLI_GENERATE:
01567       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01568    }
01569 
01570    if (a->argc < 3 || a->argc > 4)
01571       return CLI_SHOWUSAGE;
01572    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01573       return CLI_SHOWUSAGE;
01574 
01575    agent = a->argv[2] + 6;
01576    ret = agent_logoff(agent, a->argc == 4);
01577    if (ret == 0)
01578       ast_cli(a->fd, "Logging out %s\n", agent);
01579 
01580    return CLI_SUCCESS;
01581 }

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

Create new agent channel.

Definition at line 989 of file chan_agent.c.

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

Referenced by agent_request(), and check_availability().

00990 {
00991    struct ast_channel *tmp;
00992    int alreadylocked;
00993 #if 0
00994    if (!p->chan) {
00995       ast_log(LOG_WARNING, "No channel? :(\n");
00996       return NULL;
00997    }
00998 #endif   
00999    if (p->pending)
01000       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);
01001    else
01002       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", linkedid, 0, "Agent/%s", p->agent);
01003    if (!tmp) {
01004       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01005       return NULL;
01006    }
01007 
01008    tmp->tech = &agent_tech;
01009    if (p->chan) {
01010       tmp->nativeformats = p->chan->nativeformats;
01011       tmp->writeformat = p->chan->writeformat;
01012       tmp->rawwriteformat = p->chan->writeformat;
01013       tmp->readformat = p->chan->readformat;
01014       tmp->rawreadformat = p->chan->readformat;
01015       ast_string_field_set(tmp, language, p->chan->language);
01016       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01017       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01018       /* XXX Is this really all we copy form the originating channel?? */
01019    } else {
01020       tmp->nativeformats = AST_FORMAT_SLINEAR;
01021       tmp->writeformat = AST_FORMAT_SLINEAR;
01022       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01023       tmp->readformat = AST_FORMAT_SLINEAR;
01024       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01025    }
01026    /* Safe, agentlock already held */
01027    tmp->tech_pvt = p;
01028    p->owner = tmp;
01029    tmp->priority = 1;
01030    /* Wake up and wait for other applications (by definition the login app)
01031     * to release this channel). Takes ownership of the agent channel
01032     * to this thread only.
01033     * For signalling the other thread, ast_queue_frame is used until we
01034     * can safely use signals for this purpose. The pselect() needs to be
01035     * implemented in the kernel for this.
01036     */
01037    p->app_sleep_cond = 0;
01038 
01039    alreadylocked = p->app_lock_flag;
01040    p->app_lock_flag = 1;
01041 
01042    if (alreadylocked) {
01043       if (p->chan) {
01044          ast_queue_frame(p->chan, &ast_null_frame);
01045          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01046          p->app_lock_flag = 1;
01047          ast_mutex_lock(&p->lock);
01048       } else {
01049          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01050          p->owner = NULL;
01051          tmp->tech_pvt = NULL;
01052          p->app_sleep_cond = 1;
01053          tmp = ast_channel_release(tmp);
01054          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01055          p->app_lock_flag = 0;
01056          ast_cond_signal(&p->app_complete_cond);
01057          return NULL;
01058       }
01059    } 
01060    if (p->chan)
01061       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01062    return tmp;
01063 }

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

Definition at line 528 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_logoff(), agent_start_monitoring(), AST_AGENT_FD, 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_STATE_UP, AST_TIMING_FD, ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, agent_pvt::enddtmf, f, ast_channel::fdno, ast_frame::frametype, agent_pvt::lock, LOG_NOTICE, ast_channel::name, agent_pvt::name, agent_pvt::start, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, and ast_channel_tech::type.

00529 {
00530    struct agent_pvt *p = ast->tech_pvt;
00531    struct ast_frame *f = NULL;
00532    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00533    int cur_time = time(NULL);
00534    ast_mutex_lock(&p->lock);
00535    CHECK_FORMATS(ast, p);
00536    if (!p->start) {
00537       p->start = cur_time;
00538    }
00539    if (p->chan) {
00540       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00541       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00542       f = ast_read(p->chan);
00543    } else
00544       f = &ast_null_frame;
00545    if (!f) {
00546       /* If there's a channel, make it NULL */
00547       if (p->chan) {
00548          p->chan->_bridge = NULL;
00549          p->chan = NULL;
00550          ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00551          p->acknowledged = 0;
00552       }
00553    } else {
00554       /* if acknowledgement is not required, and the channel is up, we may have missed
00555          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00556       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00557          p->acknowledged = 1;
00558       }
00559 
00560       if (!p->acknowledged) {
00561          int howlong = cur_time - p->start;
00562          if (p->autologoff && (howlong >= p->autologoff)) {
00563             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00564             agent_logoff(p->agent, 0);
00565          }
00566       }
00567       switch (f->frametype) {
00568       case AST_FRAME_CONTROL:
00569          if (f->subclass == AST_CONTROL_ANSWER) {
00570             if (p->ackcall) {
00571                ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf);
00572                /* Don't pass answer along */
00573                ast_frfree(f);
00574                f = &ast_null_frame;
00575             } else {
00576                p->acknowledged = 1;
00577                /* Use the builtin answer frame for the 
00578                   recording start check below. */
00579                ast_frfree(f);
00580                f = &answer_frame;
00581             }
00582          }
00583          break;
00584       case AST_FRAME_DTMF_BEGIN:
00585          /*ignore DTMF begin's as it can cause issues with queue announce files*/
00586          if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){
00587             ast_frfree(f);
00588             f = &ast_null_frame;
00589          }
00590          break;
00591       case AST_FRAME_DTMF_END:
00592          if (!p->acknowledged && (f->subclass == p->acceptdtmf)) {
00593             ast_verb(3, "%s acknowledged\n", p->chan->name);
00594             p->acknowledged = 1;
00595             ast_frfree(f);
00596             f = &answer_frame;
00597          } else if (f->subclass == p->enddtmf && endcall) {
00598             /* terminates call */
00599             ast_frfree(f);
00600             f = NULL;
00601          }
00602          break;
00603       case AST_FRAME_VOICE:
00604       case AST_FRAME_VIDEO:
00605          /* don't pass voice or video until the call is acknowledged */
00606          if (!p->acknowledged) {
00607             ast_frfree(f);
00608             f = &ast_null_frame;
00609          }
00610       default:
00611          /* pass everything else on through */
00612          break;
00613       }
00614    }
00615 
00616    CLEANUP(ast,p);
00617    if (p->chan && !p->chan->_bridge) {
00618       if (strcasecmp(p->chan->tech->type, "Local")) {
00619          p->chan->_bridge = ast;
00620          if (p->chan)
00621             ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00622       }
00623    }
00624    ast_mutex_unlock(&p->lock);
00625    if (recordagentcalls && f == &answer_frame)
00626       agent_start_monitoring(ast,0);
00627    return f;
00628 }

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

Part of the Asterisk PBX interface.

Definition at line 1337 of file chan_agent.c.

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

01338 {
01339    struct agent_pvt *p;
01340    struct ast_channel *chan = NULL;
01341    char *s;
01342    ast_group_t groupmatch;
01343    int groupoff;
01344    int waitforagent=0;
01345    int hasagent = 0;
01346    struct timeval now;
01347 
01348    s = data;
01349    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01350       groupmatch = (1 << groupoff);
01351    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01352       groupmatch = (1 << groupoff);
01353       waitforagent = 1;
01354    } else 
01355       groupmatch = 0;
01356 
01357    /* Check actual logged in agents first */
01358    AST_LIST_LOCK(&agents);
01359    AST_LIST_TRAVERSE(&agents, p, list) {
01360       ast_mutex_lock(&p->lock);
01361       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01362          if (p->chan)
01363             hasagent++;
01364          now = ast_tvnow();
01365          if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01366             p->lastdisc = ast_tv(0, 0);
01367             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01368             if (!p->owner && p->chan) {
01369                /* Fixed agent */
01370                chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01371             }
01372             if (chan) {
01373                ast_mutex_unlock(&p->lock);
01374                break;
01375             }
01376          }
01377       }
01378       ast_mutex_unlock(&p->lock);
01379    }
01380    if (!p) {
01381       AST_LIST_TRAVERSE(&agents, p, list) {
01382          ast_mutex_lock(&p->lock);
01383          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01384             if (p->chan) {
01385                hasagent++;
01386             }
01387             now = ast_tvnow();
01388             if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01389                p->lastdisc = ast_tv(0, 0);
01390                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01391                if (!p->owner && p->chan) {
01392                   /* Could still get a fixed agent */
01393                   chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01394                }
01395                if (chan) {
01396                   ast_mutex_unlock(&p->lock);
01397                   break;
01398                }
01399             }
01400          }
01401          ast_mutex_unlock(&p->lock);
01402       }
01403    }
01404 
01405    if (!chan && waitforagent) {
01406       /* No agent available -- but we're requesting to wait for one.
01407          Allocate a place holder */
01408       if (hasagent) {
01409          ast_debug(1, "Creating place holder for '%s'\n", s);
01410          p = add_agent(data, 1);
01411          p->group = groupmatch;
01412          chan = agent_new(p, AST_STATE_DOWN, requestor ? requestor->linkedid : NULL);
01413          if (!chan) 
01414             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01415       } else {
01416          ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
01417       }
01418    }
01419    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01420    AST_LIST_UNLOCK(&agents);
01421    return chan;
01422 }

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

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

00631 {
00632    struct agent_pvt *p = ast->tech_pvt;
00633    int res = -1;
00634    ast_mutex_lock(&p->lock);
00635    if (p->chan) 
00636       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00637    ast_mutex_unlock(&p->lock);
00638    return res;
00639 }

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

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

00642 {
00643    struct agent_pvt *p = ast->tech_pvt;
00644    int res = -1;
00645    ast_mutex_lock(&p->lock);
00646    if (p->chan) 
00647       res = ast_sendtext(p->chan, text);
00648    ast_mutex_unlock(&p->lock);
00649    return res;
00650 }

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

Definition at line 814 of file chan_agent.c.

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

00815 {
00816    struct agent_pvt *p = NULL;
00817    
00818    if (!chan || !base) {
00819       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00820       return -1;
00821    }
00822    p = chan->tech_pvt;
00823    if (!p) {
00824       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00825       return -1;
00826    }
00827    p->chan = base;
00828    return 0;
00829 }

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

Definition at line 523 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00524 {
00525    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00526 }

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

Definition at line 652 of file chan_agent.c.

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

00653 {
00654    struct agent_pvt *p = ast->tech_pvt;
00655    int res = -1;
00656    CHECK_FORMATS(ast, p);
00657    ast_mutex_lock(&p->lock);
00658    if (!p->chan) 
00659       res = 0;
00660    else {
00661       if ((f->frametype != AST_FRAME_VOICE) ||
00662           (f->frametype != AST_FRAME_VIDEO) ||
00663           (f->subclass == p->chan->writeformat)) {
00664          res = ast_write(p->chan, f);
00665       } else {
00666          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00667             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00668             ast->name, p->chan->name);
00669          res = 0;
00670       }
00671    }
00672    CLEANUP(ast, p);
00673    ast_mutex_unlock(&p->lock);
00674    return res;
00675 }

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 2117 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_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, GETAGENTBYCALLERID, LOG_WARNING, and pbx_builtin_getvar_helper().

Referenced by load_module().

02118 {
02119    int exitifnoagentid = 0;
02120    int nowarnings = 0;
02121    int changeoutgoing = 0;
02122    int res = 0;
02123    char agent[AST_MAX_AGENT];
02124 
02125    if (data) {
02126       if (strchr(data, 'd'))
02127          exitifnoagentid = 1;
02128       if (strchr(data, 'n'))
02129          nowarnings = 1;
02130       if (strchr(data, 'c'))
02131          changeoutgoing = 1;
02132    }
02133    if (chan->cid.cid_num) {
02134       const char *tmp;
02135       char agentvar[AST_MAX_BUF];
02136       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02137       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02138          struct agent_pvt *p;
02139          ast_copy_string(agent, tmp, sizeof(agent));
02140          AST_LIST_LOCK(&agents);
02141          AST_LIST_TRAVERSE(&agents, p, list) {
02142             if (!strcasecmp(p->agent, tmp)) {
02143                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02144                __agent_start_monitoring(chan, p, 1);
02145                break;
02146             }
02147          }
02148          AST_LIST_UNLOCK(&agents);
02149          
02150       } else {
02151          res = -1;
02152          if (!nowarnings)
02153             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);
02154       }
02155    } else {
02156       res = -1;
02157       if (!nowarnings)
02158          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");
02159    }
02160    if (res) {
02161       if (exitifnoagentid)
02162          return res;
02163    }
02164    return 0;
02165 }

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

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

01641 {
01642    struct agent_pvt *p;
01643    char username[AST_MAX_BUF];
01644    char location[AST_MAX_BUF] = "";
01645    char talkingto[AST_MAX_BUF] = "";
01646    char music[AST_MAX_BUF];
01647    int count_agents = 0;      /*!< Number of agents configured */
01648    int online_agents = 0;     /*!< Number of online agents */
01649    int offline_agents = 0;    /*!< Number of offline agents */
01650 
01651    switch (cmd) {
01652    case CLI_INIT:
01653       e->command = "agent show";
01654       e->usage =
01655          "Usage: agent show\n"
01656          "       Provides summary information on agents.\n";
01657       return NULL;
01658    case CLI_GENERATE:
01659       return NULL;
01660    }
01661 
01662    if (a->argc != 2)
01663       return CLI_SHOWUSAGE;
01664 
01665    AST_LIST_LOCK(&agents);
01666    AST_LIST_TRAVERSE(&agents, p, list) {
01667       ast_mutex_lock(&p->lock);
01668       if (p->pending) {
01669          if (p->group)
01670             ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01671          else
01672             ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01673       } else {
01674          if (!ast_strlen_zero(p->name))
01675             snprintf(username, sizeof(username), "(%s) ", p->name);
01676          else
01677             username[0] = '\0';
01678          if (p->chan) {
01679             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01680             if (p->owner && ast_bridged_channel(p->owner))
01681                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01682              else 
01683                strcpy(talkingto, " is idle");
01684             online_agents++;
01685          } else {
01686             strcpy(location, "not logged in");
01687             talkingto[0] = '\0';
01688             offline_agents++;
01689          }
01690          if (!ast_strlen_zero(p->moh))
01691             snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01692          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
01693             username, location, talkingto, music);
01694          count_agents++;
01695       }
01696       ast_mutex_unlock(&p->lock);
01697    }
01698    AST_LIST_UNLOCK(&agents);
01699    if ( !count_agents ) 
01700       ast_cli(a->fd, "No Agents are configured in %s\n",config);
01701    else 
01702       ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01703    ast_cli(a->fd, "\n");
01704                    
01705    return CLI_SUCCESS;
01706 }

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

Definition at line 1709 of file chan_agent.c.

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

01710 {
01711    struct agent_pvt *p;
01712    char username[AST_MAX_BUF];
01713    char location[AST_MAX_BUF] = "";
01714    char talkingto[AST_MAX_BUF] = "";
01715    char music[AST_MAX_BUF];
01716    int count_agents = 0;           /* Number of agents configured */
01717    int online_agents = 0;          /* Number of online agents */
01718    int agent_status = 0;           /* 0 means offline, 1 means online */
01719 
01720    switch (cmd) {
01721    case CLI_INIT:
01722       e->command = "agent show online";
01723       e->usage =
01724          "Usage: agent show online\n"
01725          "       Provides a list of all online agents.\n";
01726       return NULL;
01727    case CLI_GENERATE:
01728       return NULL;
01729    }
01730 
01731    if (a->argc != 3)
01732       return CLI_SHOWUSAGE;
01733 
01734    AST_LIST_LOCK(&agents);
01735    AST_LIST_TRAVERSE(&agents, p, list) {
01736       agent_status = 0;       /* reset it to offline */
01737       ast_mutex_lock(&p->lock);
01738       if (!ast_strlen_zero(p->name))
01739          snprintf(username, sizeof(username), "(%s) ", p->name);
01740       else
01741          username[0] = '\0';
01742       if (p->chan) {
01743          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01744          if (p->owner && ast_bridged_channel(p->owner)) 
01745             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01746          else 
01747             strcpy(talkingto, " is idle");
01748          agent_status = 1;
01749          online_agents++;
01750       }
01751       if (!ast_strlen_zero(p->moh))
01752          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01753       if (agent_status)
01754          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01755       count_agents++;
01756       ast_mutex_unlock(&p->lock);
01757    }
01758    AST_LIST_UNLOCK(&agents);
01759    if (!count_agents) 
01760       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01761    else
01762       ast_cli(a->fd, "%d agents online\n", online_agents);
01763    ast_cli(a->fd, "\n");
01764    return CLI_SUCCESS;
01765 }

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

Definition at line 1235 of file chan_agent.c.

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

Referenced by login_exec().

01236 {
01237    struct ast_channel *chan=NULL, *parent=NULL;
01238    struct agent_pvt *p;
01239    int res;
01240 
01241    ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
01242    if (needlock)
01243       AST_LIST_LOCK(&agents);
01244    AST_LIST_TRAVERSE(&agents, p, list) {
01245       if (p == newlyavailable) {
01246          continue;
01247       }
01248       ast_mutex_lock(&p->lock);
01249       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01250          ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01251          /* We found a pending call, time to merge */
01252          chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? p->owner->linkedid : NULL);
01253          parent = p->owner;
01254          p->abouttograb = 1;
01255          ast_mutex_unlock(&p->lock);
01256          break;
01257       }
01258       ast_mutex_unlock(&p->lock);
01259    }
01260    if (needlock)
01261       AST_LIST_UNLOCK(&agents);
01262    if (parent && chan)  {
01263       if (newlyavailable->ackcall) {
01264          /* Don't do beep here */
01265          res = 0;
01266       } else {
01267          ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01268          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01269          ast_debug(3, "Played beep, result '%d'\n", res);
01270          if (!res) {
01271             res = ast_waitstream(newlyavailable->chan, "");
01272             ast_debug(1, "Waited for stream, result '%d'\n", res);
01273          }
01274       }
01275       if (!res) {
01276          /* Note -- parent may have disappeared */
01277          if (p->abouttograb) {
01278             newlyavailable->acknowledged = 1;
01279             /* Safe -- agent lock already held */
01280             ast_setstate(parent, AST_STATE_UP);
01281             ast_setstate(chan, AST_STATE_UP);
01282             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01283             /* Go ahead and mark the channel as a zombie so that masquerade will
01284                destroy it for us, and we need not call ast_hangup */
01285             ast_set_flag(chan, AST_FLAG_ZOMBIE);
01286             ast_channel_masquerade(parent, chan);
01287             p->abouttograb = 0;
01288          } else {
01289             ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
01290             agent_cleanup(newlyavailable);
01291          }
01292       } else {
01293          ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
01294          agent_cleanup(newlyavailable);
01295       }
01296    }
01297    return 0;
01298 }

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

Definition at line 1300 of file chan_agent.c.

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

Referenced by login_exec().

01301 {
01302    struct agent_pvt *p;
01303    int res=0;
01304 
01305    ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01306    if (needlock)
01307       AST_LIST_LOCK(&agents);
01308    AST_LIST_TRAVERSE(&agents, p, list) {
01309       if (p == newlyavailable) {
01310          continue;
01311       }
01312       ast_mutex_lock(&p->lock);
01313       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01314          ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01315          ast_mutex_unlock(&p->lock);
01316          break;
01317       }
01318       ast_mutex_unlock(&p->lock);
01319    }
01320    if (needlock)
01321       AST_LIST_UNLOCK(&agents);
01322    if (p) {
01323       ast_mutex_unlock(&newlyavailable->lock);
01324       ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01325       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01326       ast_debug(1, "Played beep, result '%d'\n", res);
01327       if (!res) {
01328          res = ast_waitstream(newlyavailable->chan, "");
01329          ast_debug(1, "Waited for stream, result '%d'\n", res);
01330       }
01331       ast_mutex_lock(&newlyavailable->lock);
01332    }
01333    return res;
01334 }

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

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

01614 {
01615    char *ret = NULL;
01616 
01617    if (pos == 2) {
01618       struct agent_pvt *p;
01619       char name[AST_MAX_AGENT];
01620       int which = 0, len = strlen(word);
01621 
01622       AST_LIST_LOCK(&agents);
01623       AST_LIST_TRAVERSE(&agents, p, list) {
01624          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01625          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01626             ret = ast_strdup(name);
01627             break;
01628          }
01629       }
01630       AST_LIST_UNLOCK(&agents);
01631    } else if (pos == 3 && state == 0) 
01632       return ast_strdup("soft");
01633    
01634    return ret;
01635 }

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

Note:
This function expects the agent list to be locked

Definition at line 2215 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02216 {
02217    struct agent_pvt *cur;
02218 
02219    AST_LIST_TRAVERSE(&agents, cur, list) {
02220       if (!strcmp(cur->agent, agentid))
02221          break;   
02222    }
02223 
02224    return cur; 
02225 }

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

Definition at line 2227 of file chan_agent.c.

References agent_pvt::agent, AST_APP_ARG, 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, ast_channel::name, agent_pvt::name, parse(), agent_pvt::password, and status.

02228 {
02229    char *parse;    
02230    AST_DECLARE_APP_ARGS(args,
02231       AST_APP_ARG(agentid);
02232       AST_APP_ARG(item);
02233    );
02234    char *tmp;
02235    struct agent_pvt *agent;
02236 
02237    buf[0] = '\0';
02238 
02239    if (ast_strlen_zero(data)) {
02240       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02241       return -1;
02242    }
02243 
02244    parse = ast_strdupa(data);
02245 
02246    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02247    if (!args.item)
02248       args.item = "status";
02249 
02250    AST_LIST_LOCK(&agents);
02251 
02252    if (!(agent = find_agent(args.agentid))) {
02253       AST_LIST_UNLOCK(&agents);
02254       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02255       return -1;
02256    }
02257 
02258    if (!strcasecmp(args.item, "status")) {
02259       char *status = "LOGGEDOUT";
02260       if (agent->chan) {
02261          status = "LOGGEDIN";
02262       }
02263       ast_copy_string(buf, status, len);
02264    } else if (!strcasecmp(args.item, "password")) 
02265       ast_copy_string(buf, agent->password, len);
02266    else if (!strcasecmp(args.item, "name"))
02267       ast_copy_string(buf, agent->name, len);
02268    else if (!strcasecmp(args.item, "mohclass"))
02269       ast_copy_string(buf, agent->moh, len);
02270    else if (!strcasecmp(args.item, "channel")) {
02271       if (agent->chan) {
02272          ast_copy_string(buf, agent->chan->name, len);
02273          tmp = strrchr(buf, '-');
02274          if (tmp)
02275             *tmp = '\0';
02276       } 
02277    } else if (!strcasecmp(args.item, "exten")) {
02278       buf[0] = '\0';
02279    }
02280 
02281    AST_LIST_UNLOCK(&agents);
02282 
02283    return 0;
02284 }

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

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

02300 {
02301    /* Make sure we can register our agent channel type */
02302    if (ast_channel_register(&agent_tech)) {
02303       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02304       return AST_MODULE_LOAD_FAILURE;
02305    }
02306    /* Read in the config */
02307    if (!read_agent_config(0))
02308       return AST_MODULE_LOAD_DECLINE;
02309    /* Dialplan applications */
02310    ast_register_application_xml(app, login_exec);
02311    ast_register_application_xml(app3, agentmonitoroutgoing_exec);
02312 
02313    /* Manager commands */
02314    ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
02315    ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
02316 
02317    /* CLI Commands */
02318    ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
02319 
02320    /* Dialplan Functions */
02321    ast_custom_function_register(&agent_function);
02322 
02323    return AST_MODULE_LOAD_SUCCESS;
02324 }

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

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

Referenced by load_module().

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

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

Definition at line 1424 of file chan_agent.c.

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

01425 {
01426    int x = ffs(d);
01427 
01428    if (x)
01429       return x - 1;
01430 
01431    return 0;
01432 }

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

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

Referenced by load_module(), and reload().

01072 {
01073    struct ast_config *cfg;
01074    struct ast_config *ucfg;
01075    struct ast_variable *v;
01076    struct agent_pvt *p;
01077    const char *catname;
01078    const char *hasagent;
01079    int genhasagent;
01080    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01081 
01082    group = 0;
01083    autologoff = 0;
01084    wrapuptime = 0;
01085    ackcall = 0;
01086    endcall = 1;
01087    cfg = ast_config_load(config, config_flags);
01088    if (!cfg) {
01089       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01090       return 0;
01091    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
01092       return -1;
01093    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01094       ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
01095       return 0;
01096    }
01097    if ((ucfg = ast_config_load("users.conf", config_flags))) {
01098       if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
01099          ucfg = NULL;
01100       } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
01101          ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
01102          return 0;
01103       }
01104    }
01105 
01106    AST_LIST_LOCK(&agents);
01107    AST_LIST_TRAVERSE(&agents, p, list) {
01108       p->dead = 1;
01109    }
01110    strcpy(moh, "default");
01111    /* set the default recording values */
01112    recordagentcalls = 0;
01113    strcpy(recordformat, "wav");
01114    strcpy(recordformatext, "wav");
01115    urlprefix[0] = '\0';
01116    savecallsin[0] = '\0';
01117 
01118    /* Read in [general] section for persistence */
01119    multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
01120 
01121    /* Read in the [agents] section */
01122    v = ast_variable_browse(cfg, "agents");
01123    while(v) {
01124       /* Create the interface list */
01125       if (!strcasecmp(v->name, "agent")) {
01126          add_agent(v->value, 0);
01127       } else if (!strcasecmp(v->name, "group")) {
01128          group = ast_get_group(v->value);
01129       } else if (!strcasecmp(v->name, "autologoff")) {
01130          autologoff = atoi(v->value);
01131          if (autologoff < 0)
01132             autologoff = 0;
01133       } else if (!strcasecmp(v->name, "ackcall")) {
01134          if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
01135             ackcall = 1;
01136          }
01137       } else if (!strcasecmp(v->name, "endcall")) {
01138          endcall = ast_true(v->value);
01139       } else if (!strcasecmp(v->name, "acceptdtmf")) {
01140          acceptdtmf = *(v->value);
01141          ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
01142       } else if (!strcasecmp(v->name, "enddtmf")) {
01143          enddtmf = *(v->value);
01144       } else if (!strcasecmp(v->name, "wrapuptime")) {
01145          wrapuptime = atoi(v->value);
01146          if (wrapuptime < 0)
01147             wrapuptime = 0;
01148       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01149          maxlogintries = atoi(v->value);
01150          if (maxlogintries < 0)
01151             maxlogintries = 0;
01152       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01153          strcpy(agentgoodbye,v->value);
01154       } else if (!strcasecmp(v->name, "musiconhold")) {
01155          ast_copy_string(moh, v->value, sizeof(moh));
01156       } else if (!strcasecmp(v->name, "updatecdr")) {
01157          if (ast_true(v->value))
01158             updatecdr = 1;
01159          else
01160             updatecdr = 0;
01161       } else if (!strcasecmp(v->name, "autologoffunavail")) {
01162          if (ast_true(v->value))
01163             autologoffunavail = 1;
01164          else
01165             autologoffunavail = 0;
01166       } else if (!strcasecmp(v->name, "recordagentcalls")) {
01167          recordagentcalls = ast_true(v->value);
01168       } else if (!strcasecmp(v->name, "recordformat")) {
01169          ast_copy_string(recordformat, v->value, sizeof(recordformat));
01170          if (!strcasecmp(v->value, "wav49"))
01171             strcpy(recordformatext, "WAV");
01172          else
01173             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01174       } else if (!strcasecmp(v->name, "urlprefix")) {
01175          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01176          if (urlprefix[strlen(urlprefix) - 1] != '/')
01177             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01178       } else if (!strcasecmp(v->name, "savecallsin")) {
01179          if (v->value[0] == '/')
01180             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01181          else
01182             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01183          if (savecallsin[strlen(savecallsin) - 1] != '/')
01184             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01185       } else if (!strcasecmp(v->name, "custom_beep")) {
01186          ast_copy_string(beep, v->value, sizeof(beep));
01187       }
01188       v = v->next;
01189    }
01190    if (ucfg) {
01191       genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01192       catname = ast_category_browse(ucfg, NULL);
01193       while(catname) {
01194          if (strcasecmp(catname, "general")) {
01195             hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01196             if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01197                char tmp[256];
01198                const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01199                const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01200                if (!fullname)
01201                   fullname = "";
01202                if (!secret)
01203                   secret = "";
01204                snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01205                add_agent(tmp, 0);
01206             }
01207          }
01208          catname = ast_category_browse(ucfg, catname);
01209       }
01210       ast_config_destroy(ucfg);
01211    }
01212    AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01213       if (p->dead) {
01214          AST_LIST_REMOVE_CURRENT(list);
01215          /* Destroy if  appropriate */
01216          if (!p->owner) {
01217             if (!p->chan) {
01218                ast_mutex_destroy(&p->lock);
01219                ast_mutex_destroy(&p->app_lock);
01220                ast_cond_destroy(&p->app_complete_cond);
01221                ast_free(p);
01222             } else {
01223                /* Cause them to hang up */
01224                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01225             }
01226          }
01227       }
01228    }
01229    AST_LIST_TRAVERSE_SAFE_END;
01230    AST_LIST_UNLOCK(&agents);
01231    ast_config_destroy(cfg);
01232    return 1;
01233 }

static int reload ( void   )  [static]

Definition at line 2326 of file chan_agent.c.

References read_agent_config().

02327 {
02328    return read_agent_config(1);
02329 }

static int unload_module ( void   )  [static]

Definition at line 2331 of file chan_agent.c.

References agent_function, agent_tech, ARRAY_LEN, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_free, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_manager_unregister(), ast_softhangup(), AST_SOFTHANGUP_APPUNLOAD, ast_unregister_application(), cli_agents, and agent_pvt::owner.

02332 {
02333    struct agent_pvt *p;
02334    /* First, take us out of the channel loop */
02335    ast_channel_unregister(&agent_tech);
02336    /* Unregister dialplan functions */
02337    ast_custom_function_unregister(&agent_function);   
02338    /* Unregister CLI commands */
02339    ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
02340    /* Unregister dialplan applications */
02341    ast_unregister_application(app);
02342    ast_unregister_application(app3);
02343    /* Unregister manager command */
02344    ast_manager_unregister("Agents");
02345    ast_manager_unregister("AgentLogoff");
02346    /* Unregister channel */
02347    AST_LIST_LOCK(&agents);
02348    /* Hangup all interfaces if they have an owner */
02349    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02350       if (p->owner)
02351          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02352       ast_free(p);
02353    }
02354    AST_LIST_UNLOCK(&agents);
02355    return 0;
02356 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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, } [static]

Definition at line 2362 of file chan_agent.c.

char acceptdtmf = DEFAULT_ACCEPTDTMF [static]

Definition at line 222 of file chan_agent.c.

Referenced by play_record_review().

int ackcall [static]

Definition at line 218 of file chan_agent.c.

Initial value:

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

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

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

Definition at line 200 of file chan_agent.c.

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

Definition at line 201 of file chan_agent.c.

Definition at line 2362 of file chan_agent.c.

int autologoff [static]

Definition at line 216 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 221 of file chan_agent.c.

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

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

Referenced by load_module(), and unload_module().

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

Definition at line 198 of file chan_agent.c.

int endcall [static]

Definition at line 219 of file chan_agent.c.

char enddtmf = DEFAULT_ENDDTMF [static]

Definition at line 223 of file chan_agent.c.

ast_group_t group [static]

Definition at line 215 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 225 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 220 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 209 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 228 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 229 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 230 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 232 of file chan_agent.c.

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

Definition at line 197 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 233 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 231 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 217 of file chan_agent.c.


Generated on Wed Oct 28 13:31:57 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6