Thu Jul 9 13:40:54 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"

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 GETAGENTBYCALLERID   "AGENTBYCALLERID"
#define PA_MAX_LEN   2048

Enumerations

enum  { AGENT_FLAG_ACKCALL = (1 << 0), AGENT_FLAG_AUTOLOGOFF = (1 << 1), AGENT_FLAG_WRAPUPTIME = (1 << 2) }

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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static int ackcall
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 const 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 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

Definition at line 119 of file chan_agent.c.

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

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

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

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 147 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 

Definition at line 149 of file chan_agent.c.

00149      {
00150    AGENT_FLAG_ACKCALL = (1 << 0),
00151    AGENT_FLAG_AUTOLOGOFF = (1 << 1),
00152    AGENT_FLAG_WRAPUPTIME = (1 << 2),
00153 };


Function Documentation

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

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

00399 {
00400    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00401    char filename[AST_MAX_BUF];
00402    int res = -1;
00403    if (!p)
00404       return -1;
00405    if (!ast->monitor) {
00406       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00407       /* substitute . for - */
00408       if ((pointer = strchr(filename, '.')))
00409          *pointer = '-';
00410       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00411       ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
00412       ast_monitor_setjoinfiles(ast, 1);
00413       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00414 #if 0
00415       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00416 #endif
00417       if (!ast->cdr)
00418          ast->cdr = ast_cdr_alloc();
00419       ast_cdr_setuserfield(ast, tmp2);
00420       res = 0;
00421    } else
00422       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00423    return res;
00424 }

static void __reg_module ( void   )  [static]

Definition at line 2500 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

Referenced by load_module().

01641 {
01642    const char *agent = astman_get_header(m, "Agent");
01643    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01644    int soft;
01645    int ret; /* return value of agent_logoff */
01646 
01647    if (ast_strlen_zero(agent)) {
01648       astman_send_error(s, m, "No agent specified");
01649       return 0;
01650    }
01651 
01652    soft = ast_true(soft_s) ? 1 : 0;
01653    ret = agent_logoff(agent, soft);
01654    if (ret == 0)
01655       astman_send_ack(s, m, "Agent logged out");
01656    else
01657       astman_send_error(s, m, "No such agent");
01658 
01659    return 0;
01660 }

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 1437 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, s, S_OR, and status.

Referenced by load_module().

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

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

Adds an agent to the global list of agents.

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

Definition at line 275 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_WRAPUPTIME, 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::lastdisc, agent_pvt::list, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 918 of file chan_agent.c.

References agent_pvt::app_sleep_cond, AST_FRAME_DTMF, ast_frfree, ast_mutex_lock(), ast_mutex_unlock(), ast_read(), ast_waitfor(), agent_pvt::chan, f, and agent_pvt::lock.

Referenced by login_exec().

00919 {
00920    struct agent_pvt *p;
00921    int res=0;
00922    int to = 1000;
00923    struct ast_frame *f;
00924 
00925    /* Wait a second and look for something */
00926 
00927    p = (struct agent_pvt *) data;
00928    if (!p->chan) 
00929       return -1;
00930 
00931    for(;;) {
00932       to = ast_waitfor(p->chan, to);
00933       if (to < 0) 
00934          return -1;
00935       if (!to) 
00936          return 0;
00937       f = ast_read(p->chan);
00938       if (!f) 
00939          return -1;
00940       if (f->frametype == AST_FRAME_DTMF)
00941          res = f->subclass;
00942       else
00943          res = 0;
00944       ast_frfree(f);
00945       ast_mutex_lock(&p->lock);
00946       if (!p->app_sleep_cond) {
00947          ast_mutex_unlock(&p->lock);
00948          return 0;
00949       } else if (res == '#') {
00950          ast_mutex_unlock(&p->lock);
00951          return 1;
00952       }
00953       ast_mutex_unlock(&p->lock);
00954       res = 0;
00955    }
00956    return res;
00957 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 392 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00393 {
00394    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00395    return -1;
00396 }

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

Definition at line 959 of file chan_agent.c.

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

00960 {
00961    struct agent_pvt *p = bridge->tech_pvt;
00962    struct ast_channel *ret = NULL;
00963 
00964    if (p) {
00965       if (chan == p->chan)
00966          ret = bridge->_bridge;
00967       else if (chan == bridge->_bridge)
00968          ret = p->chan;
00969    }
00970 
00971    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
00972    return ret;
00973 }

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

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

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

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

00371 {
00372    struct ast_channel *chan = p->owner;
00373    p->owner = NULL;
00374    chan->tech_pvt = NULL;
00375    p->app_sleep_cond = 1;
00376    /* Release ownership of the agent to other threads (presumably running the login app). */
00377    p->app_lock_flag = 0;
00378    ast_cond_signal(&p->app_complete_cond);
00379    if (chan)
00380       ast_channel_free(chan);
00381    if (p->dead) {
00382       ast_mutex_destroy(&p->lock);
00383       ast_mutex_destroy(&p->app_lock);
00384       ast_cond_destroy(&p->app_complete_cond);
00385       ast_free(p);
00386         }
00387    return 0;
00388 }

static int agent_cont_sleep ( void *  data  )  [static]

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

00898 {
00899    struct agent_pvt *p;
00900    int res;
00901 
00902    p = (struct agent_pvt *)data;
00903 
00904    ast_mutex_lock(&p->lock);
00905    res = p->app_sleep_cond;
00906    if (p->lastdisc.tv_sec) {
00907       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00908          res = 1;
00909    }
00910    ast_mutex_unlock(&p->lock);
00911 
00912    if (!res)
00913       ast_debug(5, "agent_cont_sleep() returning %d\n", res );
00914 
00915    return res;
00916 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2292 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

02293 {
02294    struct agent_pvt *p;
02295    char *s;
02296    ast_group_t groupmatch;
02297    int groupoff;
02298    int res = AST_DEVICE_INVALID;
02299    
02300    s = data;
02301    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
02302       groupmatch = (1 << groupoff);
02303    else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02304       groupmatch = (1 << groupoff);
02305    } else 
02306       groupmatch = 0;
02307 
02308    /* Check actual logged in agents first */
02309    AST_LIST_LOCK(&agents);
02310    AST_LIST_TRAVERSE(&agents, p, list) {
02311       ast_mutex_lock(&p->lock);
02312       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02313          if (p->owner) {
02314             if (res != AST_DEVICE_INUSE)
02315                res = AST_DEVICE_BUSY;
02316          } else {
02317             if (res == AST_DEVICE_BUSY)
02318                res = AST_DEVICE_INUSE;
02319             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02320                if (res == AST_DEVICE_INVALID)
02321                   res = AST_DEVICE_UNKNOWN;
02322             } else if (res == AST_DEVICE_INVALID)  
02323                res = AST_DEVICE_UNAVAILABLE;
02324          }
02325          if (!strcmp(data, p->agent)) {
02326             ast_mutex_unlock(&p->lock);
02327             break;
02328          }
02329       }
02330       ast_mutex_unlock(&p->lock);
02331    }
02332    AST_LIST_UNLOCK(&agents);
02333    return res;
02334 }

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

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

00639 {
00640    struct agent_pvt *p = ast->tech_pvt;
00641    ast_mutex_lock(&p->lock);
00642    if (p->chan) {
00643       ast_senddigit_begin(p->chan, digit);
00644    }
00645    ast_mutex_unlock(&p->lock);
00646    return 0;
00647 }

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

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

00650 {
00651    struct agent_pvt *p = ast->tech_pvt;
00652    ast_mutex_lock(&p->lock);
00653    if (p->chan) {
00654       ast_senddigit_end(p->chan, digit, duration);
00655    }
00656    ast_mutex_unlock(&p->lock);
00657    return 0;
00658 }

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

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

00606 {
00607    struct agent_pvt *p = newchan->tech_pvt;
00608    ast_mutex_lock(&p->lock);
00609    if (p->owner != oldchan) {
00610       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00611       ast_mutex_unlock(&p->lock);
00612       return -1;
00613    }
00614    p->owner = newchan;
00615    ast_mutex_unlock(&p->lock);
00616    return 0;
00617 }

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

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

Definition at line 750 of file chan_agent.c.

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

00751 {
00752    struct agent_pvt *p = NULL;
00753    struct ast_channel *base = chan;
00754 
00755    /* chan is locked by the calling function */
00756    if (!chan || !chan->tech_pvt) {
00757       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);
00758       return NULL;
00759    }
00760    p = chan->tech_pvt;
00761    if (p->chan) 
00762       base = p->chan;
00763    return base;
00764 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 783 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_state_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::list, 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.

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

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

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

00620 {
00621    struct agent_pvt *p = ast->tech_pvt;
00622    int res = -1;
00623    ast_mutex_lock(&p->lock);
00624    if (p->chan && !ast_check_hangup(p->chan)) {
00625       while (ast_channel_trylock(p->chan)) {
00626          ast_channel_unlock(ast);
00627          usleep(1);
00628          ast_channel_lock(ast);
00629       }
00630       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00631       ast_channel_unlock(p->chan);
00632    } else
00633       res = 0;
00634    ast_mutex_unlock(&p->lock);
00635    return res;
00636 }

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

Definition at line 1556 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.

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

01557 {
01558    struct agent_pvt *p;
01559    long logintime;
01560    int ret = -1; /* Return -1 if no agent if found */
01561 
01562    AST_LIST_LOCK(&agents);
01563    AST_LIST_TRAVERSE(&agents, p, list) {
01564       if (!strcasecmp(p->agent, agent)) {
01565          ret = 0;
01566          if (p->owner || p->chan) {
01567             if (!soft) {
01568                ast_mutex_lock(&p->lock);
01569 
01570                while (p->owner && ast_channel_trylock(p->owner)) {
01571                   DEADLOCK_AVOIDANCE(&p->lock);
01572                }
01573                if (p->owner) {
01574                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01575                   ast_channel_unlock(p->owner);
01576                }
01577 
01578                while (p->chan && ast_channel_trylock(p->chan)) {
01579                   DEADLOCK_AVOIDANCE(&p->lock);
01580                }
01581                if (p->chan) {
01582                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01583                   ast_channel_unlock(p->chan);
01584                }
01585 
01586                ast_mutex_unlock(&p->lock);
01587             } else
01588                p->deferlogoff = 1;
01589          } else {
01590             logintime = time(NULL) - p->loginstart;
01591             p->loginstart = 0;
01592             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01593          }
01594          break;
01595       }
01596    }
01597    AST_LIST_UNLOCK(&agents);
01598 
01599    return ret;
01600 }

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

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

01603 {
01604    int ret;
01605    char *agent;
01606 
01607    switch (cmd) {
01608    case CLI_INIT:
01609       e->command = "agent logoff";
01610       e->usage =
01611          "Usage: agent logoff <channel> [soft]\n"
01612          "       Sets an agent as no longer logged in.\n"
01613          "       If 'soft' is specified, do not hangup existing calls.\n";
01614       return NULL;
01615    case CLI_GENERATE:
01616       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01617    }
01618 
01619    if (a->argc < 3 || a->argc > 4)
01620       return CLI_SHOWUSAGE;
01621    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01622       return CLI_SHOWUSAGE;
01623 
01624    agent = a->argv[2] + 6;
01625    ret = agent_logoff(agent, a->argc == 4);
01626    if (ret == 0)
01627       ast_cli(a->fd, "Logging out %s\n", agent);
01628 
01629    return CLI_SUCCESS;
01630 }

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

Definition at line 1517 of file chan_agent.c.

References agent_pvt::agent, ast_device_state_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().

01518 {
01519    char *tmp = NULL;
01520    char agent[AST_MAX_AGENT];
01521 
01522    if (!ast_strlen_zero(logcommand))
01523       tmp = logcommand;
01524    else
01525       tmp = ast_strdupa("");
01526 
01527    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01528 
01529    if (!ast_strlen_zero(uniqueid)) {
01530       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01531             "Agent: %s\r\n"
01532             "Reason: %s\r\n"
01533             "Loginchan: %s\r\n"
01534             "Logintime: %ld\r\n"
01535             "Uniqueid: %s\r\n", 
01536             p->agent, tmp, loginchan, logintime, uniqueid);
01537    } else {
01538       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01539             "Agent: %s\r\n"
01540             "Reason: %s\r\n"
01541             "Loginchan: %s\r\n"
01542             "Logintime: %ld\r\n",
01543             p->agent, tmp, loginchan, logintime);
01544    }
01545 
01546    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01547    set_agentbycallerid(p->logincallerid, NULL);
01548    p->loginchan[0] ='\0';
01549    p->logincallerid[0] = '\0';
01550    ast_device_state_changed("Agent/%s", p->agent);
01551    if (persistent_agents)
01552       dump_agents();
01553 
01554 }

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

Create new agent channel.

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

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

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

Definition at line 431 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, 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_state_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, f, ast_channel::fdno, 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_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, and agent_pvt::wrapuptime.

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

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

Part of the Asterisk PBX interface.

Definition at line 1324 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::list, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

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

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

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

00559 {
00560    struct agent_pvt *p = ast->tech_pvt;
00561    int res = -1;
00562    ast_mutex_lock(&p->lock);
00563    if (p->chan) 
00564       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00565    ast_mutex_unlock(&p->lock);
00566    return res;
00567 }

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

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

00570 {
00571    struct agent_pvt *p = ast->tech_pvt;
00572    int res = -1;
00573    ast_mutex_lock(&p->lock);
00574    if (p->chan) 
00575       res = ast_sendtext(p->chan, text);
00576    ast_mutex_unlock(&p->lock);
00577    return res;
00578 }

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

Definition at line 766 of file chan_agent.c.

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

00767 {
00768    struct agent_pvt *p = NULL;
00769    
00770    if (!chan || !base) {
00771       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00772       return -1;
00773    }
00774    p = chan->tech_pvt;
00775    if (!p) {
00776       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00777       return -1;
00778    }
00779    p->chan = base;
00780    return 0;
00781 }

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

Definition at line 426 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00427 {
00428    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00429 }

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

Definition at line 580 of file chan_agent.c.

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

00581 {
00582    struct agent_pvt *p = ast->tech_pvt;
00583    int res = -1;
00584    CHECK_FORMATS(ast, p);
00585    ast_mutex_lock(&p->lock);
00586    if (!p->chan) 
00587       res = 0;
00588    else {
00589       if ((f->frametype != AST_FRAME_VOICE) ||
00590           (f->frametype != AST_FRAME_VIDEO) ||
00591           (f->subclass == p->chan->writeformat)) {
00592          res = ast_write(p->chan, f);
00593       } else {
00594          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00595             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00596             ast->name, p->chan->name);
00597          res = 0;
00598       }
00599    }
00600    CLEANUP(ast, p);
00601    ast_mutex_unlock(&p->lock);
00602    return res;
00603 }

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 2163 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, agent_pvt::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, GETAGENTBYCALLERID, agent_pvt::list, LOG_WARNING, and pbx_builtin_getvar_helper().

Referenced by load_module().

02164 {
02165    int exitifnoagentid = 0;
02166    int nowarnings = 0;
02167    int changeoutgoing = 0;
02168    int res = 0;
02169    char agent[AST_MAX_AGENT];
02170 
02171    if (data) {
02172       if (strchr(data, 'd'))
02173          exitifnoagentid = 1;
02174       if (strchr(data, 'n'))
02175          nowarnings = 1;
02176       if (strchr(data, 'c'))
02177          changeoutgoing = 1;
02178    }
02179    if (chan->cid.cid_num) {
02180       const char *tmp;
02181       char agentvar[AST_MAX_BUF];
02182       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02183       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02184          struct agent_pvt *p;
02185          ast_copy_string(agent, tmp, sizeof(agent));
02186          AST_LIST_LOCK(&agents);
02187          AST_LIST_TRAVERSE(&agents, p, list) {
02188             if (!strcasecmp(p->agent, tmp)) {
02189                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02190                __agent_start_monitoring(chan, p, 1);
02191                break;
02192             }
02193          }
02194          AST_LIST_UNLOCK(&agents);
02195          
02196       } else {
02197          res = -1;
02198          if (!nowarnings)
02199             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);
02200       }
02201    } else {
02202       res = -1;
02203       if (!nowarnings)
02204          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");
02205    }
02206    if (res) {
02207       if (exitifnoagentid)
02208          return res;
02209    }
02210    return 0;
02211 }

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 1689 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::list, 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.

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

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

Definition at line 1767 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::list, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, ast_channel::name, agent_pvt::name, agent_pvt::owner, and ast_cli_entry::usage.

01768 {
01769    struct agent_pvt *p;
01770    char username[AST_MAX_BUF];
01771    char location[AST_MAX_BUF] = "";
01772    char talkingto[AST_MAX_BUF] = "";
01773    char moh[AST_MAX_BUF];
01774    int count_agents = 0;           /* Number of agents configured */
01775    int online_agents = 0;          /* Number of online agents */
01776    int agent_status = 0;           /* 0 means offline, 1 means online */
01777 
01778    switch (cmd) {
01779    case CLI_INIT:
01780       e->command = "agent show online";
01781       e->usage =
01782          "Usage: agent show online\n"
01783          "       Provides a list of all online agents.\n";
01784       return NULL;
01785    case CLI_GENERATE:
01786       return NULL;
01787    }
01788 
01789    if (a->argc != 3)
01790       return CLI_SHOWUSAGE;
01791 
01792    AST_LIST_LOCK(&agents);
01793    AST_LIST_TRAVERSE(&agents, p, list) {
01794       agent_status = 0;       /* reset it to offline */
01795       ast_mutex_lock(&p->lock);
01796       if (!ast_strlen_zero(p->name))
01797          snprintf(username, sizeof(username), "(%s) ", p->name);
01798       else
01799          username[0] = '\0';
01800       if (p->chan) {
01801          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01802          if (p->owner && ast_bridged_channel(p->owner)) 
01803             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01804          else 
01805             strcpy(talkingto, " is idle");
01806          agent_status = 1;
01807          online_agents++;
01808       } else if (!ast_strlen_zero(p->loginchan)) {
01809          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01810          talkingto[0] = '\0';
01811          agent_status = 1;
01812          online_agents++;
01813          if (p->acknowledged)
01814             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01815       }
01816       if (!ast_strlen_zero(p->moh))
01817          snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01818       if (agent_status)
01819          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01820       count_agents++;
01821       ast_mutex_unlock(&p->lock);
01822    }
01823    AST_LIST_UNLOCK(&agents);
01824    if (!count_agents) 
01825       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01826    else
01827       ast_cli(a->fd, "%d agents online\n", online_agents);
01828    ast_cli(a->fd, "\n");
01829    return CLI_SUCCESS;
01830 }

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

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

Referenced by login_exec().

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

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

Definition at line 1287 of file chan_agent.c.

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

Referenced by login_exec().

01288 {
01289    struct agent_pvt *p;
01290    int res=0;
01291 
01292    ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01293    if (needlock)
01294       AST_LIST_LOCK(&agents);
01295    AST_LIST_TRAVERSE(&agents, p, list) {
01296       if (p == newlyavailable) {
01297          continue;
01298       }
01299       ast_mutex_lock(&p->lock);
01300       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01301          ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01302          ast_mutex_unlock(&p->lock);
01303          break;
01304       }
01305       ast_mutex_unlock(&p->lock);
01306    }
01307    if (needlock)
01308       AST_LIST_UNLOCK(&agents);
01309    if (p) {
01310       ast_mutex_unlock(&newlyavailable->lock);
01311       ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01312       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01313       ast_debug(1, "Played beep, result '%d'\n", res);
01314       if (!res) {
01315          res = ast_waitstream(newlyavailable->chan, "");
01316          ast_debug(1, "Waited for stream, result '%d'\n", res);
01317       }
01318       ast_mutex_lock(&newlyavailable->lock);
01319    }
01320    return res;
01321 }

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

Definition at line 1662 of file chan_agent.c.

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

Referenced by agent_logoff_cmd().

01663 {
01664    char *ret = NULL;
01665 
01666    if (pos == 2) {
01667       struct agent_pvt *p;
01668       char name[AST_MAX_AGENT];
01669       int which = 0, len = strlen(word);
01670 
01671       AST_LIST_LOCK(&agents);
01672       AST_LIST_TRAVERSE(&agents, p, list) {
01673          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01674          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01675             ret = ast_strdup(name);
01676             break;
01677          }
01678       }
01679       AST_LIST_UNLOCK(&agents);
01680    } else if (pos == 3 && state == 0) 
01681       return ast_strdup("soft");
01682    
01683    return ret;
01684 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2216 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, agent_pvt::list, LOG_WARNING, agent_pvt::logincallerid, and agent_pvt::loginchan.

Referenced by agent_hangup(), and agent_logoff_maintenance().

02217 {
02218    struct agent_pvt *cur_agent = NULL;
02219    char buf[256];
02220 
02221    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02222       if (cur_agent->chan)
02223          continue;
02224 
02225       if (!ast_strlen_zero(cur_agent->loginchan)) {
02226          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02227          if (ast_db_put(pa_family, cur_agent->agent, buf))
02228             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02229          else
02230             ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02231       } else {
02232          /* Delete -  no agent or there is an error */
02233          ast_db_del(pa_family, cur_agent->agent);
02234       }
02235    }
02236 }

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

Note:
This function expects the agent list to be locked

Definition at line 2339 of file chan_agent.c.

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

Referenced by function_agent().

02340 {
02341    struct agent_pvt *cur;
02342 
02343    AST_LIST_TRAVERSE(&agents, cur, list) {
02344       if (!strcmp(cur->agent, agentid))
02345          break;   
02346    }
02347 
02348    return cur; 
02349 }

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

Definition at line 2351 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(), find_agent(), LOG_WARNING, parse(), and status.

02352 {
02353    char *parse;    
02354    AST_DECLARE_APP_ARGS(args,
02355       AST_APP_ARG(agentid);
02356       AST_APP_ARG(item);
02357    );
02358    char *tmp;
02359    struct agent_pvt *agent;
02360 
02361    buf[0] = '\0';
02362 
02363    if (ast_strlen_zero(data)) {
02364       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02365       return -1;
02366    }
02367 
02368    parse = ast_strdupa(data);
02369 
02370    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02371    if (!args.item)
02372       args.item = "status";
02373 
02374    AST_LIST_LOCK(&agents);
02375 
02376    if (!(agent = find_agent(args.agentid))) {
02377       AST_LIST_UNLOCK(&agents);
02378       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02379       return -1;
02380    }
02381 
02382    if (!strcasecmp(args.item, "status")) {
02383       char *status = "LOGGEDOUT";
02384       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02385          status = "LOGGEDIN"; 
02386       ast_copy_string(buf, status, len);
02387    } else if (!strcasecmp(args.item, "password")) 
02388       ast_copy_string(buf, agent->password, len);
02389    else if (!strcasecmp(args.item, "name"))
02390       ast_copy_string(buf, agent->name, len);
02391    else if (!strcasecmp(args.item, "mohclass"))
02392       ast_copy_string(buf, agent->moh, len);
02393    else if (!strcasecmp(args.item, "channel")) {
02394       if (agent->chan) {
02395          ast_copy_string(buf, agent->chan->name, len);
02396          tmp = strrchr(buf, '-');
02397          if (tmp)
02398             *tmp = '\0';
02399       } 
02400    } else if (!strcasecmp(args.item, "exten"))
02401       ast_copy_string(buf, agent->loginchan, len); 
02402 
02403    AST_LIST_UNLOCK(&agents);
02404 
02405    return 0;
02406 }

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

02432 {
02433    /* Make sure we can register our agent channel type */
02434    if (ast_channel_register(&agent_tech)) {
02435       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02436       return AST_MODULE_LOAD_FAILURE;
02437    }
02438    /* Read in the config */
02439    if (!read_agent_config(0))
02440       return AST_MODULE_LOAD_DECLINE;
02441    if (persistent_agents)
02442       reload_agents();
02443    /* Dialplan applications */
02444    ast_register_application(app, login_exec, synopsis, descrip);
02445    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02446 
02447    /* Manager commands */
02448    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02449    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02450 
02451    /* CLI Commands */
02452    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02453 
02454    /* Dialplan Functions */
02455    ast_custom_function_register(&agent_function);
02456 
02457    return AST_MODULE_LOAD_SUCCESS;
02458 }

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

References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, 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_state_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, agent_pvt::chan, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::list, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::name, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, update_cdr, and agent_pvt::wrapuptime.

Referenced by load_module().

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

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

Definition at line 1419 of file chan_agent.c.

01420 {
01421    int x = ffs(d);
01422 
01423    if (x)
01424       return x - 1;
01425 
01426    return 0;
01427 }

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 1070 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::list, 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().

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

static int reload ( void   )  [static]

Definition at line 2460 of file chan_agent.c.

References read_agent_config(), and reload_agents().

02461 {
02462    if (!read_agent_config(1)) {
02463       if (persistent_agents)
02464          reload_agents();
02465    }
02466    return 0;
02467 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2241 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_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::list, 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().

02242 {
02243    char *agent_num;
02244    struct ast_db_entry *db_tree;
02245    struct ast_db_entry *entry;
02246    struct agent_pvt *cur_agent;
02247    char agent_data[256];
02248    char *parse;
02249    char *agent_chan;
02250    char *agent_callerid;
02251 
02252    db_tree = ast_db_gettree(pa_family, NULL);
02253 
02254    AST_LIST_LOCK(&agents);
02255    for (entry = db_tree; entry; entry = entry->next) {
02256       agent_num = entry->key + strlen(pa_family) + 2;
02257       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02258          ast_mutex_lock(&cur_agent->lock);
02259          if (strcmp(agent_num, cur_agent->agent) == 0)
02260             break;
02261          ast_mutex_unlock(&cur_agent->lock);
02262       }
02263       if (!cur_agent) {
02264          ast_db_del(pa_family, agent_num);
02265          continue;
02266       } else
02267          ast_mutex_unlock(&cur_agent->lock);
02268       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02269          ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02270          parse = agent_data;
02271          agent_chan = strsep(&parse, ";");
02272          agent_callerid = strsep(&parse, ";");
02273          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02274          if (agent_callerid) {
02275             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02276             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02277          } else
02278             cur_agent->logincallerid[0] = '\0';
02279          if (cur_agent->loginstart == 0)
02280             time(&cur_agent->loginstart);
02281          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02282       }
02283    }
02284    AST_LIST_UNLOCK(&agents);
02285    if (db_tree) {
02286       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02287       ast_db_freetree(db_tree);
02288    }
02289 }

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

00738 {
00739    char buf[AST_MAX_BUF];
00740 
00741    /* if there is no Caller ID, nothing to do */
00742    if (ast_strlen_zero(callerid))
00743       return;
00744 
00745    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00746    pbx_builtin_setvar_helper(NULL, buf, agent);
00747 }

static int unload_module ( void   )  [static]

Definition at line 2469 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, agent_pvt::list, and agent_pvt::owner.

Referenced by config_module(), and load_module().

02470 {
02471    struct agent_pvt *p;
02472    /* First, take us out of the channel loop */
02473    ast_channel_unregister(&agent_tech);
02474    /* Unregister dialplan functions */
02475    ast_custom_function_unregister(&agent_function);   
02476    /* Unregister CLI commands */
02477    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02478    /* Unregister dialplan applications */
02479    ast_unregister_application(app);
02480    ast_unregister_application(app3);
02481    /* Unregister manager command */
02482    ast_manager_unregister("Agents");
02483    ast_manager_unregister("AgentLogoff");
02484    /* Unregister channel */
02485    AST_LIST_LOCK(&agents);
02486    /* Hangup all interfaces if they have an owner */
02487    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02488       if (p->owner)
02489          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02490       ast_free(p);
02491    }
02492    AST_LIST_UNLOCK(&agents);
02493    return 0;
02494 }


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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 2500 of file chan_agent.c.

int ackcall [static]

Definition at line 131 of file chan_agent.c.

struct ast_custom_function agent_function

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2500 of file chan_agent.c.

int autologoff [static]

Definition at line 129 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 134 of file chan_agent.c.

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

Definition at line 145 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]

Initial value:

 {
   { .handler =  agents_show , .summary =  "Show status of agents" ,__VA_ARGS__ },
   { .handler =  agents_show_online , .summary =  "Show all online agents" ,__VA_ARGS__ },
   { .handler =  agent_logoff_cmd , .summary =  "Sets an agent offline" ,__VA_ARGS__ },
}

Definition at line 1837 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

Definition at line 73 of file chan_agent.c.

Referenced by add_features_datastores(), app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_insert(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_retrieve(), builtin_atxfer(), category_get(), dial_exec_full(), do_reload(), do_timelimit(), feature_interpret_helper(), get_insecure_variable_from_config(), load_config(), load_module(), load_odbc_config(), misdn_cfg_init(), odbc_load_module(), park_exec(), parse_config(), pbx_load_module(), prepare_cb(), read_config_maps(), reload(), reload_config(), set_bridge_features_on_config(), and set_config_flags().

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

ast_group_t group [static]

Definition at line 128 of file chan_agent.c.

Referenced by group_destroy().

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

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

Definition at line 116 of file chan_agent.c.

Referenced by dial_exec_full(), get_mohbyname(), moh_generate(), moh_register(), moh_release(), mohalloc(), and monmp3thread().

int multiplelogin = 1 [static]

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

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 140 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 141 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

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

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 142 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 130 of file chan_agent.c.


Generated on Thu Jul 9 13:40:54 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7