Wed Aug 18 22:34:05 2010

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

Enumerations

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

Functions

static int __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static void __reg_module (void)
static void __unreg_module (void)
static int action_agent_logoff (struct mansession *s, const struct message *m)
static int action_agents (struct mansession *s, const struct message *m)
static struct agent_pvtadd_agent (const char *agent, int pending)
static int agent_ack_sleep (void *data)
static int agent_answer (struct ast_channel *ast)
static struct ast_channelagent_bridgedchannel (struct ast_channel *chan, struct ast_channel *bridge)
static int agent_call (struct ast_channel *ast, char *dest, int timeout)
static int agent_cleanup (struct agent_pvt *p)
static int agent_cont_sleep (void *data)
static int agent_devicestate (void *data)
 Part of PBX channel interface.
static int agent_digit_begin (struct ast_channel *ast, char digit)
static int agent_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
static int agent_fixup (struct ast_channel *oldchan, struct ast_channel *newchan)
static struct ast_channelagent_get_base_channel (struct ast_channel *chan)
 return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
static int agent_hangup (struct ast_channel *ast)
static int agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
static int agent_logoff (const char *agent, int soft)
static char * agent_logoff_cmd (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void agent_logoff_maintenance (struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
static struct ast_channelagent_new (struct agent_pvt *p, int state)
 Create new agent channel.
static struct ast_frameagent_read (struct ast_channel *ast)
static struct ast_channelagent_request (const char *type, int format, void *data, int *cause)
 Part of the Asterisk PBX interface.
static int agent_sendhtml (struct ast_channel *ast, int subclass, const char *data, int datalen)
static int agent_sendtext (struct ast_channel *ast, const char *text)
static int agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, void *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static char * agents_show (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * agents_show_online (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int check_availability (struct agent_pvt *newlyavailable, int needlock)
static int check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state)
static void dump_agents (void)
 Dump AgentCallbackLogin agents to the ASTdb database for persistence.
static struct agent_pvtfind_agent (char *agentid)
static int function_agent (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int load_module (void)
 Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.
static int login_exec (struct ast_channel *chan, void *data)
 Log in agent application.
static force_inline int powerof (unsigned int d)
static int read_agent_config (int reload)
static int reload (void)
static void reload_agents (void)
 Reload the persistent agents from astdb.
static void set_agentbycallerid (const char *callerid, const char *agent)
 store/clear the global variable that stores agentid based on the callerid
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, .reload = reload, }
static char acceptdtmf = DEFAULT_ACCEPTDTMF
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 struct ast_module_infoast_module_info = &__mod_info
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static const char config [] = "agents.conf"
static const char descrip []
static const char descrip3 []
static int endcall
static char enddtmf = DEFAULT_ENDDTMF
static ast_group_t group
static const char mandescr_agent_logoff []
static const char mandescr_agents []
static int maxlogintries = 3
static char moh [80] = "default"
static int multiplelogin = 1
static const char pa_family [] = "Agents"
static int persistent_agents = 0
static int recordagentcalls = 0
static char recordformat [AST_MAX_BUF] = ""
static char recordformatext [AST_MAX_BUF] = ""
static char savecallsin [AST_MAX_BUF] = ""
static const char synopsis [] = "Call agent login"
static const char synopsis3 [] = "Record agent's outgoing call"
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int wrapuptime


Detailed Description

Implementation of Agents (proxy channel).

Author:
Mark Spencer <markster@digium.com>
This file is the implementation of Agents modules. It is a dynamic module that is loaded by Asterisk.
See also

Definition in file chan_agent.c.


Define Documentation

#define AST_MAX_AGENT   80

Agent ID or Password max length

Definition at line 118 of file chan_agent.c.

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

#define AST_MAX_BUF   256

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

Referenced by agent_read(), and agent_write().

#define CLEANUP ( ast,
 ) 

Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.

Definition at line 218 of file chan_agent.c.

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

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 128 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 129 of file chan_agent.c.

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 152 of file chan_agent.c.

Referenced by agentmonitoroutgoing_exec(), and set_agentbycallerid().

#define PA_MAX_LEN   2048

The maximum length of each persistent member agent database entry

Definition at line 123 of file chan_agent.c.


Enumeration Type Documentation

anonymous enum

Enumerator:
AGENT_FLAG_ACKCALL 
AGENT_FLAG_AUTOLOGOFF 
AGENT_FLAG_WRAPUPTIME 
AGENT_FLAG_ACCEPTDTMF 
AGENT_FLAG_ENDDTMF 

Definition at line 154 of file chan_agent.c.

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


Function Documentation

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

Definition at line 413 of file chan_agent.c.

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

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

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

static void __reg_module ( void   )  [static]

Definition at line 2563 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

01683 {
01684    const char *agent = astman_get_header(m, "Agent");
01685    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01686    int soft;
01687    int ret; /* return value of agent_logoff */
01688 
01689    if (ast_strlen_zero(agent)) {
01690       astman_send_error(s, m, "No agent specified");
01691       return 0;
01692    }
01693 
01694    soft = ast_true(soft_s) ? 1 : 0;
01695    ret = agent_logoff(agent, soft);
01696    if (ret == 0)
01697       astman_send_ack(s, m, "Agent logged out");
01698    else
01699       astman_send_error(s, m, "No such agent");
01700 
01701    return 0;
01702 }

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

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

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

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

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 955 of file chan_agent.c.

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

Referenced by login_exec().

00956 {
00957    struct agent_pvt *p;
00958    int res=0;
00959    int to = 1000;
00960    struct ast_frame *f;
00961 
00962    /* Wait a second and look for something */
00963 
00964    p = (struct agent_pvt *) data;
00965    if (!p->chan) 
00966       return -1;
00967 
00968    for(;;) {
00969       to = ast_waitfor(p->chan, to);
00970       if (to < 0) 
00971          return -1;
00972       if (!to) 
00973          return 0;
00974       f = ast_read(p->chan);
00975       if (!f) 
00976          return -1;
00977       if (f->frametype == AST_FRAME_DTMF)
00978          res = f->subclass;
00979       else
00980          res = 0;
00981       ast_frfree(f);
00982       ast_mutex_lock(&p->lock);
00983       if (!p->app_sleep_cond) {
00984          ast_mutex_unlock(&p->lock);
00985          return 0;
00986       } else if (res == p->acceptdtmf) {
00987          ast_mutex_unlock(&p->lock);
00988          return 1;
00989       }
00990       ast_mutex_unlock(&p->lock);
00991       res = 0;
00992    }
00993    return res;
00994 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 407 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

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

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

Definition at line 996 of file chan_agent.c.

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

00997 {
00998    struct agent_pvt *p = bridge->tech_pvt;
00999    struct ast_channel *ret = NULL;
01000 
01001    if (p) {
01002       if (chan == p->chan)
01003          ret = bridge->_bridge;
01004       else if (chan == bridge->_bridge)
01005          ret = p->chan;
01006    }
01007 
01008    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01009    return ret;
01010 }

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

Definition at line 697 of file chan_agent.c.

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

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

static int agent_cleanup ( struct agent_pvt p  )  [static]

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

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

Definition at line 385 of file chan_agent.c.

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

Referenced by check_availability().

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

static int agent_cont_sleep ( void *  data  )  [static]

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

00935 {
00936    struct agent_pvt *p;
00937    int res;
00938 
00939    p = (struct agent_pvt *)data;
00940 
00941    ast_mutex_lock(&p->lock);
00942    res = p->app_sleep_cond;
00943    if (p->lastdisc.tv_sec) {
00944       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00945          res = 1;
00946    }
00947    ast_mutex_unlock(&p->lock);
00948 
00949    if (!res)
00950       ast_debug(5, "agent_cont_sleep() returning %d\n", res );
00951 
00952    return res;
00953 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

02356 {
02357    struct agent_pvt *p;
02358    char *s;
02359    ast_group_t groupmatch;
02360    int groupoff;
02361    int res = AST_DEVICE_INVALID;
02362    
02363    s = data;
02364    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02365       groupmatch = (1 << groupoff);
02366    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02367       groupmatch = (1 << groupoff);
02368    } else 
02369       groupmatch = 0;
02370 
02371    /* Check actual logged in agents first */
02372    AST_LIST_LOCK(&agents);
02373    AST_LIST_TRAVERSE(&agents, p, list) {
02374       ast_mutex_lock(&p->lock);
02375       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02376          if (p->owner) {
02377             if (res != AST_DEVICE_INUSE)
02378                res = AST_DEVICE_BUSY;
02379          } else {
02380             if (res == AST_DEVICE_BUSY)
02381                res = AST_DEVICE_INUSE;
02382             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02383                if (res == AST_DEVICE_INVALID)
02384                   res = AST_DEVICE_UNKNOWN;
02385             } else if (res == AST_DEVICE_INVALID)  
02386                res = AST_DEVICE_UNAVAILABLE;
02387          }
02388          if (!strcmp(data, p->agent)) {
02389             ast_mutex_unlock(&p->lock);
02390             break;
02391          }
02392       }
02393       ast_mutex_unlock(&p->lock);
02394    }
02395    AST_LIST_UNLOCK(&agents);
02396    return res;
02397 }

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

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

00676 {
00677    struct agent_pvt *p = ast->tech_pvt;
00678    ast_mutex_lock(&p->lock);
00679    if (p->chan) {
00680       ast_senddigit_begin(p->chan, digit);
00681    }
00682    ast_mutex_unlock(&p->lock);
00683    return 0;
00684 }

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

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

00687 {
00688    struct agent_pvt *p = ast->tech_pvt;
00689    ast_mutex_lock(&p->lock);
00690    if (p->chan) {
00691       ast_senddigit_end(p->chan, digit, duration);
00692    }
00693    ast_mutex_unlock(&p->lock);
00694    return 0;
00695 }

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

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

00643 {
00644    struct agent_pvt *p = newchan->tech_pvt;
00645    ast_mutex_lock(&p->lock);
00646    if (p->owner != oldchan) {
00647       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00648       ast_mutex_unlock(&p->lock);
00649       return -1;
00650    }
00651    p->owner = newchan;
00652    ast_mutex_unlock(&p->lock);
00653    return 0;
00654 }

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

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

00788 {
00789    struct agent_pvt *p = NULL;
00790    struct ast_channel *base = chan;
00791 
00792    /* chan is locked by the calling function */
00793    if (!chan || !chan->tech_pvt) {
00794       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);
00795       return NULL;
00796    }
00797    p = chan->tech_pvt;
00798    if (p->chan) 
00799       base = p->chan;
00800    return base;
00801 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 820 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::abouttograb, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_signal(), AST_CONTROL_HOLD, ast_debug, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_hangup(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tv(), ast_tvadd(), ast_tvnow(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), agent_pvt::lastdisc, agent_pvt::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.

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

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

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

00657 {
00658    struct agent_pvt *p = ast->tech_pvt;
00659    int res = -1;
00660    ast_mutex_lock(&p->lock);
00661    if (p->chan && !ast_check_hangup(p->chan)) {
00662       while (ast_channel_trylock(p->chan)) {
00663          ast_channel_unlock(ast);
00664          usleep(1);
00665          ast_channel_lock(ast);
00666       }
00667       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00668       ast_channel_unlock(p->chan);
00669    } else
00670       res = 0;
00671    ast_mutex_unlock(&p->lock);
00672    return res;
00673 }

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

Definition at line 1598 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(), and agent_logoff_cmd().

01599 {
01600    struct agent_pvt *p;
01601    long logintime;
01602    int ret = -1; /* Return -1 if no agent if found */
01603 
01604    AST_LIST_LOCK(&agents);
01605    AST_LIST_TRAVERSE(&agents, p, list) {
01606       if (!strcasecmp(p->agent, agent)) {
01607          ret = 0;
01608          if (p->owner || p->chan) {
01609             if (!soft) {
01610                ast_mutex_lock(&p->lock);
01611 
01612                while (p->owner && ast_channel_trylock(p->owner)) {
01613                   DEADLOCK_AVOIDANCE(&p->lock);
01614                }
01615                if (p->owner) {
01616                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01617                   ast_channel_unlock(p->owner);
01618                }
01619 
01620                while (p->chan && ast_channel_trylock(p->chan)) {
01621                   DEADLOCK_AVOIDANCE(&p->lock);
01622                }
01623                if (p->chan) {
01624                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01625                   ast_channel_unlock(p->chan);
01626                }
01627 
01628                ast_mutex_unlock(&p->lock);
01629             } else
01630                p->deferlogoff = 1;
01631          } else {
01632             logintime = time(NULL) - p->loginstart;
01633             p->loginstart = 0;
01634             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01635          }
01636          break;
01637       }
01638    }
01639    AST_LIST_UNLOCK(&agents);
01640 
01641    return ret;
01642 }

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

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

01645 {
01646    int ret;
01647    char *agent;
01648 
01649    switch (cmd) {
01650    case CLI_INIT:
01651       e->command = "agent logoff";
01652       e->usage =
01653          "Usage: agent logoff <channel> [soft]\n"
01654          "       Sets an agent as no longer logged in.\n"
01655          "       If 'soft' is specified, do not hangup existing calls.\n";
01656       return NULL;
01657    case CLI_GENERATE:
01658       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01659    }
01660 
01661    if (a->argc < 3 || a->argc > 4)
01662       return CLI_SHOWUSAGE;
01663    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01664       return CLI_SHOWUSAGE;
01665 
01666    agent = a->argv[2] + 6;
01667    ret = agent_logoff(agent, a->argc == 4);
01668    if (ret == 0)
01669       ast_cli(a->fd, "Logging out %s\n", agent);
01670 
01671    return CLI_SUCCESS;
01672 }

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

Definition at line 1559 of file chan_agent.c.

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

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

01560 {
01561    char *tmp = NULL;
01562    char agent[AST_MAX_AGENT];
01563 
01564    if (!ast_strlen_zero(logcommand))
01565       tmp = logcommand;
01566    else
01567       tmp = ast_strdupa("");
01568 
01569    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01570 
01571    if (!ast_strlen_zero(uniqueid)) {
01572       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01573             "Agent: %s\r\n"
01574             "Reason: %s\r\n"
01575             "Loginchan: %s\r\n"
01576             "Logintime: %ld\r\n"
01577             "Uniqueid: %s\r\n", 
01578             p->agent, tmp, loginchan, logintime, uniqueid);
01579    } else {
01580       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01581             "Agent: %s\r\n"
01582             "Reason: %s\r\n"
01583             "Loginchan: %s\r\n"
01584             "Logintime: %ld\r\n",
01585             p->agent, tmp, loginchan, logintime);
01586    }
01587 
01588    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01589    set_agentbycallerid(p->logincallerid, NULL);
01590    p->loginchan[0] ='\0';
01591    p->logincallerid[0] = '\0';
01592    ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
01593    if (persistent_agents)
01594       dump_agents();
01595 
01596 }

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

Create new agent channel.

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

01014 {
01015    struct ast_channel *tmp;
01016    int alreadylocked;
01017 #if 0
01018    if (!p->chan) {
01019       ast_log(LOG_WARNING, "No channel? :(\n");
01020       return NULL;
01021    }
01022 #endif   
01023    if (p->pending)
01024       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);
01025    else
01026       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
01027    if (!tmp) {
01028       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01029       return NULL;
01030    }
01031 
01032    tmp->tech = &agent_tech;
01033    if (p->chan) {
01034       tmp->nativeformats = p->chan->nativeformats;
01035       tmp->writeformat = p->chan->writeformat;
01036       tmp->rawwriteformat = p->chan->writeformat;
01037       tmp->readformat = p->chan->readformat;
01038       tmp->rawreadformat = p->chan->readformat;
01039       ast_string_field_set(tmp, language, p->chan->language);
01040       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01041       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01042       /* XXX Is this really all we copy form the originating channel?? */
01043    } else {
01044       tmp->nativeformats = AST_FORMAT_SLINEAR;
01045       tmp->writeformat = AST_FORMAT_SLINEAR;
01046       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01047       tmp->readformat = AST_FORMAT_SLINEAR;
01048       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01049    }
01050    /* Safe, agentlock already held */
01051    tmp->tech_pvt = p;
01052    p->owner = tmp;
01053    tmp->priority = 1;
01054    /* Wake up and wait for other applications (by definition the login app)
01055     * to release this channel). Takes ownership of the agent channel
01056     * to this thread only.
01057     * For signalling the other thread, ast_queue_frame is used until we
01058     * can safely use signals for this purpose. The pselect() needs to be
01059     * implemented in the kernel for this.
01060     */
01061    p->app_sleep_cond = 0;
01062 
01063    alreadylocked = p->app_lock_flag;
01064    p->app_lock_flag = 1;
01065 
01066    if(ast_strlen_zero(p->loginchan) && alreadylocked) {
01067       if (p->chan) {
01068          ast_queue_frame(p->chan, &ast_null_frame);
01069          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01070          p->app_lock_flag = 1;
01071          ast_mutex_lock(&p->lock);
01072       } else {
01073          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01074          p->owner = NULL;
01075          tmp->tech_pvt = NULL;
01076          p->app_sleep_cond = 1;
01077          ast_channel_free( tmp );
01078          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01079          p->app_lock_flag = 0;
01080          ast_cond_signal(&p->app_complete_cond);
01081          return NULL;
01082       }
01083    } else if (!ast_strlen_zero(p->loginchan)) {
01084       if (p->chan)
01085          ast_queue_frame(p->chan, &ast_null_frame);
01086       if (!p->chan) {
01087          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01088          p->owner = NULL;
01089          tmp->tech_pvt = NULL;
01090          p->app_sleep_cond = 1;
01091          ast_channel_free( tmp );
01092          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
01093          return NULL;
01094       }  
01095    } 
01096    if (p->chan)
01097       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01098    return tmp;
01099 }

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

Definition at line 446 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, ast_channel_trylock, ast_channel_unlock, AST_CONTROL_ANSWER, ast_copy_flags, ast_debug, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), ast_samp2tv(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_tvnow(), ast_verb, agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, DEADLOCK_AVOIDANCE, agent_pvt::enddtmf, 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.

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

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

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

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

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

00596 {
00597    struct agent_pvt *p = ast->tech_pvt;
00598    int res = -1;
00599    ast_mutex_lock(&p->lock);
00600    if (p->chan) 
00601       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00602    ast_mutex_unlock(&p->lock);
00603    return res;
00604 }

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

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

00607 {
00608    struct agent_pvt *p = ast->tech_pvt;
00609    int res = -1;
00610    ast_mutex_lock(&p->lock);
00611    if (p->chan) 
00612       res = ast_sendtext(p->chan, text);
00613    ast_mutex_unlock(&p->lock);
00614    return res;
00615 }

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

Definition at line 803 of file chan_agent.c.

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

00804 {
00805    struct agent_pvt *p = NULL;
00806    
00807    if (!chan || !base) {
00808       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00809       return -1;
00810    }
00811    p = chan->tech_pvt;
00812    if (!p) {
00813       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00814       return -1;
00815    }
00816    p->chan = base;
00817    return 0;
00818 }

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

Definition at line 441 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

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

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

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

00618 {
00619    struct agent_pvt *p = ast->tech_pvt;
00620    int res = -1;
00621    CHECK_FORMATS(ast, p);
00622    ast_mutex_lock(&p->lock);
00623    if (!p->chan) 
00624       res = 0;
00625    else {
00626       if ((f->frametype != AST_FRAME_VOICE) ||
00627           (f->frametype != AST_FRAME_VIDEO) ||
00628           (f->subclass == p->chan->writeformat)) {
00629          res = ast_write(p->chan, f);
00630       } else {
00631          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00632             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00633             ast->name, p->chan->name);
00634          res = 0;
00635       }
00636    }
00637    CLEANUP(ast, p);
00638    ast_mutex_unlock(&p->lock);
00639    return res;
00640 }

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

02227 {
02228    int exitifnoagentid = 0;
02229    int nowarnings = 0;
02230    int changeoutgoing = 0;
02231    int res = 0;
02232    char agent[AST_MAX_AGENT];
02233 
02234    if (data) {
02235       if (strchr(data, 'd'))
02236          exitifnoagentid = 1;
02237       if (strchr(data, 'n'))
02238          nowarnings = 1;
02239       if (strchr(data, 'c'))
02240          changeoutgoing = 1;
02241    }
02242    if (chan->cid.cid_num) {
02243       const char *tmp;
02244       char agentvar[AST_MAX_BUF];
02245       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02246       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02247          struct agent_pvt *p;
02248          ast_copy_string(agent, tmp, sizeof(agent));
02249          AST_LIST_LOCK(&agents);
02250          AST_LIST_TRAVERSE(&agents, p, list) {
02251             if (!strcasecmp(p->agent, tmp)) {
02252                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02253                __agent_start_monitoring(chan, p, 1);
02254                break;
02255             }
02256          }
02257          AST_LIST_UNLOCK(&agents);
02258          
02259       } else {
02260          res = -1;
02261          if (!nowarnings)
02262             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);
02263       }
02264    } else {
02265       res = -1;
02266       if (!nowarnings)
02267          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");
02268    }
02269    if (res) {
02270       if (exitifnoagentid)
02271          return res;
02272    }
02273    return 0;
02274 }

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

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

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

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

01810 {
01811    struct agent_pvt *p;
01812    char username[AST_MAX_BUF];
01813    char location[AST_MAX_BUF] = "";
01814    char talkingto[AST_MAX_BUF] = "";
01815    char music[AST_MAX_BUF];
01816    int count_agents = 0;           /* Number of agents configured */
01817    int online_agents = 0;          /* Number of online agents */
01818    int agent_status = 0;           /* 0 means offline, 1 means online */
01819 
01820    switch (cmd) {
01821    case CLI_INIT:
01822       e->command = "agent show online";
01823       e->usage =
01824          "Usage: agent show online\n"
01825          "       Provides a list of all online agents.\n";
01826       return NULL;
01827    case CLI_GENERATE:
01828       return NULL;
01829    }
01830 
01831    if (a->argc != 3)
01832       return CLI_SHOWUSAGE;
01833 
01834    AST_LIST_LOCK(&agents);
01835    AST_LIST_TRAVERSE(&agents, p, list) {
01836       agent_status = 0;       /* reset it to offline */
01837       ast_mutex_lock(&p->lock);
01838       if (!ast_strlen_zero(p->name))
01839          snprintf(username, sizeof(username), "(%s) ", p->name);
01840       else
01841          username[0] = '\0';
01842       if (p->chan) {
01843          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01844          if (p->owner && ast_bridged_channel(p->owner)) 
01845             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01846          else 
01847             strcpy(talkingto, " is idle");
01848          agent_status = 1;
01849          online_agents++;
01850       } else if (!ast_strlen_zero(p->loginchan)) {
01851          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01852          talkingto[0] = '\0';
01853          agent_status = 1;
01854          online_agents++;
01855          if (p->acknowledged)
01856             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01857       }
01858       if (!ast_strlen_zero(p->moh))
01859          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01860       if (agent_status)
01861          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01862       count_agents++;
01863       ast_mutex_unlock(&p->lock);
01864    }
01865    AST_LIST_UNLOCK(&agents);
01866    if (!count_agents) 
01867       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01868    else
01869       ast_cli(a->fd, "%d agents online\n", online_agents);
01870    ast_cli(a->fd, "\n");
01871    return CLI_SUCCESS;
01872 }

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

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

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

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

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

01330 {
01331    struct agent_pvt *p;
01332    int res=0;
01333 
01334    ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01335    if (needlock)
01336       AST_LIST_LOCK(&agents);
01337    AST_LIST_TRAVERSE(&agents, p, list) {
01338       if (p == newlyavailable) {
01339          continue;
01340       }
01341       ast_mutex_lock(&p->lock);
01342       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01343          ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01344          ast_mutex_unlock(&p->lock);
01345          break;
01346       }
01347       ast_mutex_unlock(&p->lock);
01348    }
01349    if (needlock)
01350       AST_LIST_UNLOCK(&agents);
01351    if (p) {
01352       ast_mutex_unlock(&newlyavailable->lock);
01353       ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01354       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01355       ast_debug(1, "Played beep, result '%d'\n", res);
01356       if (!res) {
01357          res = ast_waitstream(newlyavailable->chan, "");
01358          ast_debug(1, "Waited for stream, result '%d'\n", res);
01359       }
01360       ast_mutex_lock(&newlyavailable->lock);
01361    }
01362    return res;
01363 }

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

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

01705 {
01706    char *ret = NULL;
01707 
01708    if (pos == 2) {
01709       struct agent_pvt *p;
01710       char name[AST_MAX_AGENT];
01711       int which = 0, len = strlen(word);
01712 
01713       AST_LIST_LOCK(&agents);
01714       AST_LIST_TRAVERSE(&agents, p, list) {
01715          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01716          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01717             ret = ast_strdup(name);
01718             break;
01719          }
01720       }
01721       AST_LIST_UNLOCK(&agents);
01722    } else if (pos == 3 && state == 0) 
01723       return ast_strdup("soft");
01724    
01725    return ret;
01726 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

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

02280 {
02281    struct agent_pvt *cur_agent = NULL;
02282    char buf[256];
02283 
02284    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02285       if (cur_agent->chan)
02286          continue;
02287 
02288       if (!ast_strlen_zero(cur_agent->loginchan)) {
02289          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02290          if (ast_db_put(pa_family, cur_agent->agent, buf))
02291             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02292          else
02293             ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02294       } else {
02295          /* Delete -  no agent or there is an error */
02296          ast_db_del(pa_family, cur_agent->agent);
02297       }
02298    }
02299 }

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

Note:
This function expects the agent list to be locked

Definition at line 2402 of file chan_agent.c.

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

Referenced by function_agent().

02403 {
02404    struct agent_pvt *cur;
02405 
02406    AST_LIST_TRAVERSE(&agents, cur, list) {
02407       if (!strcmp(cur->agent, agentid))
02408          break;   
02409    }
02410 
02411    return cur; 
02412 }

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

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

02415 {
02416    char *parse;    
02417    AST_DECLARE_APP_ARGS(args,
02418       AST_APP_ARG(agentid);
02419       AST_APP_ARG(item);
02420    );
02421    char *tmp;
02422    struct agent_pvt *agent;
02423 
02424    buf[0] = '\0';
02425 
02426    if (ast_strlen_zero(data)) {
02427       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02428       return -1;
02429    }
02430 
02431    parse = ast_strdupa(data);
02432 
02433    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02434    if (!args.item)
02435       args.item = "status";
02436 
02437    AST_LIST_LOCK(&agents);
02438 
02439    if (!(agent = find_agent(args.agentid))) {
02440       AST_LIST_UNLOCK(&agents);
02441       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02442       return -1;
02443    }
02444 
02445    if (!strcasecmp(args.item, "status")) {
02446       char *status = "LOGGEDOUT";
02447       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02448          status = "LOGGEDIN"; 
02449       ast_copy_string(buf, status, len);
02450    } else if (!strcasecmp(args.item, "password")) 
02451       ast_copy_string(buf, agent->password, len);
02452    else if (!strcasecmp(args.item, "name"))
02453       ast_copy_string(buf, agent->name, len);
02454    else if (!strcasecmp(args.item, "mohclass"))
02455       ast_copy_string(buf, agent->moh, len);
02456    else if (!strcasecmp(args.item, "channel")) {
02457       if (agent->chan) {
02458          ast_copy_string(buf, agent->chan->name, len);
02459          tmp = strrchr(buf, '-');
02460          if (tmp)
02461             *tmp = '\0';
02462       } 
02463    } else if (!strcasecmp(args.item, "exten"))
02464       ast_copy_string(buf, agent->loginchan, len); 
02465 
02466    AST_LIST_UNLOCK(&agents);
02467 
02468    return 0;
02469 }

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

02495 {
02496    /* Make sure we can register our agent channel type */
02497    if (ast_channel_register(&agent_tech)) {
02498       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02499       return AST_MODULE_LOAD_FAILURE;
02500    }
02501    /* Read in the config */
02502    if (!read_agent_config(0))
02503       return AST_MODULE_LOAD_DECLINE;
02504    if (persistent_agents)
02505       reload_agents();
02506    /* Dialplan applications */
02507    ast_register_application(app, login_exec, synopsis, descrip);
02508    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02509 
02510    /* Manager commands */
02511    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02512    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02513 
02514    /* CLI Commands */
02515    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02516 
02517    /* Dialplan Functions */
02518    ast_custom_function_register(&agent_function);
02519 
02520    return AST_MODULE_LOAD_SUCCESS;
02521 }

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

References ast_channel::_state, agent_pvt::acceptdtmf, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), AGENT_FLAG_ACCEPTDTMF, AGENT_FLAG_ACKCALL, AGENT_FLAG_AUTOLOGOFF, AGENT_FLAG_ENDDTMF, AGENT_FLAG_WRAPUPTIME, agent_pvt::app_complete_cond, agent_pvt::app_lock, agent_pvt::app_lock_flag, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_wait(), AST_CONTROL_HOLD, ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, AST_DEVICE_NOT_INUSE, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), ast_free, ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_flag, ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, agent_pvt::chan, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::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().

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

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

Definition at line 1461 of file chan_agent.c.

01462 {
01463    int x = ffs(d);
01464 
01465    if (x)
01466       return x - 1;
01467 
01468    return 0;
01469 }

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 1107 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_flags, 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().

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

static int reload ( void   )  [static]

Definition at line 2523 of file chan_agent.c.

References read_agent_config(), and reload_agents().

02524 {
02525    if (!read_agent_config(1)) {
02526       if (persistent_agents)
02527          reload_agents();
02528    }
02529    return 0;
02530 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2304 of file chan_agent.c.

References agent_pvt::agent, ast_copy_string(), ast_db_del(), ast_db_freetree(), ast_db_get(), ast_db_gettree(), ast_debug, AST_DEVICE_UNKNOWN, ast_devstate_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_db_entry::key, agent_pvt::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().

02305 {
02306    char *agent_num;
02307    struct ast_db_entry *db_tree;
02308    struct ast_db_entry *entry;
02309    struct agent_pvt *cur_agent;
02310    char agent_data[256];
02311    char *parse;
02312    char *agent_chan;
02313    char *agent_callerid;
02314 
02315    db_tree = ast_db_gettree(pa_family, NULL);
02316 
02317    AST_LIST_LOCK(&agents);
02318    for (entry = db_tree; entry; entry = entry->next) {
02319       agent_num = entry->key + strlen(pa_family) + 2;
02320       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02321          ast_mutex_lock(&cur_agent->lock);
02322          if (strcmp(agent_num, cur_agent->agent) == 0)
02323             break;
02324          ast_mutex_unlock(&cur_agent->lock);
02325       }
02326       if (!cur_agent) {
02327          ast_db_del(pa_family, agent_num);
02328          continue;
02329       } else
02330          ast_mutex_unlock(&cur_agent->lock);
02331       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02332          ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02333          parse = agent_data;
02334          agent_chan = strsep(&parse, ";");
02335          agent_callerid = strsep(&parse, ";");
02336          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02337          if (agent_callerid) {
02338             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02339             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02340          } else
02341             cur_agent->logincallerid[0] = '\0';
02342          if (cur_agent->loginstart == 0)
02343             time(&cur_agent->loginstart);
02344          ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 
02345       }
02346    }
02347    AST_LIST_UNLOCK(&agents);
02348    if (db_tree) {
02349       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02350       ast_db_freetree(db_tree);
02351    }
02352 }

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

00775 {
00776    char buf[AST_MAX_BUF];
00777 
00778    /* if there is no Caller ID, nothing to do */
00779    if (ast_strlen_zero(callerid))
00780       return;
00781 
00782    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00783    pbx_builtin_setvar_helper(NULL, buf, agent);
00784 }

static int unload_module ( void   )  [static]

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

02533 {
02534    struct agent_pvt *p;
02535    /* First, take us out of the channel loop */
02536    ast_channel_unregister(&agent_tech);
02537    /* Unregister dialplan functions */
02538    ast_custom_function_unregister(&agent_function);   
02539    /* Unregister CLI commands */
02540    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02541    /* Unregister dialplan applications */
02542    ast_unregister_application(app);
02543    ast_unregister_application(app3);
02544    /* Unregister manager command */
02545    ast_manager_unregister("Agents");
02546    ast_manager_unregister("AgentLogoff");
02547    /* Unregister channel */
02548    AST_LIST_LOCK(&agents);
02549    /* Hangup all interfaces if they have an owner */
02550    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02551       if (p->owner)
02552          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02553       ast_free(p);
02554    }
02555    AST_LIST_UNLOCK(&agents);
02556    return 0;
02557 }


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

Definition at line 2563 of file chan_agent.c.

char acceptdtmf = DEFAULT_ACCEPTDTMF [static]

Definition at line 138 of file chan_agent.c.

Referenced by play_record_review().

int ackcall [static]

Definition at line 134 of file chan_agent.c.

struct ast_custom_function agent_function

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

Definition at line 252 of file chan_agent.c.

Referenced by agent_new(), load_module(), and unload_module().

char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye" [static]

Definition at line 142 of file chan_agent.c.

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

Definition at line 75 of file chan_agent.c.

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

Definition at line 76 of file chan_agent.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 2563 of file chan_agent.c.

int autologoff [static]

Definition at line 132 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 137 of file chan_agent.c.

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

Definition at line 150 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]

Initial value:

 {
   { .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 1879 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(), execute_cb(), feature_interpret_helper(), load_config(), load_module(), load_odbc_config(), misdn_cfg_init(), odbc_load_module(), park_exec_full(), parse_config(), pbx_load_module(), read_config_maps(), 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 135 of file chan_agent.c.

char enddtmf = DEFAULT_ENDDTMF [static]

Definition at line 139 of file chan_agent.c.

ast_group_t group [static]

Definition at line 131 of file chan_agent.c.

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

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

Definition at line 116 of file chan_agent.c.

Referenced by _get_mohbyname(), _moh_register(), dial_exec_full(), moh_generate(), moh_release(), mohalloc(), and monmp3thread().

int multiplelogin = 1 [static]

Definition at line 136 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 122 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 125 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 144 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 145 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 146 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 148 of file chan_agent.c.

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

Definition at line 78 of file chan_agent.c.

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

Definition at line 79 of file chan_agent.c.

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

Definition at line 72 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 149 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 147 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 133 of file chan_agent.c.


Generated on Wed Aug 18 22:34:06 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7