Fri Nov 12 11:54:54 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"
Include dependency graph for chan_agent.c:

Go to the source code of this file.

Data Structures

struct  agent_pvt
 Structure representing an agent. More...
struct  agents

Defines

#define AST_MAX_AGENT   80
#define AST_MAX_BUF   256
#define AST_MAX_FILENAME_LEN   256
#define CHECK_FORMATS(ast, p)
#define CLEANUP(ast, p)
 Cleanup moves all the relevant FD's from the 2nd to the first, but retains things properly for a timingfd XXX This might need more work if agents were logged in as agents or other totally impractical combinations XXX.
#define DEFAULT_ACCEPTDTMF   '#'
#define DEFAULT_ENDDTMF   '*'
#define GETAGENTBYCALLERID   "AGENTBYCALLERID"
#define PA_MAX_LEN   2048

Enumerations

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

Functions

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

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Agent Proxy Channel" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, }
static char acceptdtmf = DEFAULT_ACCEPTDTMF
static int ackcall
struct ast_custom_function agent_function
static const char agent_logoff_usage []
static struct ast_channel_tech agent_tech
 Channel interface description for PBX integration.
static char agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static const char app [] = "AgentLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static struct ast_module_infoast_module_info = &__mod_info
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static const char config [] = "agents.conf"
static 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 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 191 of file chan_agent.c.

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

#define AST_MAX_BUF   256
#define AST_MAX_FILENAME_LEN   256

Definition at line 193 of file chan_agent.c.

Referenced by login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define DEFAULT_ACCEPTDTMF   '#'

Definition at line 201 of file chan_agent.c.

#define DEFAULT_ENDDTMF   '*'

Definition at line 202 of file chan_agent.c.

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 225 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 196 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 227 of file chan_agent.c.

00227      {
00228    AGENT_FLAG_ACKCALL = (1 << 0),
00229    AGENT_FLAG_AUTOLOGOFF = (1 << 1),
00230    AGENT_FLAG_WRAPUPTIME = (1 << 2),
00231    AGENT_FLAG_ACCEPTDTMF = (1 << 3),
00232    AGENT_FLAG_ENDDTMF = (1 << 4),
00233 };


Function Documentation

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

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

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

static void __reg_module ( void   )  [static]

Definition at line 2636 of file chan_agent.c.

static void __unreg_module ( void   )  [static]

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

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

Referenced by load_module().

01769 {
01770    const char *agent = astman_get_header(m, "Agent");
01771    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01772    int soft;
01773    int ret; /* return value of agent_logoff */
01774 
01775    if (ast_strlen_zero(agent)) {
01776       astman_send_error(s, m, "No agent specified");
01777       return 0;
01778    }
01779 
01780    soft = ast_true(soft_s) ? 1 : 0;
01781    ret = agent_logoff(agent, soft);
01782    if (ret == 0)
01783       astman_send_ack(s, m, "Agent logged out");
01784    else
01785       astman_send_error(s, m, "No such agent");
01786 
01787    return 0;
01788 }

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 1565 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_strlen_zero(), astman_append(), astman_get_header(), astman_send_ack(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_num, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, ast_channel::name, agent_pvt::name, agent_pvt::owner, S_OR, and status.

Referenced by load_module().

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

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

Adds an agent to the global list of agents.

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

Definition at line 357 of file chan_agent.c.

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

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 1028 of file chan_agent.c.

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

Referenced by login_exec().

01029 {
01030    struct agent_pvt *p;
01031    int res=0;
01032    int to = 1000;
01033    struct ast_frame *f;
01034 
01035    /* Wait a second and look for something */
01036 
01037    p = (struct agent_pvt *) data;
01038    if (!p->chan) 
01039       return -1;
01040 
01041    for(;;) {
01042       to = ast_waitfor(p->chan, to);
01043       if (to < 0) 
01044          return -1;
01045       if (!to) 
01046          return 0;
01047       f = ast_read(p->chan);
01048       if (!f) 
01049          return -1;
01050       if (f->frametype == AST_FRAME_DTMF)
01051          res = f->subclass;
01052       else
01053          res = 0;
01054       ast_frfree(f);
01055       ast_mutex_lock(&p->lock);
01056       if (!p->app_sleep_cond) {
01057          ast_mutex_unlock(&p->lock);
01058          return 0;
01059       } else if (res == p->acceptdtmf) {
01060          ast_mutex_unlock(&p->lock);
01061          return 1;
01062       }
01063       ast_mutex_unlock(&p->lock);
01064       res = 0;
01065    }
01066    return res;
01067 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 480 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00481 {
00482    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00483    return -1;
00484 }

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

Definition at line 1069 of file chan_agent.c.

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

01070 {
01071    struct agent_pvt *p = bridge->tech_pvt;
01072    struct ast_channel *ret = NULL;
01073 
01074    if (p) {
01075       if (chan == p->chan)
01076          ret = bridge->_bridge;
01077       else if (chan == bridge->_bridge)
01078          ret = p->chan;
01079    }
01080 
01081    ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01082    return ret;
01083 }

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

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

00771 {
00772    struct agent_pvt *p = ast->tech_pvt;
00773    int res = -1;
00774    int newstate=0;
00775    ast_mutex_lock(&p->lock);
00776    p->acknowledged = 0;
00777    if (!p->chan) {
00778       if (p->pending) {
00779          ast_debug(1, "Pretending to dial on pending agent\n");
00780          newstate = AST_STATE_DIALING;
00781          res = 0;
00782       } else {
00783          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00784          res = -1;
00785       }
00786       ast_mutex_unlock(&p->lock);
00787       if (newstate)
00788          ast_setstate(ast, newstate);
00789       return res;
00790    } else if (!ast_strlen_zero(p->loginchan)) {
00791       time(&p->start);
00792       /* Call on this agent */
00793       ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00794       ast_set_callerid(p->chan,
00795          ast->cid.cid_num, ast->cid.cid_name, NULL);
00796       ast_channel_inherit_variables(ast, p->chan);
00797       res = ast_call(p->chan, p->loginchan, 0);
00798       CLEANUP(ast,p);
00799       ast_mutex_unlock(&p->lock);
00800       return res;
00801    }
00802    ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00803    ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
00804    res = ast_streamfile(p->chan, beep, p->chan->language);
00805    ast_debug(3, "Played beep, result '%d'\n", res);
00806    if (!res) {
00807       res = ast_waitstream(p->chan, "");
00808       ast_debug(3, "Waited for stream, result '%d'\n", res);
00809    }
00810    if (!res) {
00811       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00812       ast_debug(3, "Set read format, result '%d'\n", res);
00813       if (res)
00814          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00815    } else {
00816       /* Agent hung-up */
00817       p->chan = NULL;
00818       ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00819    }
00820 
00821    if (!res) {
00822       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00823       ast_debug(3, "Set write format, result '%d'\n", res);
00824       if (res)
00825          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00826    }
00827    if(!res) {
00828       /* Call is immediately up, or might need ack */
00829       if (p->ackcall > 1)
00830          newstate = AST_STATE_RINGING;
00831       else {
00832          newstate = AST_STATE_UP;
00833          if (recordagentcalls)
00834             agent_start_monitoring(ast, 0);
00835          p->acknowledged = 1;
00836       }
00837       res = 0;
00838    }
00839    CLEANUP(ast, p);
00840    ast_mutex_unlock(&p->lock);
00841    if (newstate)
00842       ast_setstate(ast, newstate);
00843    return res;
00844 }

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

00459 {
00460    struct ast_channel *chan = p->owner;
00461    p->owner = NULL;
00462    chan->tech_pvt = NULL;
00463    p->app_sleep_cond = 1;
00464    /* Release ownership of the agent to other threads (presumably running the login app). */
00465    p->app_lock_flag = 0;
00466    ast_cond_signal(&p->app_complete_cond);
00467    if (chan)
00468       ast_channel_free(chan);
00469    if (p->dead) {
00470       ast_mutex_destroy(&p->lock);
00471       ast_mutex_destroy(&p->app_lock);
00472       ast_cond_destroy(&p->app_complete_cond);
00473       ast_free(p);
00474         }
00475    return 0;
00476 }

static int agent_cont_sleep ( void *  data  )  [static]

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

01008 {
01009    struct agent_pvt *p;
01010    int res;
01011 
01012    p = (struct agent_pvt *)data;
01013 
01014    ast_mutex_lock(&p->lock);
01015    res = p->app_sleep_cond;
01016    if (p->lastdisc.tv_sec) {
01017       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
01018          res = 1;
01019    }
01020    ast_mutex_unlock(&p->lock);
01021 
01022    if (!res)
01023       ast_debug(5, "agent_cont_sleep() returning %d\n", res );
01024 
01025    return res;
01026 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2438 of file chan_agent.c.

References agent_pvt::agent, AST_DEVICE_BUSY, AST_DEVICE_INUSE, AST_DEVICE_INVALID, AST_DEVICE_UNAVAILABLE, AST_DEVICE_UNKNOWN, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

02439 {
02440    struct agent_pvt *p;
02441    char *s;
02442    ast_group_t groupmatch;
02443    int groupoff;
02444    int res = AST_DEVICE_INVALID;
02445    
02446    s = data;
02447    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
02448       groupmatch = (1 << groupoff);
02449    else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
02450       groupmatch = (1 << groupoff);
02451    } else 
02452       groupmatch = 0;
02453 
02454    /* Check actual logged in agents first */
02455    AST_LIST_LOCK(&agents);
02456    AST_LIST_TRAVERSE(&agents, p, list) {
02457       ast_mutex_lock(&p->lock);
02458       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02459          if (p->owner) {
02460             if (res != AST_DEVICE_INUSE)
02461                res = AST_DEVICE_BUSY;
02462          } else {
02463             if (res == AST_DEVICE_BUSY)
02464                res = AST_DEVICE_INUSE;
02465             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02466                if (res == AST_DEVICE_INVALID)
02467                   res = AST_DEVICE_UNKNOWN;
02468             } else if (res == AST_DEVICE_INVALID)  
02469                res = AST_DEVICE_UNAVAILABLE;
02470          }
02471          if (!strcmp(data, p->agent)) {
02472             ast_mutex_unlock(&p->lock);
02473             break;
02474          }
02475       }
02476       ast_mutex_unlock(&p->lock);
02477    }
02478    AST_LIST_UNLOCK(&agents);
02479    return res;
02480 }

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

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

00749 {
00750    struct agent_pvt *p = ast->tech_pvt;
00751    ast_mutex_lock(&p->lock);
00752    if (p->chan) {
00753       ast_senddigit_begin(p->chan, digit);
00754    }
00755    ast_mutex_unlock(&p->lock);
00756    return 0;
00757 }

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

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

00760 {
00761    struct agent_pvt *p = ast->tech_pvt;
00762    ast_mutex_lock(&p->lock);
00763    if (p->chan) {
00764       ast_senddigit_end(p->chan, digit, duration);
00765    }
00766    ast_mutex_unlock(&p->lock);
00767    return 0;
00768 }

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

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

00716 {
00717    struct agent_pvt *p = newchan->tech_pvt;
00718    ast_mutex_lock(&p->lock);
00719    if (p->owner != oldchan) {
00720       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00721       ast_mutex_unlock(&p->lock);
00722       return -1;
00723    }
00724    p->owner = newchan;
00725    ast_mutex_unlock(&p->lock);
00726    return 0;
00727 }

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

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

Definition at line 860 of file chan_agent.c.

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

00861 {
00862    struct agent_pvt *p = NULL;
00863    struct ast_channel *base = chan;
00864 
00865    /* chan is locked by the calling function */
00866    if (!chan || !chan->tech_pvt) {
00867       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);
00868       return NULL;
00869    }
00870    p = chan->tech_pvt;
00871    if (p->chan) 
00872       base = p->chan;
00873    return base;
00874 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 893 of file chan_agent.c.

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

00894 {
00895    struct agent_pvt *p = ast->tech_pvt;
00896    int howlong = 0;
00897    const char *status;
00898    ast_mutex_lock(&p->lock);
00899    p->owner = NULL;
00900    ast->tech_pvt = NULL;
00901    p->app_sleep_cond = 1;
00902    p->acknowledged = 0;
00903 
00904    /* if they really are hung up then set start to 0 so the test
00905     * later if we're called on an already downed channel
00906     * doesn't cause an agent to be logged out like when
00907     * agent_request() is followed immediately by agent_hangup()
00908     * as in apps/app_chanisavail.c:chanavail_exec()
00909     */
00910 
00911    ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
00912    if (p->start && (ast->_state != AST_STATE_UP)) {
00913       howlong = time(NULL) - p->start;
00914       p->start = 0;
00915    } else if (ast->_state == AST_STATE_RESERVED) 
00916       howlong = 0;
00917    else
00918       p->start = 0; 
00919    if (p->chan) {
00920       p->chan->_bridge = NULL;
00921       /* If they're dead, go ahead and hang up on the agent now */
00922       if (!ast_strlen_zero(p->loginchan)) {
00923          /* Store last disconnect time */
00924          if (p->wrapuptime)
00925             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00926          else
00927             p->lastdisc = ast_tv(0,0);
00928          if (p->chan) {
00929             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00930             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00931                long logintime = time(NULL) - p->loginstart;
00932                p->loginstart = 0;
00933                ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00934                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00935             }
00936             /* Recognize the hangup and pass it along immediately */
00937             ast_hangup(p->chan);
00938             p->chan = NULL;
00939             ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00940          }
00941          ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00942          if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
00943             long logintime = time(NULL) - p->loginstart;
00944             p->loginstart = 0;
00945             if (!p->deferlogoff)
00946                ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00947             p->deferlogoff = 0;
00948             agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00949             if (persistent_agents)
00950                dump_agents();
00951          }
00952       } else if (p->dead) {
00953          ast_channel_lock(p->chan);
00954          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00955          ast_channel_unlock(p->chan);
00956       } else if (p->loginstart) {
00957          ast_channel_lock(p->chan);
00958          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00959             S_OR(p->moh, NULL),
00960             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00961          ast_channel_unlock(p->chan);
00962       }
00963    }
00964    ast_mutex_unlock(&p->lock);
00965 
00966    /* Only register a device state change if the agent is still logged in */
00967    if (!p->loginstart) {
00968       p->loginchan[0] = '\0';
00969       p->logincallerid[0] = '\0';
00970       if (persistent_agents)
00971          dump_agents();
00972    } else {
00973       ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
00974    }
00975 
00976    if (p->pending) {
00977       AST_LIST_LOCK(&agents);
00978       AST_LIST_REMOVE(&agents, p, list);
00979       AST_LIST_UNLOCK(&agents);
00980    }
00981    if (p->abouttograb) {
00982       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00983          kill it later */
00984       p->abouttograb = 0;
00985    } else if (p->dead) {
00986       ast_mutex_destroy(&p->lock);
00987       ast_mutex_destroy(&p->app_lock);
00988       ast_cond_destroy(&p->app_complete_cond);
00989       ast_free(p);
00990    } else {
00991       if (p->chan) {
00992          /* Not dead -- check availability now */
00993          ast_mutex_lock(&p->lock);
00994          /* Store last disconnect time */
00995          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00996          ast_mutex_unlock(&p->lock);
00997       }
00998       /* Release ownership of the agent to other threads (presumably running the login app). */
00999       if (ast_strlen_zero(p->loginchan)) {
01000          p->app_lock_flag = 0;
01001          ast_cond_signal(&p->app_complete_cond);
01002       }
01003    }
01004    return 0;
01005 }

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

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

00730 {
00731    struct agent_pvt *p = ast->tech_pvt;
00732    int res = -1;
00733    ast_mutex_lock(&p->lock);
00734    if (p->chan && !ast_check_hangup(p->chan)) {
00735       while (ast_channel_trylock(p->chan)) {
00736          ast_channel_unlock(ast);
00737          usleep(1);
00738          ast_channel_lock(ast);
00739       }
00740       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00741       ast_channel_unlock(p->chan);
00742    } else
00743       res = 0;
00744    ast_mutex_unlock(&p->lock);
00745    return res;
00746 }

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

Definition at line 1684 of file chan_agent.c.

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

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01685 {
01686    struct agent_pvt *p;
01687    long logintime;
01688    int ret = -1; /* Return -1 if no agent if found */
01689 
01690    AST_LIST_LOCK(&agents);
01691    AST_LIST_TRAVERSE(&agents, p, list) {
01692       if (!strcasecmp(p->agent, agent)) {
01693          ret = 0;
01694          if (p->owner || p->chan) {
01695             if (!soft) {
01696                ast_mutex_lock(&p->lock);
01697 
01698                while (p->owner && ast_channel_trylock(p->owner)) {
01699                   DEADLOCK_AVOIDANCE(&p->lock);
01700                }
01701                if (p->owner) {
01702                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01703                   ast_channel_unlock(p->owner);
01704                }
01705 
01706                while (p->chan && ast_channel_trylock(p->chan)) {
01707                   DEADLOCK_AVOIDANCE(&p->lock);
01708                }
01709                if (p->chan) {
01710                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01711                   ast_channel_unlock(p->chan);
01712                }
01713 
01714                ast_mutex_unlock(&p->lock);
01715             } else
01716                p->deferlogoff = 1;
01717          } else {
01718             logintime = time(NULL) - p->loginstart;
01719             p->loginstart = 0;
01720             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01721          }
01722          break;
01723       }
01724    }
01725    AST_LIST_UNLOCK(&agents);
01726 
01727    return ret;
01728 }

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

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

01731 {
01732    int ret;
01733    char *agent;
01734 
01735    switch (cmd) {
01736    case CLI_INIT:
01737       e->command = "agent logoff";
01738       e->usage =
01739          "Usage: agent logoff <channel> [soft]\n"
01740          "       Sets an agent as no longer logged in.\n"
01741          "       If 'soft' is specified, do not hangup existing calls.\n";
01742       return NULL;
01743    case CLI_GENERATE:
01744       return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
01745    }
01746 
01747    if (a->argc < 3 || a->argc > 4)
01748       return CLI_SHOWUSAGE;
01749    if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
01750       return CLI_SHOWUSAGE;
01751 
01752    agent = a->argv[2] + 6;
01753    ret = agent_logoff(agent, a->argc == 4);
01754    if (ret == 0)
01755       ast_cli(a->fd, "Logging out %s\n", agent);
01756 
01757    return CLI_SUCCESS;
01758 }

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

Definition at line 1645 of file chan_agent.c.

References agent_pvt::agent, AST_DEVICE_UNAVAILABLE, ast_devstate_changed(), AST_MAX_AGENT, ast_queue_log(), 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().

01646 {
01647    char *tmp = NULL;
01648    char agent[AST_MAX_AGENT];
01649 
01650    if (!ast_strlen_zero(logcommand))
01651       tmp = logcommand;
01652    else
01653       tmp = ast_strdupa("");
01654 
01655    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01656 
01657    if (!ast_strlen_zero(uniqueid)) {
01658       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01659             "Agent: %s\r\n"
01660             "Reason: %s\r\n"
01661             "Loginchan: %s\r\n"
01662             "Logintime: %ld\r\n"
01663             "Uniqueid: %s\r\n", 
01664             p->agent, tmp, loginchan, logintime, uniqueid);
01665    } else {
01666       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01667             "Agent: %s\r\n"
01668             "Reason: %s\r\n"
01669             "Loginchan: %s\r\n"
01670             "Logintime: %ld\r\n",
01671             p->agent, tmp, loginchan, logintime);
01672    }
01673 
01674    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01675    set_agentbycallerid(p->logincallerid, NULL);
01676    p->loginchan[0] ='\0';
01677    p->logincallerid[0] = '\0';
01678    ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
01679    if (persistent_agents)
01680       dump_agents();
01681 
01682 }

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

Create new agent channel.

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

01087 {
01088    struct ast_channel *tmp;
01089    int alreadylocked;
01090 #if 0
01091    if (!p->chan) {
01092       ast_log(LOG_WARNING, "No channel? :(\n");
01093       return NULL;
01094    }
01095 #endif   
01096    if (p->pending)
01097       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);
01098    else
01099       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
01100    if (!tmp) {
01101       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01102       return NULL;
01103    }
01104 
01105    tmp->tech = &agent_tech;
01106    if (p->chan) {
01107       tmp->nativeformats = p->chan->nativeformats;
01108       tmp->writeformat = p->chan->writeformat;
01109       tmp->rawwriteformat = p->chan->writeformat;
01110       tmp->readformat = p->chan->readformat;
01111       tmp->rawreadformat = p->chan->readformat;
01112       ast_string_field_set(tmp, language, p->chan->language);
01113       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01114       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01115       /* XXX Is this really all we copy form the originating channel?? */
01116    } else {
01117       tmp->nativeformats = AST_FORMAT_SLINEAR;
01118       tmp->writeformat = AST_FORMAT_SLINEAR;
01119       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01120       tmp->readformat = AST_FORMAT_SLINEAR;
01121       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01122    }
01123    /* Safe, agentlock already held */
01124    tmp->tech_pvt = p;
01125    p->owner = tmp;
01126    tmp->priority = 1;
01127    /* Wake up and wait for other applications (by definition the login app)
01128     * to release this channel). Takes ownership of the agent channel
01129     * to this thread only.
01130     * For signalling the other thread, ast_queue_frame is used until we
01131     * can safely use signals for this purpose. The pselect() needs to be
01132     * implemented in the kernel for this.
01133     */
01134    p->app_sleep_cond = 0;
01135 
01136    alreadylocked = p->app_lock_flag;
01137    p->app_lock_flag = 1;
01138 
01139    if(ast_strlen_zero(p->loginchan) && alreadylocked) {
01140       if (p->chan) {
01141          ast_queue_frame(p->chan, &ast_null_frame);
01142          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01143          p->app_lock_flag = 1;
01144          ast_mutex_lock(&p->lock);
01145       } else {
01146          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01147          p->owner = NULL;
01148          tmp->tech_pvt = NULL;
01149          p->app_sleep_cond = 1;
01150          ast_channel_free( tmp );
01151          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01152          p->app_lock_flag = 0;
01153          ast_cond_signal(&p->app_complete_cond);
01154          return NULL;
01155       }
01156    } else if (!ast_strlen_zero(p->loginchan)) {
01157       if (p->chan)
01158          ast_queue_frame(p->chan, &ast_null_frame);
01159       if (!p->chan) {
01160          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01161          p->owner = NULL;
01162          tmp->tech_pvt = NULL;
01163          p->app_sleep_cond = 1;
01164          ast_channel_free( tmp );
01165          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
01166          return NULL;
01167       }  
01168    } 
01169    if (p->chan)
01170       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01171    return tmp;
01172 }

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

Definition at line 519 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, ast_frame::frametype, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, ast_channel::name, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, status, ast_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, ast_channel::uniqueid, and agent_pvt::wrapuptime.

00520 {
00521    struct agent_pvt *p = ast->tech_pvt;
00522    struct ast_frame *f = NULL;
00523    static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
00524    const char *status;
00525    int cur_time = time(NULL);
00526    ast_mutex_lock(&p->lock);
00527    CHECK_FORMATS(ast, p);
00528    if (!p->start) {
00529       p->start = cur_time;
00530    }
00531    if (p->chan) {
00532       ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
00533       p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
00534       f = ast_read(p->chan);
00535    } else
00536       f = &ast_null_frame;
00537    if (!f) {
00538       /* If there's a channel, hang it up (if it's on a callback) make it NULL */
00539       if (p->chan) {
00540          p->chan->_bridge = NULL;
00541          /* Note that we don't hangup if it's not a callback because Asterisk will do it
00542             for us when the PBX instance that called login finishes */
00543          if (!ast_strlen_zero(p->loginchan)) {
00544             if (p->chan)
00545                ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name);
00546             if (p->owner->_state != AST_STATE_UP) {
00547                int howlong = cur_time - p->start;
00548                if (p->autologoff && howlong >= p->autologoff) {
00549                   p->loginstart = 0;
00550                      ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00551                   agent_logoff_maintenance(p, p->loginchan, (cur_time = p->loginstart), ast->uniqueid, "Autologoff");
00552                }
00553             }
00554             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00555             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00556                long logintime = cur_time - p->loginstart;
00557                p->loginstart = 0;
00558                ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
00559                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00560             }
00561             ast_hangup(p->chan);
00562             if (p->wrapuptime && p->acknowledged)
00563                p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00564          }
00565          p->chan = NULL;
00566          ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
00567          p->acknowledged = 0;
00568       }
00569    } else {
00570       /* if acknowledgement is not required, and the channel is up, we may have missed
00571          an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
00572       if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP)) {
00573          p->acknowledged = 1;
00574       }
00575 
00576       if (!p->acknowledged) {
00577          int howlong = cur_time - p->start;
00578          if (p->autologoff && (howlong >= p->autologoff)) {
00579             ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00580             agent_logoff_maintenance(p, p->loginchan, (cur_time - p->loginstart), ast->uniqueid, "Autologoff");
00581             if (p->owner || p->chan) {
00582                while (p->owner && ast_channel_trylock(p->owner)) {
00583                   DEADLOCK_AVOIDANCE(&p->lock);
00584                }
00585                if (p->owner) {
00586                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
00587                   ast_channel_unlock(p->owner);
00588                }
00589 
00590                while (p->chan && ast_channel_trylock(p->chan)) {
00591                   DEADLOCK_AVOIDANCE(&p->lock);
00592                }
00593                if (p->chan) {
00594                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00595                   ast_channel_unlock(p->chan);
00596                }
00597             } else {
00598                long logintime;
00599                logintime = time(NULL) - p->loginstart;
00600                p->loginstart = 0;
00601                agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
00602             }
00603          }
00604       }
00605       switch (f->frametype) {
00606       case AST_FRAME_CONTROL:
00607          if (f->subclass == AST_CONTROL_ANSWER) {
00608             if (p->ackcall) {
00609                ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf);
00610                /* Don't pass answer along */
00611                ast_frfree(f);
00612                f = &ast_null_frame;
00613             } else {
00614                p->acknowledged = 1;
00615                /* Use the builtin answer frame for the 
00616                   recording start check below. */
00617                ast_frfree(f);
00618                f = &answer_frame;
00619             }
00620          }
00621          break;
00622       case AST_FRAME_DTMF_BEGIN:
00623          /*ignore DTMF begin's as it can cause issues with queue announce files*/
00624          if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){
00625             ast_frfree(f);
00626             f = &ast_null_frame;
00627          }
00628          break;
00629       case AST_FRAME_DTMF_END:
00630          if (!p->acknowledged && (f->subclass == p->acceptdtmf)) {
00631             ast_verb(3, "%s acknowledged\n", p->chan->name);
00632             p->acknowledged = 1;
00633             ast_frfree(f);
00634             f = &answer_frame;
00635          } else if (f->subclass == p->enddtmf && endcall) {
00636             /* terminates call */
00637             ast_frfree(f);
00638             f = NULL;
00639          }
00640          break;
00641       case AST_FRAME_VOICE:
00642       case AST_FRAME_VIDEO:
00643          /* don't pass voice or video until the call is acknowledged */
00644          if (!p->acknowledged) {
00645             ast_frfree(f);
00646             f = &ast_null_frame;
00647          }
00648       default:
00649          /* pass everything else on through */
00650          break;
00651       }
00652    }
00653 
00654    CLEANUP(ast,p);
00655    if (p->chan && !p->chan->_bridge) {
00656       if (strcasecmp(p->chan->tech->type, "Local")) {
00657          p->chan->_bridge = ast;
00658          if (p->chan)
00659             ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
00660       }
00661    }
00662    ast_mutex_unlock(&p->lock);
00663    if (recordagentcalls && f == &answer_frame)
00664       agent_start_monitoring(ast,0);
00665    return f;
00666 }

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

Part of the Asterisk PBX interface.

Definition at line 1452 of file chan_agent.c.

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

01453 {
01454    struct agent_pvt *p;
01455    struct ast_channel *chan = NULL;
01456    char *s;
01457    ast_group_t groupmatch;
01458    int groupoff;
01459    int waitforagent=0;
01460    int hasagent = 0;
01461    struct timeval now;
01462 
01463    s = data;
01464    if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01465       groupmatch = (1 << groupoff);
01466    } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
01467       groupmatch = (1 << groupoff);
01468       waitforagent = 1;
01469    } else 
01470       groupmatch = 0;
01471 
01472    /* Check actual logged in agents first */
01473    AST_LIST_LOCK(&agents);
01474    AST_LIST_TRAVERSE(&agents, p, list) {
01475       ast_mutex_lock(&p->lock);
01476       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01477           ast_strlen_zero(p->loginchan)) {
01478          if (p->chan)
01479             hasagent++;
01480          now = ast_tvnow();
01481          if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01482             p->lastdisc = ast_tv(0, 0);
01483             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01484             if (!p->owner && p->chan) {
01485                /* Fixed agent */
01486                chan = agent_new(p, AST_STATE_DOWN);
01487             }
01488             if (chan) {
01489                ast_mutex_unlock(&p->lock);
01490                break;
01491             }
01492          }
01493       }
01494       ast_mutex_unlock(&p->lock);
01495    }
01496    if (!p) {
01497       AST_LIST_TRAVERSE(&agents, p, list) {
01498          ast_mutex_lock(&p->lock);
01499          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01500             if (p->chan || !ast_strlen_zero(p->loginchan))
01501                hasagent++;
01502             now = ast_tvnow();
01503 #if 0
01504             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec);
01505 #endif
01506             if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
01507                p->lastdisc = ast_tv(0, 0);
01508                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01509                if (!p->owner && p->chan) {
01510                   /* Could still get a fixed agent */
01511                   chan = agent_new(p, AST_STATE_DOWN);
01512                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01513                   /* Adjustable agent */
01514                   p->chan = ast_request("Local", format, p->loginchan, cause);
01515                   if (p->chan)
01516                      chan = agent_new(p, AST_STATE_DOWN);
01517                }
01518                if (chan) {
01519                   ast_mutex_unlock(&p->lock);
01520                   break;
01521                }
01522             }
01523          }
01524          ast_mutex_unlock(&p->lock);
01525       }
01526    }
01527 
01528    if (!chan && waitforagent) {
01529       /* No agent available -- but we're requesting to wait for one.
01530          Allocate a place holder */
01531       if (hasagent) {
01532          ast_debug(1, "Creating place holder for '%s'\n", s);
01533          p = add_agent(data, 1);
01534          p->group = groupmatch;
01535          chan = agent_new(p, AST_STATE_DOWN);
01536          if (!chan) 
01537             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01538       } else {
01539          ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
01540       }
01541    }
01542    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01543    AST_LIST_UNLOCK(&agents);
01544    return chan;
01545 }

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

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

00669 {
00670    struct agent_pvt *p = ast->tech_pvt;
00671    int res = -1;
00672    ast_mutex_lock(&p->lock);
00673    if (p->chan) 
00674       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00675    ast_mutex_unlock(&p->lock);
00676    return res;
00677 }

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

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

00680 {
00681    struct agent_pvt *p = ast->tech_pvt;
00682    int res = -1;
00683    ast_mutex_lock(&p->lock);
00684    if (p->chan) 
00685       res = ast_sendtext(p->chan, text);
00686    ast_mutex_unlock(&p->lock);
00687    return res;
00688 }

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

Definition at line 876 of file chan_agent.c.

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

00877 {
00878    struct agent_pvt *p = NULL;
00879    
00880    if (!chan || !base) {
00881       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00882       return -1;
00883    }
00884    p = chan->tech_pvt;
00885    if (!p) {
00886       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00887       return -1;
00888    }
00889    p->chan = base;
00890    return 0;
00891 }

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

Definition at line 514 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00515 {
00516    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00517 }

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

Definition at line 690 of file chan_agent.c.

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

00691 {
00692    struct agent_pvt *p = ast->tech_pvt;
00693    int res = -1;
00694    CHECK_FORMATS(ast, p);
00695    ast_mutex_lock(&p->lock);
00696    if (!p->chan) 
00697       res = 0;
00698    else {
00699       if ((f->frametype != AST_FRAME_VOICE) ||
00700           (f->frametype != AST_FRAME_VIDEO) ||
00701           (f->subclass == p->chan->writeformat)) {
00702          res = ast_write(p->chan, f);
00703       } else {
00704          ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00705             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00706             ast->name, p->chan->name);
00707          res = 0;
00708       }
00709    }
00710    CLEANUP(ast, p);
00711    ast_mutex_unlock(&p->lock);
00712    return res;
00713 }

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

References __agent_start_monitoring(), agent_pvt::agent, ast_copy_string(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_channel::cdr, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, GETAGENTBYCALLERID, LOG_WARNING, and pbx_builtin_getvar_helper().

Referenced by load_module().

02310 {
02311    int exitifnoagentid = 0;
02312    int nowarnings = 0;
02313    int changeoutgoing = 0;
02314    int res = 0;
02315    char agent[AST_MAX_AGENT];
02316 
02317    if (data) {
02318       if (strchr(data, 'd'))
02319          exitifnoagentid = 1;
02320       if (strchr(data, 'n'))
02321          nowarnings = 1;
02322       if (strchr(data, 'c'))
02323          changeoutgoing = 1;
02324    }
02325    if (chan->cid.cid_num) {
02326       const char *tmp;
02327       char agentvar[AST_MAX_BUF];
02328       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02329       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02330          struct agent_pvt *p;
02331          ast_copy_string(agent, tmp, sizeof(agent));
02332          AST_LIST_LOCK(&agents);
02333          AST_LIST_TRAVERSE(&agents, p, list) {
02334             if (!strcasecmp(p->agent, tmp)) {
02335                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02336                __agent_start_monitoring(chan, p, 1);
02337                break;
02338             }
02339          }
02340          AST_LIST_UNLOCK(&agents);
02341          
02342       } else {
02343          res = -1;
02344          if (!nowarnings)
02345             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);
02346       }
02347    } else {
02348       res = -1;
02349       if (!nowarnings)
02350          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");
02351    }
02352    if (res) {
02353       if (exitifnoagentid)
02354          return res;
02355    }
02356    return 0;
02357 }

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

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

01818 {
01819    struct agent_pvt *p;
01820    char username[AST_MAX_BUF];
01821    char location[AST_MAX_BUF] = "";
01822    char talkingto[AST_MAX_BUF] = "";
01823    char music[AST_MAX_BUF];
01824    int count_agents = 0;      /*!< Number of agents configured */
01825    int online_agents = 0;     /*!< Number of online agents */
01826    int offline_agents = 0;    /*!< Number of offline agents */
01827 
01828    switch (cmd) {
01829    case CLI_INIT:
01830       e->command = "agent show";
01831       e->usage =
01832          "Usage: agent show\n"
01833          "       Provides summary information on agents.\n";
01834       return NULL;
01835    case CLI_GENERATE:
01836       return NULL;
01837    }
01838 
01839    if (a->argc != 2)
01840       return CLI_SHOWUSAGE;
01841 
01842    AST_LIST_LOCK(&agents);
01843    AST_LIST_TRAVERSE(&agents, p, list) {
01844       ast_mutex_lock(&p->lock);
01845       if (p->pending) {
01846          if (p->group)
01847             ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
01848          else
01849             ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
01850       } else {
01851          if (!ast_strlen_zero(p->name))
01852             snprintf(username, sizeof(username), "(%s) ", p->name);
01853          else
01854             username[0] = '\0';
01855          if (p->chan) {
01856             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01857             if (p->owner && ast_bridged_channel(p->owner))
01858                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01859              else 
01860                strcpy(talkingto, " is idle");
01861             online_agents++;
01862          } else if (!ast_strlen_zero(p->loginchan)) {
01863             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01864                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01865             else 
01866                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01867             talkingto[0] = '\0';
01868             online_agents++;
01869             if (p->acknowledged)
01870                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01871          } else {
01872             strcpy(location, "not logged in");
01873             talkingto[0] = '\0';
01874             offline_agents++;
01875          }
01876          if (!ast_strlen_zero(p->moh))
01877             snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01878          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
01879             username, location, talkingto, music);
01880          count_agents++;
01881       }
01882       ast_mutex_unlock(&p->lock);
01883    }
01884    AST_LIST_UNLOCK(&agents);
01885    if ( !count_agents ) 
01886       ast_cli(a->fd, "No Agents are configured in %s\n",config);
01887    else 
01888       ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01889    ast_cli(a->fd, "\n");
01890                    
01891    return CLI_SUCCESS;
01892 }

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

Definition at line 1895 of file chan_agent.c.

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

01896 {
01897    struct agent_pvt *p;
01898    char username[AST_MAX_BUF];
01899    char location[AST_MAX_BUF] = "";
01900    char talkingto[AST_MAX_BUF] = "";
01901    char music[AST_MAX_BUF];
01902    int count_agents = 0;           /* Number of agents configured */
01903    int online_agents = 0;          /* Number of online agents */
01904    int agent_status = 0;           /* 0 means offline, 1 means online */
01905 
01906    switch (cmd) {
01907    case CLI_INIT:
01908       e->command = "agent show online";
01909       e->usage =
01910          "Usage: agent show online\n"
01911          "       Provides a list of all online agents.\n";
01912       return NULL;
01913    case CLI_GENERATE:
01914       return NULL;
01915    }
01916 
01917    if (a->argc != 3)
01918       return CLI_SHOWUSAGE;
01919 
01920    AST_LIST_LOCK(&agents);
01921    AST_LIST_TRAVERSE(&agents, p, list) {
01922       agent_status = 0;       /* reset it to offline */
01923       ast_mutex_lock(&p->lock);
01924       if (!ast_strlen_zero(p->name))
01925          snprintf(username, sizeof(username), "(%s) ", p->name);
01926       else
01927          username[0] = '\0';
01928       if (p->chan) {
01929          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01930          if (p->owner && ast_bridged_channel(p->owner)) 
01931             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01932          else 
01933             strcpy(talkingto, " is idle");
01934          agent_status = 1;
01935          online_agents++;
01936       } else if (!ast_strlen_zero(p->loginchan)) {
01937          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01938          talkingto[0] = '\0';
01939          agent_status = 1;
01940          online_agents++;
01941          if (p->acknowledged)
01942             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01943       }
01944       if (!ast_strlen_zero(p->moh))
01945          snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
01946       if (agent_status)
01947          ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
01948       count_agents++;
01949       ast_mutex_unlock(&p->lock);
01950    }
01951    AST_LIST_UNLOCK(&agents);
01952    if (!count_agents) 
01953       ast_cli(a->fd, "No Agents are configured in %s\n", config);
01954    else
01955       ast_cli(a->fd, "%d agents online\n", online_agents);
01956    ast_cli(a->fd, "\n");
01957    return CLI_SUCCESS;
01958 }

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

Definition at line 1350 of file chan_agent.c.

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

Referenced by login_exec().

01351 {
01352    struct ast_channel *chan=NULL, *parent=NULL;
01353    struct agent_pvt *p;
01354    int res;
01355 
01356    ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
01357    if (needlock)
01358       AST_LIST_LOCK(&agents);
01359    AST_LIST_TRAVERSE(&agents, p, list) {
01360       if (p == newlyavailable) {
01361          continue;
01362       }
01363       ast_mutex_lock(&p->lock);
01364       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01365          ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01366          /* We found a pending call, time to merge */
01367          chan = agent_new(newlyavailable, AST_STATE_DOWN);
01368          parent = p->owner;
01369          p->abouttograb = 1;
01370          ast_mutex_unlock(&p->lock);
01371          break;
01372       }
01373       ast_mutex_unlock(&p->lock);
01374    }
01375    if (needlock)
01376       AST_LIST_UNLOCK(&agents);
01377    if (parent && chan)  {
01378       if (newlyavailable->ackcall > 1) {
01379          /* Don't do beep here */
01380          res = 0;
01381       } else {
01382          ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01383          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01384          ast_debug(3, "Played beep, result '%d'\n", res);
01385          if (!res) {
01386             res = ast_waitstream(newlyavailable->chan, "");
01387             ast_debug(1, "Waited for stream, result '%d'\n", res);
01388          }
01389       }
01390       if (!res) {
01391          /* Note -- parent may have disappeared */
01392          if (p->abouttograb) {
01393             newlyavailable->acknowledged = 1;
01394             /* Safe -- agent lock already held */
01395             ast_setstate(parent, AST_STATE_UP);
01396             ast_setstate(chan, AST_STATE_UP);
01397             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01398             /* Go ahead and mark the channel as a zombie so that masquerade will
01399                destroy it for us, and we need not call ast_hangup */
01400             ast_set_flag(chan, AST_FLAG_ZOMBIE);
01401             ast_channel_masquerade(parent, chan);
01402             p->abouttograb = 0;
01403          } else {
01404             ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
01405             agent_cleanup(newlyavailable);
01406          }
01407       } else {
01408          ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
01409          agent_cleanup(newlyavailable);
01410       }
01411    }
01412    return 0;
01413 }

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

Definition at line 1415 of file chan_agent.c.

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

Referenced by login_exec().

01416 {
01417    struct agent_pvt *p;
01418    int res=0;
01419 
01420    ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
01421    if (needlock)
01422       AST_LIST_LOCK(&agents);
01423    AST_LIST_TRAVERSE(&agents, p, list) {
01424       if (p == newlyavailable) {
01425          continue;
01426       }
01427       ast_mutex_lock(&p->lock);
01428       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01429          ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01430          ast_mutex_unlock(&p->lock);
01431          break;
01432       }
01433       ast_mutex_unlock(&p->lock);
01434    }
01435    if (needlock)
01436       AST_LIST_UNLOCK(&agents);
01437    if (p) {
01438       ast_mutex_unlock(&newlyavailable->lock);
01439       ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01440       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01441       ast_debug(1, "Played beep, result '%d'\n", res);
01442       if (!res) {
01443          res = ast_waitstream(newlyavailable->chan, "");
01444          ast_debug(1, "Waited for stream, result '%d'\n", res);
01445       }
01446       ast_mutex_lock(&newlyavailable->lock);
01447    }
01448    return res;
01449 }

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

Definition at line 1790 of file chan_agent.c.

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

Referenced by agent_logoff_cmd().

01791 {
01792    char *ret = NULL;
01793 
01794    if (pos == 2) {
01795       struct agent_pvt *p;
01796       char name[AST_MAX_AGENT];
01797       int which = 0, len = strlen(word);
01798 
01799       AST_LIST_LOCK(&agents);
01800       AST_LIST_TRAVERSE(&agents, p, list) {
01801          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01802          if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
01803             ret = ast_strdup(name);
01804             break;
01805          }
01806       }
01807       AST_LIST_UNLOCK(&agents);
01808    } else if (pos == 3 && state == 0) 
01809       return ast_strdup("soft");
01810    
01811    return ret;
01812 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2362 of file chan_agent.c.

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

Referenced by agent_hangup(), and agent_logoff_maintenance().

02363 {
02364    struct agent_pvt *cur_agent = NULL;
02365    char buf[256];
02366 
02367    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02368       if (cur_agent->chan)
02369          continue;
02370 
02371       if (!ast_strlen_zero(cur_agent->loginchan)) {
02372          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02373          if (ast_db_put(pa_family, cur_agent->agent, buf))
02374             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02375          else
02376             ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02377       } else {
02378          /* Delete -  no agent or there is an error */
02379          ast_db_del(pa_family, cur_agent->agent);
02380       }
02381    }
02382 }

static struct agent_pvt* find_agent ( char *  agentid  )  [static, read]
Note:
This function expects the agent list to be locked

Definition at line 2485 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02486 {
02487    struct agent_pvt *cur;
02488 
02489    AST_LIST_TRAVERSE(&agents, cur, list) {
02490       if (!strcmp(cur->agent, agentid))
02491          break;   
02492    }
02493 
02494    return cur; 
02495 }

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

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

02498 {
02499    char *parse;    
02500    AST_DECLARE_APP_ARGS(args,
02501       AST_APP_ARG(agentid);
02502       AST_APP_ARG(item);
02503    );
02504    char *tmp;
02505    struct agent_pvt *agent;
02506 
02507    buf[0] = '\0';
02508 
02509    if (ast_strlen_zero(data)) {
02510       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02511       return -1;
02512    }
02513 
02514    parse = ast_strdupa(data);
02515 
02516    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02517    if (!args.item)
02518       args.item = "status";
02519 
02520    AST_LIST_LOCK(&agents);
02521 
02522    if (!(agent = find_agent(args.agentid))) {
02523       AST_LIST_UNLOCK(&agents);
02524       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02525       return -1;
02526    }
02527 
02528    if (!strcasecmp(args.item, "status")) {
02529       char *status = "LOGGEDOUT";
02530       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02531          status = "LOGGEDIN"; 
02532       ast_copy_string(buf, status, len);
02533    } else if (!strcasecmp(args.item, "password")) 
02534       ast_copy_string(buf, agent->password, len);
02535    else if (!strcasecmp(args.item, "name"))
02536       ast_copy_string(buf, agent->name, len);
02537    else if (!strcasecmp(args.item, "mohclass"))
02538       ast_copy_string(buf, agent->moh, len);
02539    else if (!strcasecmp(args.item, "channel")) {
02540       if (agent->chan) {
02541          ast_copy_string(buf, agent->chan->name, len);
02542          tmp = strrchr(buf, '-');
02543          if (tmp)
02544             *tmp = '\0';
02545       } 
02546    } else if (!strcasecmp(args.item, "exten"))
02547       ast_copy_string(buf, agent->loginchan, len); 
02548 
02549    AST_LIST_UNLOCK(&agents);
02550 
02551    return 0;
02552 }

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

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

02568 {
02569    /* Make sure we can register our agent channel type */
02570    if (ast_channel_register(&agent_tech)) {
02571       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02572       return AST_MODULE_LOAD_FAILURE;
02573    }
02574    /* Read in the config */
02575    if (!read_agent_config(0))
02576       return AST_MODULE_LOAD_DECLINE;
02577    if (persistent_agents)
02578       reload_agents();
02579    /* Dialplan applications */
02580    ast_register_application_xml(app, login_exec);
02581    ast_register_application_xml(app3, agentmonitoroutgoing_exec);
02582 
02583    /* Manager commands */
02584    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02585    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02586 
02587    /* CLI Commands */
02588    ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
02589 
02590    /* Dialplan Functions */
02591    ast_custom_function_register(&agent_function);
02592 
02593    return AST_MODULE_LOAD_SUCCESS;
02594 }

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 1981 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_streamfile(), ast_strlen_zero(), ast_true(), ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_verb, ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), agent_pvt::dead, agent_pvt::deferlogoff, agent_pvt::enddtmf, EVENT_FLAG_AGENT, ast_channel::language, agent_pvt::lastdisc, agent_pvt::lock, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event, agent_pvt::moh, ast_channel::name, ast_channel::nativeformats, agent_pvt::owner, parse(), pass, agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, ast_channel::readformat, S_OR, ast_channel::uniqueid, update_cdr, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by load_module().

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

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

Definition at line 1547 of file chan_agent.c.

Referenced by agents_show().

01548 {
01549    int x = ffs(d);
01550 
01551    if (x)
01552       return x - 1;
01553 
01554    return 0;
01555 }

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

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

Referenced by load_module(), and reload().

01181 {
01182    struct ast_config *cfg;
01183    struct ast_config *ucfg;
01184    struct ast_variable *v;
01185    struct agent_pvt *p;
01186    const char *general_val;
01187    const char *catname;
01188    const char *hasagent;
01189    int genhasagent;
01190    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01191 
01192    group = 0;
01193    autologoff = 0;
01194    wrapuptime = 0;
01195    ackcall = 0;
01196    endcall = 1;
01197    cfg = ast_config_load(config, config_flags);
01198    if (!cfg) {
01199       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01200       return 0;
01201    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
01202       return -1;
01203    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
01204       ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
01205       return 0;
01206    }
01207    if ((ucfg = ast_config_load("users.conf", config_flags))) {
01208       if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
01209          ucfg = NULL;
01210       } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
01211          ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
01212          return 0;
01213       }
01214    }
01215 
01216    AST_LIST_LOCK(&agents);
01217    AST_LIST_TRAVERSE(&agents, p, list) {
01218       p->dead = 1;
01219    }
01220    strcpy(moh, "default");
01221    /* set the default recording values */
01222    recordagentcalls = 0;
01223    strcpy(recordformat, "wav");
01224    strcpy(recordformatext, "wav");
01225    urlprefix[0] = '\0';
01226    savecallsin[0] = '\0';
01227 
01228    /* Read in [general] section for persistence */
01229    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
01230       persistent_agents = ast_true(general_val);
01231    multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
01232 
01233    /* Read in the [agents] section */
01234    v = ast_variable_browse(cfg, "agents");
01235    while(v) {
01236       /* Create the interface list */
01237       if (!strcasecmp(v->name, "agent")) {
01238          add_agent(v->value, 0);
01239       } else if (!strcasecmp(v->name, "group")) {
01240          group = ast_get_group(v->value);
01241       } else if (!strcasecmp(v->name, "autologoff")) {
01242          autologoff = atoi(v->value);
01243          if (autologoff < 0)
01244             autologoff = 0;
01245       } else if (!strcasecmp(v->name, "ackcall")) {
01246          if (!strcasecmp(v->value, "always"))
01247             ackcall = 2;
01248          else if (ast_true(v->value))
01249             ackcall = 1;
01250          else
01251             ackcall = 0;
01252       } else if (!strcasecmp(v->name, "endcall")) {
01253          endcall = ast_true(v->value);
01254       } else if (!strcasecmp(v->name, "acceptdtmf")) {
01255          acceptdtmf = *(v->value);
01256          ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
01257       } else if (!strcasecmp(v->name, "enddtmf")) {
01258          enddtmf = *(v->value);
01259       } else if (!strcasecmp(v->name, "wrapuptime")) {
01260          wrapuptime = atoi(v->value);
01261          if (wrapuptime < 0)
01262             wrapuptime = 0;
01263       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01264          maxlogintries = atoi(v->value);
01265          if (maxlogintries < 0)
01266             maxlogintries = 0;
01267       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01268          strcpy(agentgoodbye,v->value);
01269       } else if (!strcasecmp(v->name, "musiconhold")) {
01270          ast_copy_string(moh, v->value, sizeof(moh));
01271       } else if (!strcasecmp(v->name, "updatecdr")) {
01272          if (ast_true(v->value))
01273             updatecdr = 1;
01274          else
01275             updatecdr = 0;
01276       } else if (!strcasecmp(v->name, "autologoffunavail")) {
01277          if (ast_true(v->value))
01278             autologoffunavail = 1;
01279          else
01280             autologoffunavail = 0;
01281       } else if (!strcasecmp(v->name, "recordagentcalls")) {
01282          recordagentcalls = ast_true(v->value);
01283       } else if (!strcasecmp(v->name, "recordformat")) {
01284          ast_copy_string(recordformat, v->value, sizeof(recordformat));
01285          if (!strcasecmp(v->value, "wav49"))
01286             strcpy(recordformatext, "WAV");
01287          else
01288             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01289       } else if (!strcasecmp(v->name, "urlprefix")) {
01290          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01291          if (urlprefix[strlen(urlprefix) - 1] != '/')
01292             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01293       } else if (!strcasecmp(v->name, "savecallsin")) {
01294          if (v->value[0] == '/')
01295             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01296          else
01297             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01298          if (savecallsin[strlen(savecallsin) - 1] != '/')
01299             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01300       } else if (!strcasecmp(v->name, "custom_beep")) {
01301          ast_copy_string(beep, v->value, sizeof(beep));
01302       }
01303       v = v->next;
01304    }
01305    if (ucfg) {
01306       genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01307       catname = ast_category_browse(ucfg, NULL);
01308       while(catname) {
01309          if (strcasecmp(catname, "general")) {
01310             hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01311             if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01312                char tmp[256];
01313                const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01314                const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01315                if (!fullname)
01316                   fullname = "";
01317                if (!secret)
01318                   secret = "";
01319                snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01320                add_agent(tmp, 0);
01321             }
01322          }
01323          catname = ast_category_browse(ucfg, catname);
01324       }
01325       ast_config_destroy(ucfg);
01326    }
01327    AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01328       if (p->dead) {
01329          AST_LIST_REMOVE_CURRENT(list);
01330          /* Destroy if  appropriate */
01331          if (!p->owner) {
01332             if (!p->chan) {
01333                ast_mutex_destroy(&p->lock);
01334                ast_mutex_destroy(&p->app_lock);
01335                ast_cond_destroy(&p->app_complete_cond);
01336                ast_free(p);
01337             } else {
01338                /* Cause them to hang up */
01339                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01340             }
01341          }
01342       }
01343    }
01344    AST_LIST_TRAVERSE_SAFE_END;
01345    AST_LIST_UNLOCK(&agents);
01346    ast_config_destroy(cfg);
01347    return 1;
01348 }

static int reload ( void   )  [static]

Definition at line 2596 of file chan_agent.c.

References read_agent_config(), and reload_agents().

02597 {
02598    if (!read_agent_config(1)) {
02599       if (persistent_agents)
02600          reload_agents();
02601    }
02602    return 0;
02603 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2387 of file chan_agent.c.

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

Referenced by load_module(), and reload().

02388 {
02389    char *agent_num;
02390    struct ast_db_entry *db_tree;
02391    struct ast_db_entry *entry;
02392    struct agent_pvt *cur_agent;
02393    char agent_data[256];
02394    char *parse;
02395    char *agent_chan;
02396    char *agent_callerid;
02397 
02398    db_tree = ast_db_gettree(pa_family, NULL);
02399 
02400    AST_LIST_LOCK(&agents);
02401    for (entry = db_tree; entry; entry = entry->next) {
02402       agent_num = entry->key + strlen(pa_family) + 2;
02403       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02404          ast_mutex_lock(&cur_agent->lock);
02405          if (strcmp(agent_num, cur_agent->agent) == 0)
02406             break;
02407          ast_mutex_unlock(&cur_agent->lock);
02408       }
02409       if (!cur_agent) {
02410          ast_db_del(pa_family, agent_num);
02411          continue;
02412       } else
02413          ast_mutex_unlock(&cur_agent->lock);
02414       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02415          ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02416          parse = agent_data;
02417          agent_chan = strsep(&parse, ";");
02418          agent_callerid = strsep(&parse, ";");
02419          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02420          if (agent_callerid) {
02421             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02422             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02423          } else
02424             cur_agent->logincallerid[0] = '\0';
02425          if (cur_agent->loginstart == 0)
02426             time(&cur_agent->loginstart);
02427          ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 
02428       }
02429    }
02430    AST_LIST_UNLOCK(&agents);
02431    if (db_tree) {
02432       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02433       ast_db_freetree(db_tree);
02434    }
02435 }

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

00848 {
00849    char buf[AST_MAX_BUF];
00850 
00851    /* if there is no Caller ID, nothing to do */
00852    if (ast_strlen_zero(callerid))
00853       return;
00854 
00855    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00856    pbx_builtin_setvar_helper(NULL, buf, agent);
00857 }

static int unload_module ( void   )  [static]

Definition at line 2605 of file chan_agent.c.

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

02606 {
02607    struct agent_pvt *p;
02608    /* First, take us out of the channel loop */
02609    ast_channel_unregister(&agent_tech);
02610    /* Unregister dialplan functions */
02611    ast_custom_function_unregister(&agent_function);   
02612    /* Unregister CLI commands */
02613    ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
02614    /* Unregister dialplan applications */
02615    ast_unregister_application(app);
02616    ast_unregister_application(app3);
02617    /* Unregister manager command */
02618    ast_manager_unregister("Agents");
02619    ast_manager_unregister("AgentLogoff");
02620    /* Unregister channel */
02621    AST_LIST_LOCK(&agents);
02622    /* Hangup all interfaces if they have an owner */
02623    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02624       if (p->owner)
02625          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02626       ast_free(p);
02627    }
02628    AST_LIST_UNLOCK(&agents);
02629    return 0;
02630 }


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

Definition at line 2636 of file chan_agent.c.

char acceptdtmf = DEFAULT_ACCEPTDTMF [static]

Definition at line 211 of file chan_agent.c.

Referenced by play_record_review().

int ackcall [static]

Definition at line 207 of file chan_agent.c.

Initial value:
 {
   .name = "AGENT",
   .read = function_agent,
}

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

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

Definition at line 176 of file chan_agent.c.

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

Definition at line 177 of file chan_agent.c.

Definition at line 2636 of file chan_agent.c.

int autologoff [static]

Definition at line 205 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 210 of file chan_agent.c.

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

Definition at line 223 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]
Initial value:
 {
   AST_CLI_DEFINE(agents_show, "Show status of agents"),
   AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
   AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
}

Definition at line 1965 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

Definition at line 174 of file chan_agent.c.

int endcall [static]

Definition at line 208 of file chan_agent.c.

char enddtmf = DEFAULT_ENDDTMF [static]

Definition at line 212 of file chan_agent.c.

ast_group_t group [static]

Definition at line 204 of file chan_agent.c.

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

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

int maxlogintries = 3 [static]

Definition at line 214 of file chan_agent.c.

char moh[80] = "default" [static]
int multiplelogin = 1 [static]

Definition at line 209 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 195 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 198 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 217 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 218 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 219 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 221 of file chan_agent.c.

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

Definition at line 173 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 222 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 220 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 206 of file chan_agent.c.


Generated by  doxygen 1.6.2