Wed Oct 28 11:51:48 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/rtp.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 void agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
static struct ast_channelagent_new (struct agent_pvt *p, int state)
 Create new agent channel.
static struct ast_frameagent_read (struct ast_channel *ast)
static struct ast_channelagent_request (const char *type, int format, 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, void *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 void dump_agents (void)
 Dump AgentCallbackLogin agents to the ASTdb database for persistence.
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, void *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 void reload_agents (void)
 Reload the persistent agents from astdb.
static void set_agentbycallerid (const char *callerid, const char *agent)
 store/clear the global variable that stores agentid based on the callerid
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
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 const char descrip []
static const char descrip3 []
static int endcall
static char enddtmf = DEFAULT_ENDDTMF
static ast_group_t group
static const char mandescr_agent_logoff []
static const char mandescr_agents []
static int maxlogintries = 3
static char moh [80] = "default"
static int multiplelogin = 1
static const char pa_family [] = "Agents"
static int persistent_agents = 0
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 synopsis [] = "Call agent login"
static const char synopsis3 [] = "Record agent's outgoing call"
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 118 of file chan_agent.c.

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

#define AST_MAX_BUF   256

#define AST_MAX_FILENAME_LEN   256

Definition at line 120 of file chan_agent.c.

Referenced by login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 128 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 129 of file chan_agent.c.

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 152 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().

#define PA_MAX_LEN   2048

The maximum length of each persistent member agent database entry

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

00154      {
00155    AGENT_FLAG_ACKCALL = (1 << 0),
00156    AGENT_FLAG_AUTOLOGOFF = (1 << 1),
00157    AGENT_FLAG_WRAPUPTIME = (1 << 2),
00158    AGENT_FLAG_ACCEPTDTMF = (1 << 3),
00159    AGENT_FLAG_ENDDTMF = (1 << 4),
00160 };


Function Documentation

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

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

00414 {
00415    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00416    char filename[AST_MAX_BUF];
00417    int res = -1;
00418    if (!p)
00419       return -1;
00420    if (!ast->monitor) {
00421       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00422       /* substitute . for - */
00423       if ((pointer = strchr(filename, '.')))
00424          *pointer = '-';
00425       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00426       ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
00427       ast_monitor_setjoinfiles(ast, 1);
00428       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00429 #if 0
00430       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00431 #endif
00432       if (!ast->cdr)
00433          ast->cdr = ast_cdr_alloc();
00434       ast_cdr_setuserfield(ast, tmp2);
00435       res = 0;
00436    } else
00437       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00438    return res;
00439 }

static void __reg_module ( void   )  [static]

Definition at line 2542 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

01662 {
01663    const char *agent = astman_get_header(m, "Agent");
01664    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01665    int soft;
01666    int ret; /* return value of agent_logoff */
01667 
01668    if (ast_strlen_zero(agent)) {
01669       astman_send_error(s, m, "No agent specified");
01670       return 0;
01671    }
01672 
01673    soft = ast_true(soft_s) ? 1 : 0;
01674    ret = agent_logoff(agent, soft);
01675    if (ret == 0)
01676       astman_send_ack(s, m, "Agent logged out");
01677    else
01678       astman_send_error(s, m, "No such agent");
01679 
01680    return 0;
01681 }

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

References ast_channel::_bridge, agent_pvt::acknowledged, 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::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, S_OR, and status.

Referenced by load_module().

01459 {
01460    const char *id = astman_get_header(m,"ActionID");
01461    char idText[256] = "";
01462    char chanbuf[256];
01463    struct agent_pvt *p;
01464    char *username = NULL;
01465    char *loginChan = NULL;
01466    char *talkingto = NULL;
01467    char *talkingtoChan = NULL;
01468    char *status = NULL;
01469 
01470    if (!ast_strlen_zero(id))
01471       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01472    astman_send_ack(s, m, "Agents will follow");
01473    AST_LIST_LOCK(&agents);
01474    AST_LIST_TRAVERSE(&agents, p, list) {
01475          ast_mutex_lock(&p->lock);
01476 
01477       /* Status Values:
01478          AGENT_LOGGEDOFF - Agent isn't logged in
01479          AGENT_IDLE      - Agent is logged in, and waiting for call
01480          AGENT_ONCALL    - Agent is logged in, and on a call
01481          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01482 
01483       username = S_OR(p->name, "None");
01484 
01485       /* Set a default status. It 'should' get changed. */
01486       status = "AGENT_UNKNOWN";
01487 
01488       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01489          loginChan = p->loginchan;
01490          talkingto = "n/a";
01491          talkingtoChan = "n/a";
01492          status = "AGENT_IDLE";
01493          if (p->acknowledged) {
01494             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01495             loginChan = chanbuf;
01496          }
01497       } else if (p->chan) {
01498          loginChan = ast_strdupa(p->chan->name);
01499          if (p->owner && p->owner->_bridge) {
01500             talkingto = p->chan->cid.cid_num;
01501             if (ast_bridged_channel(p->owner))
01502                talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name);
01503             else
01504                talkingtoChan = "n/a";
01505                status = "AGENT_ONCALL";
01506          } else {
01507             talkingto = "n/a";
01508             talkingtoChan = "n/a";
01509                status = "AGENT_IDLE";
01510          }
01511       } else {
01512          loginChan = "n/a";
01513          talkingto = "n/a";
01514          talkingtoChan = "n/a";
01515          status = "AGENT_LOGGEDOFF";
01516       }
01517 
01518       astman_append(s, "Event: Agents\r\n"
01519          "Agent: %s\r\n"
01520          "Name: %s\r\n"
01521          "Status: %s\r\n"
01522          "LoggedInChan: %s\r\n"
01523          "LoggedInTime: %d\r\n"
01524          "TalkingTo: %s\r\n"
01525          "TalkingToChan: %s\r\n"
01526          "%s"
01527          "\r\n",
01528          p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
01529       ast_mutex_unlock(&p->lock);
01530    }
01531    AST_LIST_UNLOCK(&agents);
01532    astman_append(s, "Event: AgentsComplete\r\n"
01533       "%s"
01534       "\r\n",idText);
01535    return 0;
01536 }

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

00285 {
00286    char *parse;
00287    AST_DECLARE_APP_ARGS(args,
00288       AST_APP_ARG(agt);
00289       AST_APP_ARG(password);
00290       AST_APP_ARG(name);
00291    );
00292    char *password = NULL;
00293    char *name = NULL;
00294    char *agt = NULL;
00295    struct agent_pvt *p;
00296 
00297    parse = ast_strdupa(agent);
00298 
00299    /* Extract username (agt), password and name from agent (args). */
00300    AST_STANDARD_APP_ARGS(args, parse);
00301 
00302    if(args.argc == 0) {
00303       ast_log(LOG_WARNING, "A blank agent line!\n");
00304       return NULL;
00305    }
00306 
00307    if(ast_strlen_zero(args.agt) ) {
00308       ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00309       return NULL;
00310    } else
00311       agt = args.agt;
00312 
00313    if(!ast_strlen_zero(args.password)) {
00314       password = args.password;
00315       while (*password && *password < 33) password++;
00316    }
00317    if(!ast_strlen_zero(args.name)) {
00318       name = args.name;
00319       while (*name && *name < 33) name++;
00320    }
00321    
00322    /* Are we searching for the agent here ? To see if it exists already ? */
00323    AST_LIST_TRAVERSE(&agents, p, list) {
00324       if (!pending && !strcmp(p->agent, agt))
00325          break;
00326    }
00327    if (!p) {
00328       // Build the agent.
00329       if (!(p = ast_calloc(1, sizeof(*p))))
00330          return NULL;
00331       ast_copy_string(p->agent, agt, sizeof(p->agent));
00332       ast_mutex_init(&p->lock);
00333       ast_mutex_init(&p->app_lock);
00334       ast_cond_init(&p->app_complete_cond, NULL);
00335       p->app_lock_flag = 0;
00336       p->app_sleep_cond = 1;
00337       p->group = group;
00338       p->pending = pending;
00339       AST_LIST_INSERT_TAIL(&agents, p, list);
00340    }
00341    
00342    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00343    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00344    ast_copy_string(p->moh, moh, sizeof(p->moh));
00345    if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) {
00346       p->ackcall = ackcall;
00347    }
00348    if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) {
00349       p->autologoff = autologoff;
00350    }
00351    if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) {
00352       p->acceptdtmf = acceptdtmf;
00353    }
00354    if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) {
00355       p->enddtmf = enddtmf;
00356    }
00357 
00358    /* If someone reduces the wrapuptime and reloads, we want it
00359     * to change the wrapuptime immediately on all calls */
00360    if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) {
00361       struct timeval now = ast_tvnow();
00362       /* XXX check what is this exactly */
00363 
00364       /* We won't be pedantic and check the tv_usec val */
00365       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00366          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00367          p->lastdisc.tv_usec = now.tv_usec;
00368       }
00369    }
00370    p->wrapuptime = wrapuptime;
00371 
00372    if (pending)
00373       p->dead = 1;
00374    else
00375       p->dead = 0;
00376    return p;
00377 }

static int agent_ack_sleep ( void *  data  )  [static]

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

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

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 407 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00408 {
00409    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00410    return -1;
00411 }

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

Definition at line 975 of file chan_agent.c.

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

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

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

Definition at line 676 of file chan_agent.c.

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

00677 {
00678    struct agent_pvt *p = ast->tech_pvt;
00679    int res = -1;
00680    int newstate=0;
00681    ast_mutex_lock(&p->lock);
00682    p->acknowledged = 0;
00683    if (!p->chan) {
00684       if (p->pending) {
00685          ast_debug(1, "Pretending to dial on pending agent\n");
00686          newstate = AST_STATE_DIALING;
00687          res = 0;
00688       } else {
00689          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00690          res = -1;
00691       }
00692       ast_mutex_unlock(&p->lock);
00693       if (newstate)
00694          ast_setstate(ast, newstate);
00695       return res;
00696    } else if (!ast_strlen_zero(p->loginchan)) {
00697       time(&p->start);
00698       /* Call on this agent */
00699       ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00700       ast_set_callerid(p->chan,
00701          ast->cid.cid_num, ast->cid.cid_name, NULL);
00702       ast_channel_inherit_variables(ast, p->chan);
00703       res = ast_call(p->chan, p->loginchan, 0);
00704       CLEANUP(ast,p);
00705       ast_mutex_unlock(&p->lock);
00706       return res;
00707    }
00708    ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00709    ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
00710    res = ast_streamfile(p->chan, beep, p->chan->language);
00711    ast_debug(3, "Played beep, result '%d'\n", res);
00712    if (!res) {
00713       res = ast_waitstream(p->chan, "");
00714       ast_debug(3, "Waited for stream, result '%d'\n", res);
00715    }
00716    if (!res) {
00717       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00718       ast_debug(3, "Set read format, result '%d'\n", res);
00719       if (res)
00720          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00721    } else {
00722       /* Agent hung-up */
00723       p->chan = NULL;
00724       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00725    }
00726 
00727    if (!res) {
00728       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00729       ast_debug(3, "Set write format, result '%d'\n", res);
00730       if (res)
00731          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00732    }
00733    if(!res) {
00734       /* Call is immediately up, or might need ack */
00735       if (p->ackcall > 1)
00736          newstate = AST_STATE_RINGING;
00737       else {
00738          newstate = AST_STATE_UP;
00739          if (recordagentcalls)
00740             agent_start_monitoring(ast, 0);
00741          p->acknowledged = 1;
00742       }
00743       res = 0;
00744    }
00745    CLEANUP(ast, p);
00746    ast_mutex_unlock(&p->lock);
00747    if (newstate)
00748       ast_setstate(ast, newstate);
00749    return res;
00750 }

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 385 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_free(), 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().

00386 {
00387    struct ast_channel *chan = p->owner;
00388    p->owner = NULL;
00389    chan->tech_pvt = NULL;
00390    p->app_sleep_cond = 1;
00391    /* Release ownership of the agent to other threads (presumably running the login app). */
00392    p->app_lock_flag = 0;
00393    ast_cond_signal(&p->app_complete_cond);
00394    if (chan)
00395       ast_channel_free(chan);
00396    if (p->dead) {
00397       ast_mutex_destroy(&p->lock);
00398       ast_mutex_destroy(&p->app_lock);
00399       ast_cond_destroy(&p->app_complete_cond);
00400       ast_free(p);
00401         }
00402    return 0;
00403 }

static int agent_cont_sleep ( void *  data  )  [static]

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

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

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2334 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(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

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

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

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

00655 {
00656    struct agent_pvt *p = ast->tech_pvt;
00657    ast_mutex_lock(&p->lock);
00658    if (p->chan) {
00659       ast_senddigit_begin(p->chan, digit);
00660    }
00661    ast_mutex_unlock(&p->lock);
00662    return 0;
00663 }

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

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

00666 {
00667    struct agent_pvt *p = ast->tech_pvt;
00668    ast_mutex_lock(&p->lock);
00669    if (p->chan) {
00670       ast_senddigit_end(p->chan, digit, duration);
00671    }
00672    ast_mutex_unlock(&p->lock);
00673    return 0;
00674 }

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

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

00622 {
00623    struct agent_pvt *p = newchan->tech_pvt;
00624    ast_mutex_lock(&p->lock);
00625    if (p->owner != oldchan) {
00626       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00627       ast_mutex_unlock(&p->lock);
00628       return -1;
00629    }
00630    p->owner = newchan;
00631    ast_mutex_unlock(&p->lock);
00632    return 0;
00633 }

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

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

00767 {
00768    struct agent_pvt *p = NULL;
00769    struct ast_channel *base = chan;
00770 
00771    /* chan is locked by the calling function */
00772    if (!chan || !chan->tech_pvt) {
00773       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);
00774       return NULL;
00775    }
00776    p = chan->tech_pvt;
00777    if (p->chan) 
00778       base = p->chan;
00779    return base;
00780 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 799 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), 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_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_hangup(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), 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_tv(), ast_tvadd(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, status, ast_channel::tech_pvt, ast_channel::uniqueid, and agent_pvt::wrapuptime.

00800 {
00801    struct agent_pvt *p = ast->tech_pvt;
00802    int howlong = 0;
00803    const char *status;
00804    ast_mutex_lock(&p->lock);
00805    p->owner = NULL;
00806    ast->tech_pvt = NULL;
00807    p->app_sleep_cond = 1;
00808    p->acknowledged = 0;
00809 
00810    /* if they really are hung up then set start to 0 so the test
00811     * later if we're called on an already downed channel
00812     * doesn't cause an agent to be logged out like when
00813     * agent_request() is followed immediately by agent_hangup()
00814     * as in apps/app_chanisavail.c:chanavail_exec()
00815     */
00816 
00817    ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
00818    if (p->start && (ast->_state != AST_STATE_UP)) {
00819       howlong = time(NULL) - p->start;
00820       p->start = 0;
00821    } else if (ast->_state == AST_STATE_RESERVED) 
00822       howlong = 0;
00823    else
00824       p->start = 0; 
00825    if (p->chan) {
00826       p->chan->_bridge = NULL;
00827       /* If they're dead, go ahead and hang up on the agent now */
00828       if (!ast_strlen_zero(p->loginchan)) {
00829          /* Store last disconnect time */
00830          if (p->wrapuptime)
00831             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00832          else
00833             p->lastdisc = ast_tv(0,0);
00834          if (p->chan) {
00835             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00836             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00837                long logintime = time(NULL) - p->loginstart;
00838                p->loginstart = 0;
00839                ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00840                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00841             }
00842             /* Recognize the hangup and pass it along immediately */
00843             ast_hangup(p->chan);
00844             p->chan = NULL;
00845             ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00846          }
00847          ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00848          if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
00849             long logintime = time(NULL) - p->loginstart;
00850             p->loginstart = 0;
00851             if (!p->deferlogoff)
00852                ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00853             p->deferlogoff = 0;
00854             agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00855             if (persistent_agents)
00856                dump_agents();
00857          }
00858       } else if (p->dead) {
00859          ast_channel_lock(p->chan);
00860          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00861          ast_channel_unlock(p->chan);
00862       } else if (p->loginstart) {
00863          ast_channel_lock(p->chan);
00864          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00865             S_OR(p->moh, NULL),
00866             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00867          ast_channel_unlock(p->chan);
00868       }
00869    }
00870    ast_mutex_unlock(&p->lock);
00871 
00872    /* Only register a device state change if the agent is still logged in */
00873    if (!p->loginstart) {
00874       p->loginchan[0] = '\0';
00875       p->logincallerid[0] = '\0';
00876       if (persistent_agents)
00877          dump_agents();
00878    } else {
00879       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
00880    }
00881 
00882    if (p->pending) {
00883       AST_LIST_LOCK(&agents);
00884       AST_LIST_REMOVE(&agents, p, list);
00885       AST_LIST_UNLOCK(&agents);
00886    }
00887    if (p->abouttograb) {
00888       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00889          kill it later */
00890       p->abouttograb = 0;
00891    } else if (p->dead) {
00892       ast_mutex_destroy(&p->lock);
00893       ast_mutex_destroy(&p->app_lock);
00894       ast_cond_destroy(&p->app_complete_cond);
00895       ast_free(p);
00896    } else {
00897       if (p->chan) {
00898          /* Not dead -- check availability now */
00899          ast_mutex_lock(&p->lock);
00900          /* Store last disconnect time */
00901          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00902          ast_mutex_unlock(&p->lock);
00903       }
00904       /* Release ownership of the agent to other threads (presumably running the login app). */
00905       if (ast_strlen_zero(p->loginchan)) {
00906          p->app_lock_flag = 0;
00907          ast_cond_signal(&p->app_complete_cond);
00908       }
00909    }
00910    return 0;
00911 }

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

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

00636 {
00637    struct agent_pvt *p = ast->tech_pvt;
00638    int res = -1;
00639    ast_mutex_lock(&p->lock);
00640    if (p->chan && !ast_check_hangup(p->chan)) {
00641       while (ast_channel_trylock(p->chan)) {
00642          ast_channel_unlock(ast);
00643          usleep(1);
00644          ast_channel_lock(ast);
00645       }
00646       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00647       ast_channel_unlock(p->chan);
00648    } else
00649       res = 0;
00650    ast_mutex_unlock(&p->lock);
00651    return res;
00652 }

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

Definition at line 1577 of file chan_agent.c.

References agent_pvt::agent, agent_logoff_maintenance(), 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, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.

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

01578 {
01579    struct agent_pvt *p;
01580    long logintime;
01581    int ret = -1; /* Return -1 if no agent if found */
01582 
01583    AST_LIST_LOCK(&agents);
01584    AST_LIST_TRAVERSE(&agents, p, list) {
01585       if (!strcasecmp(p->agent, agent)) {
01586          ret = 0;
01587          if (p->owner || p->chan) {
01588             if (!soft) {
01589                ast_mutex_lock(&p->lock);
01590 
01591                while (p->owner && ast_channel_trylock(p->owner)) {
01592                   DEADLOCK_AVOIDANCE(&p->lock);
01593                }
01594                if (p->owner) {
01595                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01596                   ast_channel_unlock(p->owner);
01597                }
01598 
01599                while (p->chan && ast_channel_trylock(p->chan)) {
01600                   DEADLOCK_AVOIDANCE(&p->lock);
01601                }
01602                if (p->chan) {
01603                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01604                   ast_channel_unlock(p->chan);
01605                }
01606 
01607                ast_mutex_unlock(&p->lock);
01608             } else
01609                p->deferlogoff = 1;
01610          } else {
01611             logintime = time(NULL) - p->loginstart;
01612             p->loginstart = 0;
01613             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01614          }
01615          break;
01616       }
01617    }
01618    AST_LIST_UNLOCK(&agents);
01619 
01620    return ret;
01621 }

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

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

01624 {
01625    int ret;
01626    char *agent;
01627 
01628    switch (cmd) {
01629    case CLI_INIT:
01630       e->command = "agent logoff";
01631       e->usage =
01632          "Usage: agent logoff <channel> [soft]\n"
01633          "       Sets an agent as no longer logged in.\n"
01634          "       If 'soft' is specified, do not hangup existing calls.\n";
01635       return NULL;
01636    case CLI_GENERATE:
01637       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01638    }
01639 
01640    if (a->argc < 3 || a->argc > 4)
01641       return CLI_SHOWUSAGE;
01642    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01643       return CLI_SHOWUSAGE;
01644 
01645    agent = a->argv[2] + 6;
01646    ret = agent_logoff(agent, a->argc == 4);
01647    if (ret == 0)
01648       ast_cli(a->fd, "Logging out %s\n", agent);
01649 
01650    return CLI_SUCCESS;
01651 }

static void agent_logoff_maintenance ( struct agent_pvt p,
char *  loginchan,
long  logintime,
const char *  uniqueid,
char *  logcommand 
) [static]

Definition at line 1538 of file chan_agent.c.

References agent_pvt::agent, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_MAX_AGENT, ast_queue_log(), ast_strdupa, ast_strlen_zero(), dump_agents(), EVENT_FLAG_AGENT, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event, and set_agentbycallerid().

Referenced by agent_hangup(), agent_logoff(), and agent_read().

01539 {
01540    char *tmp = NULL;
01541    char agent[AST_MAX_AGENT];
01542 
01543    if (!ast_strlen_zero(logcommand))
01544       tmp = logcommand;
01545    else
01546       tmp = ast_strdupa("");
01547 
01548    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01549 
01550    if (!ast_strlen_zero(uniqueid)) {
01551       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01552             "Agent: %s\r\n"
01553             "Reason: %s\r\n"
01554             "Loginchan: %s\r\n"
01555             "Logintime: %ld\r\n"
01556             "Uniqueid: %s\r\n", 
01557             p->agent, tmp, loginchan, logintime, uniqueid);
01558    } else {
01559       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01560             "Agent: %s\r\n"
01561             "Reason: %s\r\n"
01562             "Loginchan: %s\r\n"
01563             "Logintime: %ld\r\n",
01564             p->agent, tmp, loginchan, logintime);
01565    }
01566 
01567    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01568    set_agentbycallerid(p->logincallerid, NULL);
01569    p->loginchan[0] ='\0';
01570    p->logincallerid[0] = '\0';
01571    ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
01572    if (persistent_agents)
01573       dump_agents();
01574 
01575 }

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

Create new agent channel.

Definition at line 992 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_free(), 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, ast_strlen_zero(), agent_pvt::chan, ast_channel::context, ast_channel::exten, ast_channel::language, language, agent_pvt::lock, LOG_WARNING, agent_pvt::loginchan, 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().

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

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

Definition at line 446 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_logoff_maintenance(), 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_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), ast_samp2tv(), AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, agent_pvt::enddtmf, f, ast_channel::fdno, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, ast_channel::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, status, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, and agent_pvt::wrapuptime.

00447 {
00448    struct agent_pvt *p = ast->tech_pvt;
00449    struct ast_frame *f = NULL;
00450    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00451    const char *status;
00452    int cur_time = time(NULL);
00453    ast_mutex_lock(&p->lock);
00454    CHECK_FORMATS(ast, p);
00455    if (!p->start) {
00456       p->start = cur_time;
00457    }
00458    if (p->chan) {
00459       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00460       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00461       f = ast_read(p->chan);
00462    } else
00463       f = &ast_null_frame;
00464    if (!f) {
00465       /* If there's a channel, hang it up (if it's on a callback) make it NULL */
00466       if (p->chan) {
00467          p->chan->_bridge = NULL;
00468          /* Note that we don't hangup if it's not a callback because Asterisk will do it
00469             for us when the PBX instance that called login finishes */
00470          if (!ast_strlen_zero(p->loginchan)) {
00471             if (p->chan)
00472                ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00473             if (p->owner->_state != AST_STATE_UP) {
00474                int howlong = cur_time - p->start;
00475                if (p->autologoff && howlong >= p->autologoff) {
00476                   p->loginstart = 0;
00477                      ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00478                   agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff");
00479                }
00480             }
00481             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00482             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00483                long logintime = cur_time - p->loginstart;
00484                p->loginstart = 0;
00485                ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
00486                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00487             }
00488             ast_hangup(p->chan);
00489             if (p->wrapuptime && p->acknowledged)
00490                p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00491          }
00492          p->chan = NULL;
00493          ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00494          p->acknowledged = 0;
00495       }
00496    } else {
00497       /* if acknowledgement is not required, and the channel is up, we may have missed
00498          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00499       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00500          p->acknowledged = 1;
00501       }
00502 
00503       if (!p->acknowledged) {
00504          int howlong = cur_time - p->start;
00505          if (p->autologoff && (howlong >= p->autologoff)) {
00506             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00507             agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff");
00508             agent_logoff(p->agent, 0);
00509          }
00510       }
00511       switch (f->frametype) {
00512       case AST_FRAME_CONTROL:
00513          if (f->subclass == AST_CONTROL_ANSWER) {
00514             if (p->ackcall) {
00515                ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf);
00516                /* Don't pass answer along */
00517                ast_frfree(f);
00518                f = &ast_null_frame;
00519             } else {
00520                p->acknowledged = 1;
00521                /* Use the builtin answer frame for the 
00522                   recording start check below. */
00523                ast_frfree(f);
00524                f = &answer_frame;
00525             }
00526          }
00527          break;
00528       case AST_FRAME_DTMF_BEGIN:
00529          /*ignore DTMF begin's as it can cause issues with queue announce files*/
00530          if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){
00531             ast_frfree(f);
00532             f = &ast_null_frame;
00533          }
00534          break;
00535       case AST_FRAME_DTMF_END:
00536          if (!p->acknowledged && (f->subclass == p->acceptdtmf)) {
00537             ast_verb(3, "%s acknowledged\n", p->chan->name);
00538             p->acknowledged = 1;
00539             ast_frfree(f);
00540             f = &answer_frame;
00541          } else if (f->subclass == p->enddtmf && endcall) {
00542             /* terminates call */
00543             ast_frfree(f);
00544             f = NULL;
00545          }
00546          break;
00547       case AST_FRAME_VOICE:
00548       case AST_FRAME_VIDEO:
00549          /* don't pass voice or video until the call is acknowledged */
00550          if (!p->acknowledged) {
00551             ast_frfree(f);
00552             f = &ast_null_frame;
00553          }
00554       default:
00555          /* pass everything else on through */
00556          break;
00557       }
00558    }
00559 
00560    CLEANUP(ast,p);
00561    if (p->chan && !p->chan->_bridge) {
00562       if (strcasecmp(p->chan->tech->type, "Local")) {
00563          p->chan->_bridge = ast;
00564          if (p->chan)
00565             ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00566       }
00567    }
00568    ast_mutex_unlock(&p->lock);
00569    if (recordagentcalls && f == &answer_frame)
00570       agent_start_monitoring(ast,0);
00571    return f;
00572 }

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

Part of the Asterisk PBX interface.

Definition at line 1345 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_request(), AST_STATE_DOWN, ast_strlen_zero(), ast_tv(), ast_tvnow(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

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

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

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

00575 {
00576    struct agent_pvt *p = ast->tech_pvt;
00577    int res = -1;
00578    ast_mutex_lock(&p->lock);
00579    if (p->chan) 
00580       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00581    ast_mutex_unlock(&p->lock);
00582    return res;
00583 }

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

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

00586 {
00587    struct agent_pvt *p = ast->tech_pvt;
00588    int res = -1;
00589    ast_mutex_lock(&p->lock);
00590    if (p->chan) 
00591       res = ast_sendtext(p->chan, text);
00592    ast_mutex_unlock(&p->lock);
00593    return res;
00594 }

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

Definition at line 782 of file chan_agent.c.

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

00783 {
00784    struct agent_pvt *p = NULL;
00785    
00786    if (!chan || !base) {
00787       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00788       return -1;
00789    }
00790    p = chan->tech_pvt;
00791    if (!p) {
00792       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00793       return -1;
00794    }
00795    p->chan = base;
00796    return 0;
00797 }

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

Definition at line 441 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00442 {
00443    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00444 }

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

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

00597 {
00598    struct agent_pvt *p = ast->tech_pvt;
00599    int res = -1;
00600    CHECK_FORMATS(ast, p);
00601    ast_mutex_lock(&p->lock);
00602    if (!p->chan) 
00603       res = 0;
00604    else {
00605       if ((f->frametype != AST_FRAME_VOICE) ||
00606           (f->frametype != AST_FRAME_VIDEO) ||
00607           (f->subclass == p->chan->writeformat)) {
00608          res = ast_write(p->chan, f);
00609       } else {
00610          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00611             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00612             ast->name, p->chan->name);
00613          res = 0;
00614       }
00615    }
00616    CLEANUP(ast, p);
00617    ast_mutex_unlock(&p->lock);
00618    return res;
00619 }

static int agentmonitoroutgoing_exec ( struct ast_channel chan,
void *  data 
) [static]

Called by the AgentMonitorOutgoing application (from the dial plan).

Parameters:
chan 
data 
Returns:
See also:
login_exec(), load_module().

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

02206 {
02207    int exitifnoagentid = 0;
02208    int nowarnings = 0;
02209    int changeoutgoing = 0;
02210    int res = 0;
02211    char agent[AST_MAX_AGENT];
02212 
02213    if (data) {
02214       if (strchr(data, 'd'))
02215          exitifnoagentid = 1;
02216       if (strchr(data, 'n'))
02217          nowarnings = 1;
02218       if (strchr(data, 'c'))
02219          changeoutgoing = 1;
02220    }
02221    if (chan->cid.cid_num) {
02222       const char *tmp;
02223       char agentvar[AST_MAX_BUF];
02224       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02225       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02226          struct agent_pvt *p;
02227          ast_copy_string(agent, tmp, sizeof(agent));
02228          AST_LIST_LOCK(&agents);
02229          AST_LIST_TRAVERSE(&agents, p, list) {
02230             if (!strcasecmp(p->agent, tmp)) {
02231                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02232                __agent_start_monitoring(chan, p, 1);
02233                break;
02234             }
02235          }
02236          AST_LIST_UNLOCK(&agents);
02237          
02238       } else {
02239          res = -1;
02240          if (!nowarnings)
02241             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);
02242       }
02243    } else {
02244       res = -1;
02245       if (!nowarnings)
02246          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");
02247    }
02248    if (res) {
02249       if (exitifnoagentid)
02250          return res;
02251    }
02252    return 0;
02253 }

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

References agent_pvt::acknowledged, 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(), ast_tvdiff_ms(), ast_tvnow(), agent_pvt::chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), and ast_cli_entry::usage.

01711 {
01712    struct agent_pvt *p;
01713    char username[AST_MAX_BUF];
01714    char location[AST_MAX_BUF] = "";
01715    char talkingto[AST_MAX_BUF] = "";
01716    char music[AST_MAX_BUF];
01717    int count_agents = 0;      /*!< Number of agents configured */
01718    int online_agents = 0;     /*!< Number of online agents */
01719    int offline_agents = 0;    /*!< Number of offline agents */
01720 
01721    switch (cmd) {
01722    case CLI_INIT:
01723       e->command = "agent show";
01724       e->usage =
01725          "Usage: agent show\n"
01726          "       Provides summary information on agents.\n";
01727       return NULL;
01728    case CLI_GENERATE:
01729       return NULL;
01730    }
01731 
01732    if (a->argc != 2)
01733       return CLI_SHOWUSAGE;
01734 
01735    AST_LIST_LOCK(&agents);
01736    AST_LIST_TRAVERSE(&agents, p, list) {
01737       ast_mutex_lock(&p->lock);
01738       if (p->pending) {
01739          if (p->group)
01740             ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01741          else
01742             ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01743       } else {
01744          if (!ast_strlen_zero(p->name))
01745             snprintf(username, sizeof(username), "(%s) ", p->name);
01746          else
01747             username[0] = '\0';
01748          if (p->chan) {
01749             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01750             if (p->owner && ast_bridged_channel(p->owner))
01751                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01752              else 
01753                strcpy(talkingto, " is idle");
01754             online_agents++;
01755          } else if (!ast_strlen_zero(p->loginchan)) {
01756             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01757                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01758             else 
01759                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01760             talkingto[0] = '\0';
01761             online_agents++;
01762             if (p->acknowledged)
01763                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01764          } else {
01765             strcpy(location, "not logged in");
01766             talkingto[0] = '\0';
01767             offline_agents++;
01768          }
01769          if (!ast_strlen_zero(p->moh))
01770             snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01771          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
01772             username, location, talkingto, music);
01773          count_agents++;
01774       }
01775       ast_mutex_unlock(&p->lock);
01776    }
01777    AST_LIST_UNLOCK(&agents);
01778    if ( !count_agents ) 
01779       ast_cli(a->fd, "No Agents are configured in %s\n",config);
01780    else 
01781       ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01782    ast_cli(a->fd, "\n");
01783                    
01784    return CLI_SUCCESS;
01785 }

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

Definition at line 1788 of file chan_agent.c.

References agent_pvt::acknowledged, 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::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.

01789 {
01790    struct agent_pvt *p;
01791    char username[AST_MAX_BUF];
01792    char location[AST_MAX_BUF] = "";
01793    char talkingto[AST_MAX_BUF] = "";
01794    char music[AST_MAX_BUF];
01795    int count_agents = 0;           /* Number of agents configured */
01796    int online_agents = 0;          /* Number of online agents */
01797    int agent_status = 0;           /* 0 means offline, 1 means online */
01798 
01799    switch (cmd) {
01800    case CLI_INIT:
01801       e->command = "agent show online";
01802       e->usage =
01803          "Usage: agent show online\n"
01804          "       Provides a list of all online agents.\n";
01805       return NULL;
01806    case CLI_GENERATE:
01807       return NULL;
01808    }
01809 
01810    if (a->argc != 3)
01811       return CLI_SHOWUSAGE;
01812 
01813    AST_LIST_LOCK(&agents);
01814    AST_LIST_TRAVERSE(&agents, p, list) {
01815       agent_status = 0;       /* reset it to offline */
01816       ast_mutex_lock(&p->lock);
01817       if (!ast_strlen_zero(p->name))
01818          snprintf(username, sizeof(username), "(%s) ", p->name);
01819       else
01820          username[0] = '\0';
01821       if (p->chan) {
01822          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01823          if (p->owner && ast_bridged_channel(p->owner)) 
01824             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01825          else 
01826             strcpy(talkingto, " is idle");
01827          agent_status = 1;
01828          online_agents++;
01829       } else if (!ast_strlen_zero(p->loginchan)) {
01830          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01831          talkingto[0] = '\0';
01832          agent_status = 1;
01833          online_agents++;
01834          if (p->acknowledged)
01835             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01836       }
01837       if (!ast_strlen_zero(p->moh))
01838          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01839       if (agent_status)
01840          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01841       count_agents++;
01842       ast_mutex_unlock(&p->lock);
01843    }
01844    AST_LIST_UNLOCK(&agents);
01845    if (!count_agents) 
01846       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01847    else
01848       ast_cli(a->fd, "%d agents online\n", online_agents);
01849    ast_cli(a->fd, "\n");
01850    return CLI_SUCCESS;
01851 }

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

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

Referenced by login_exec().

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

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

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

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

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

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

01684 {
01685    char *ret = NULL;
01686 
01687    if (pos == 2) {
01688       struct agent_pvt *p;
01689       char name[AST_MAX_AGENT];
01690       int which = 0, len = strlen(word);
01691 
01692       AST_LIST_LOCK(&agents);
01693       AST_LIST_TRAVERSE(&agents, p, list) {
01694          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01695          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01696             ret = ast_strdup(name);
01697             break;
01698          }
01699       }
01700       AST_LIST_UNLOCK(&agents);
01701    } else if (pos == 3 && state == 0) 
01702       return ast_strdup("soft");
01703    
01704    return ret;
01705 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2258 of file chan_agent.c.

References agent_pvt::agent, ast_db_del(), ast_db_put(), ast_debug, AST_LIST_TRAVERSE, ast_log(), ast_strlen_zero(), buf, agent_pvt::chan, LOG_WARNING, agent_pvt::logincallerid, and agent_pvt::loginchan.

Referenced by agent_hangup(), and agent_logoff_maintenance().

02259 {
02260    struct agent_pvt *cur_agent = NULL;
02261    char buf[256];
02262 
02263    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02264       if (cur_agent->chan)
02265          continue;
02266 
02267       if (!ast_strlen_zero(cur_agent->loginchan)) {
02268          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02269          if (ast_db_put(pa_family, cur_agent->agent, buf))
02270             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02271          else
02272             ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02273       } else {
02274          /* Delete -  no agent or there is an error */
02275          ast_db_del(pa_family, cur_agent->agent);
02276       }
02277    }
02278 }

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

Note:
This function expects the agent list to be locked

Definition at line 2381 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02382 {
02383    struct agent_pvt *cur;
02384 
02385    AST_LIST_TRAVERSE(&agents, cur, list) {
02386       if (!strcmp(cur->agent, agentid))
02387          break;   
02388    }
02389 
02390    return cur; 
02391 }

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

Definition at line 2393 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::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, parse(), agent_pvt::password, and status.

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

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

References action_agent_logoff(), action_agents(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register, ast_log(), ast_manager_register2(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_SUCCESS, ast_register_application, cli_agents, EVENT_FLAG_AGENT, LOG_ERROR, login_exec(), read_agent_config(), and reload_agents().

02474 {
02475    /* Make sure we can register our agent channel type */
02476    if (ast_channel_register(&agent_tech)) {
02477       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02478       return AST_MODULE_LOAD_FAILURE;
02479    }
02480    /* Read in the config */
02481    if (!read_agent_config(0))
02482       return AST_MODULE_LOAD_DECLINE;
02483    if (persistent_agents)
02484       reload_agents();
02485    /* Dialplan applications */
02486    ast_register_application(app, login_exec, synopsis, descrip);
02487    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02488 
02489    /* Manager commands */
02490    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02491    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02492 
02493    /* CLI Commands */
02494    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02495 
02496    /* Dialplan Functions */
02497    ast_custom_function_register(&agent_function);
02498 
02499    return AST_MODULE_LOAD_SUCCESS;
02500 }

static int login_exec ( struct ast_channel chan,
void *  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 1874 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::loginchan, 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().

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

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

Definition at line 1440 of file chan_agent.c.

01441 {
01442    int x = ffs(d);
01443 
01444    if (x)
01445       return x - 1;
01446 
01447    return 0;
01448 }

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 1086 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_FILEUNCHANGED, agent_pvt::dead, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

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

static int reload ( void   )  [static]

Definition at line 2502 of file chan_agent.c.

References read_agent_config(), and reload_agents().

02503 {
02504    if (!read_agent_config(1)) {
02505       if (persistent_agents)
02506          reload_agents();
02507    }
02508    return 0;
02509 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2283 of file chan_agent.c.

References agent_pvt::agent, ast_copy_string(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, AST_DEVICE_UNKNOWN, ast_devstate_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::lock, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, ast_db_entry::next, parse(), set_agentbycallerid(), and strsep().

Referenced by load_module(), and reload().

02284 {
02285    char *agent_num;
02286    struct ast_db_entry *db_tree;
02287    struct ast_db_entry *entry;
02288    struct agent_pvt *cur_agent;
02289    char agent_data[256];
02290    char *parse;
02291    char *agent_chan;
02292    char *agent_callerid;
02293 
02294    db_tree = ast_db_gettree(pa_family, NULL);
02295 
02296    AST_LIST_LOCK(&agents);
02297    for (entry = db_tree; entry; entry = entry->next) {
02298       agent_num = entry->key + strlen(pa_family) + 2;
02299       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02300          ast_mutex_lock(&cur_agent->lock);
02301          if (strcmp(agent_num, cur_agent->agent) == 0)
02302             break;
02303          ast_mutex_unlock(&cur_agent->lock);
02304       }
02305       if (!cur_agent) {
02306          ast_db_del(pa_family, agent_num);
02307          continue;
02308       } else
02309          ast_mutex_unlock(&cur_agent->lock);
02310       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02311          ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02312          parse = agent_data;
02313          agent_chan = strsep(&parse, ";");
02314          agent_callerid = strsep(&parse, ";");
02315          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02316          if (agent_callerid) {
02317             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02318             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02319          } else
02320             cur_agent->logincallerid[0] = '\0';
02321          if (cur_agent->loginstart == 0)
02322             time(&cur_agent->loginstart);
02323          ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 
02324       }
02325    }
02326    AST_LIST_UNLOCK(&agents);
02327    if (db_tree) {
02328       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02329       ast_db_freetree(db_tree);
02330    }
02331 }

static void set_agentbycallerid ( const char *  callerid,
const char *  agent 
) [static]

store/clear the global variable that stores agentid based on the callerid

Definition at line 753 of file chan_agent.c.

References AST_MAX_BUF, ast_strlen_zero(), buf, GETAGENTBYCALLERID, and pbx_builtin_setvar_helper().

Referenced by agent_logoff_maintenance(), and reload_agents().

00754 {
00755    char buf[AST_MAX_BUF];
00756 
00757    /* if there is no Caller ID, nothing to do */
00758    if (ast_strlen_zero(callerid))
00759       return;
00760 
00761    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00762    pbx_builtin_setvar_helper(NULL, buf, agent);
00763 }

static int unload_module ( void   )  [static]

Definition at line 2511 of file chan_agent.c.

References agent_function, agent_tech, 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.

Referenced by config_module(), and load_module().

02512 {
02513    struct agent_pvt *p;
02514    /* First, take us out of the channel loop */
02515    ast_channel_unregister(&agent_tech);
02516    /* Unregister dialplan functions */
02517    ast_custom_function_unregister(&agent_function);   
02518    /* Unregister CLI commands */
02519    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02520    /* Unregister dialplan applications */
02521    ast_unregister_application(app);
02522    ast_unregister_application(app3);
02523    /* Unregister manager command */
02524    ast_manager_unregister("Agents");
02525    ast_manager_unregister("AgentLogoff");
02526    /* Unregister channel */
02527    AST_LIST_LOCK(&agents);
02528    /* Hangup all interfaces if they have an owner */
02529    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02530       if (p->owner)
02531          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02532       ast_free(p);
02533    }
02534    AST_LIST_UNLOCK(&agents);
02535    return 0;
02536 }


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

char acceptdtmf = DEFAULT_ACCEPTDTMF [static]

Definition at line 138 of file chan_agent.c.

Referenced by play_record_review().

int ackcall [static]

Definition at line 134 of file chan_agent.c.

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

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

Definition at line 75 of file chan_agent.c.

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

Definition at line 76 of file chan_agent.c.

Definition at line 2542 of file chan_agent.c.

int autologoff [static]

Definition at line 132 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 137 of file chan_agent.c.

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

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

Referenced by load_module(), and unload_module().

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

const char descrip[] [static]

Definition at line 81 of file chan_agent.c.

const char descrip3[] [static]

Definition at line 90 of file chan_agent.c.

int endcall [static]

Definition at line 135 of file chan_agent.c.

char enddtmf = DEFAULT_ENDDTMF [static]

Definition at line 139 of file chan_agent.c.

ast_group_t group [static]

Definition at line 131 of file chan_agent.c.

const char mandescr_agent_logoff[] [static]

Initial value:

"Description: Sets an agent as no longer logged in.\n"
"Variables: (Names marked with * are required)\n"
"  *Agent: Agent ID of the agent to log off\n"
"  Soft: Set to 'true' to not hangup existing calls\n"

Definition at line 110 of file chan_agent.c.

const char mandescr_agents[] [static]

Initial value:

"Description: Will list info about all possible agents.\n"
"Variables: NONE\n"

Definition at line 106 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 141 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 136 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 122 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 125 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 144 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 145 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 146 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 148 of file chan_agent.c.

const char synopsis[] = "Call agent login" [static]

Definition at line 78 of file chan_agent.c.

const char synopsis3[] = "Record agent's outgoing call" [static]

Definition at line 79 of file chan_agent.c.

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

Definition at line 72 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 149 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 147 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 133 of file chan_agent.c.


Generated on Wed Oct 28 11:51:48 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6