Fri Aug 24 02:23:49 2007

Asterisk developer's documentation


chan_agent.c File Reference

Implementation of Agents (proxy channel). More...

#include "asterisk.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdlib.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/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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 dependency graph for chan_agent.c:

Go to the source code of this file.

Data Structures

struct  agent_pvt
 Structure representing an agent. More...

Defines

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

Functions

static int __agent_start_monitoring (struct ast_channel *ast, struct agent_pvt *p, int needlock)
static int __login_exec (struct ast_channel *chan, void *data, int callbackmode)
 Log in agent application.
static int action_agent_callback_login (struct mansession *s, const struct message *m)
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 (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 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 int agent_logoff_cmd (int fd, int argc, char **argv)
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_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 int agents_show (int fd, int argc, char **argv)
static int agents_show_online (int fd, int argc, char **argv)
static int allow_multiple_login (char *chan, char *context)
static AST_LIST_HEAD_STATIC (agents, agent_pvt)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,)
static void callback_deprecated (void)
static int callback_exec (struct ast_channel *chan, void *data)
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, 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)
static force_inline int powerof (unsigned int d)
static int read_agent_config (void)
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 int ackcall
ast_custom_function agent_function
static 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 app2 [] = "AgentCallbackLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static struct ast_cli_entry cli_show_agents_deprecated
static struct ast_cli_entry cli_show_agents_online_deprecated
static const char config [] = "agents.conf"
static const char descrip []
static const char descrip2 []
static const char descrip3 []
static int endcall
static ast_group_t group
static const char mandescr_agent_callback_login []
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 char show_agents_online_usage []
static char show_agents_usage []
static const char synopsis [] = "Call agent login"
static const char synopsis2 [] = "Call agent callback login"
static const char synopsis3 [] = "Record agent's outgoing call"
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int wrapuptime


Detailed Description

Implementation of Agents (proxy channel).

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

Definition in file chan_agent.c.


Define Documentation

#define AST_MAX_AGENT   80

Agent ID or Password max length

Definition at line 143 of file chan_agent.c.

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

#define AST_MAX_BUF   256

Definition at line 144 of file chan_agent.c.

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

#define AST_MAX_FILENAME_LEN   256

Definition at line 145 of file chan_agent.c.

Referenced by __login_exec().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

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


Function Documentation

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

Definition at line 402 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, and ast_channel::monitor.

Referenced by agent_start_monitoring(), and agentmonitoroutgoing_exec().

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

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

Log in agent application.

Parameters:
chan 
data 
callbackmode non-zero for AgentCallbackLogin

Definition at line 1782 of file chan_agent.c.

References ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_ack_sleep(), agent_cont_sleep(), agent_logoff_maintenance(), allow_multiple_login(), agent_pvt::app_lock, ast_answer(), AST_APP_ARG, ast_app_getdata(), ast_best_codec(), AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

Referenced by callback_exec(), and login_exec().

01783 {
01784    int res=0;
01785    int tries = 0;
01786    int max_login_tries = maxlogintries;
01787    struct agent_pvt *p;
01788    struct ast_module_user *u;
01789    int login_state = 0;
01790    char user[AST_MAX_AGENT] = "";
01791    char pass[AST_MAX_AGENT];
01792    char agent[AST_MAX_AGENT] = "";
01793    char xpass[AST_MAX_AGENT] = "";
01794    char *errmsg;
01795    char *parse;
01796    AST_DECLARE_APP_ARGS(args,
01797               AST_APP_ARG(agent_id);
01798               AST_APP_ARG(options);
01799               AST_APP_ARG(extension);
01800       );
01801    const char *tmpoptions = NULL;
01802    char *context = NULL;
01803    int play_announcement = 1;
01804    char agent_goodbye[AST_MAX_FILENAME_LEN];
01805    int update_cdr = updatecdr;
01806    char *filename = "agent-loginok";
01807    char tmpchan[AST_MAX_BUF] = "";
01808 
01809    u = ast_module_user_add(chan);
01810 
01811    parse = ast_strdupa(data);
01812 
01813    AST_STANDARD_APP_ARGS(args, parse);
01814 
01815    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
01816 
01817    /* Set Channel Specific Login Overrides */
01818    if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
01819       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
01820       if (max_login_tries < 0)
01821          max_login_tries = 0;
01822       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
01823       if (option_verbose > 2)
01824          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
01825    }
01826    if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
01827       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
01828          update_cdr = 1;
01829       else
01830          update_cdr = 0;
01831       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
01832       if (option_verbose > 2)
01833          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
01834    }
01835    if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
01836       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
01837       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
01838       if (option_verbose > 2)
01839          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
01840    }
01841    /* End Channel Specific Login Overrides */
01842    
01843    if (callbackmode && args.extension) {
01844       parse = args.extension;
01845       args.extension = strsep(&parse, "@");
01846       context = parse;
01847    }
01848 
01849    if (!ast_strlen_zero(args.options)) {
01850       if (strchr(args.options, 's')) {
01851          play_announcement = 0;
01852       }
01853    }
01854 
01855    if (chan->_state != AST_STATE_UP)
01856       res = ast_answer(chan);
01857    if (!res) {
01858       if (!ast_strlen_zero(args.agent_id))
01859          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
01860       else
01861          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
01862    }
01863    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
01864       tries++;
01865       /* Check for password */
01866       AST_LIST_LOCK(&agents);
01867       AST_LIST_TRAVERSE(&agents, p, list) {
01868          if (!strcmp(p->agent, user) && !p->pending)
01869             ast_copy_string(xpass, p->password, sizeof(xpass));
01870       }
01871       AST_LIST_UNLOCK(&agents);
01872       if (!res) {
01873          if (!ast_strlen_zero(xpass))
01874             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
01875          else
01876             pass[0] = '\0';
01877       }
01878       errmsg = "agent-incorrect";
01879 
01880 #if 0
01881       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
01882 #endif      
01883 
01884       /* Check again for accuracy */
01885       AST_LIST_LOCK(&agents);
01886       AST_LIST_TRAVERSE(&agents, p, list) {
01887          ast_mutex_lock(&p->lock);
01888          if (!strcmp(p->agent, user) &&
01889              !strcmp(p->password, pass) && !p->pending) {
01890             login_state = 1; /* Successful Login */
01891 
01892             /* Ensure we can't be gotten until we're done */
01893             gettimeofday(&p->lastdisc, NULL);
01894             p->lastdisc.tv_sec++;
01895 
01896             /* Set Channel Specific Agent Overrides */
01897             if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
01898                if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
01899                   p->ackcall = 2;
01900                else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
01901                   p->ackcall = 1;
01902                else
01903                   p->ackcall = 0;
01904                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
01905                if (option_verbose > 2)
01906                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
01907             }
01908             if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
01909                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
01910                if (p->autologoff < 0)
01911                   p->autologoff = 0;
01912                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
01913                if (option_verbose > 2)
01914                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
01915             }
01916             if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
01917                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
01918                if (p->wrapuptime < 0)
01919                   p->wrapuptime = 0;
01920                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
01921                if (option_verbose > 2)
01922                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
01923             }
01924             /* End Channel Specific Agent Overrides */
01925             if (!p->chan) {
01926                char last_loginchan[80] = "";
01927                long logintime;
01928                snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01929 
01930                if (callbackmode) {
01931                   int pos = 0;
01932                   /* Retrieve login chan */
01933                   for (;;) {
01934                      if (!ast_strlen_zero(args.extension)) {
01935                         ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
01936                         res = 0;
01937                      } else
01938                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
01939                      if (ast_strlen_zero(tmpchan) )
01940                         break;
01941                      if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
01942                         if(!allow_multiple_login(tmpchan,context) ) {
01943                            args.extension = NULL;
01944                            pos = 0;
01945                         } else
01946                            break;
01947                      }
01948                      if (args.extension) {
01949                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
01950                         args.extension = NULL;
01951                         pos = 0;
01952                      } else {
01953                         ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
01954                         res = ast_streamfile(chan, "invalid", chan->language);
01955                         if (!res)
01956                            res = ast_waitstream(chan, AST_DIGIT_ANY);
01957                         if (res > 0) {
01958                            tmpchan[0] = res;
01959                            tmpchan[1] = '\0';
01960                            pos = 1;
01961                         } else {
01962                            tmpchan[0] = '\0';
01963                            pos = 0;
01964                         }
01965                      }
01966                   }
01967                   args.extension = tmpchan;
01968                   if (!res) {
01969                      set_agentbycallerid(p->logincallerid, NULL);
01970                      if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
01971                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
01972                      else {
01973                         ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
01974                         ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
01975                      }
01976                      p->acknowledged = 0;
01977                      if (ast_strlen_zero(p->loginchan)) {
01978                         login_state = 2;
01979                         filename = "agent-loggedoff";
01980                      } else {
01981                         if (chan->cid.cid_num) {
01982                            ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
01983                            set_agentbycallerid(p->logincallerid, p->agent);
01984                         } else
01985                            p->logincallerid[0] = '\0';
01986                      }
01987 
01988                      if(update_cdr && chan->cdr)
01989                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
01990 
01991                   }
01992                } else {
01993                   p->loginchan[0] = '\0';
01994                   p->logincallerid[0] = '\0';
01995                   p->acknowledged = 0;
01996                }
01997                ast_mutex_unlock(&p->lock);
01998                AST_LIST_UNLOCK(&agents);
01999                if( !res && play_announcement==1 )
02000                   res = ast_streamfile(chan, filename, chan->language);
02001                if (!res)
02002                   ast_waitstream(chan, "");
02003                AST_LIST_LOCK(&agents);
02004                ast_mutex_lock(&p->lock);
02005                if (!res) {
02006                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02007                   if (res)
02008                      ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
02009                }
02010                if (!res) {
02011                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02012                   if (res)
02013                      ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
02014                }
02015                /* Check once more just in case */
02016                if (p->chan)
02017                   res = -1;
02018                if (callbackmode && !res) {
02019                   /* Just say goodbye and be done with it */
02020                   if (!ast_strlen_zero(p->loginchan)) {
02021                      if (p->loginstart == 0)
02022                         time(&p->loginstart);
02023                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02024                               "Agent: %s\r\n"
02025                               "Loginchan: %s\r\n"
02026                               "Uniqueid: %s\r\n",
02027                               p->agent, p->loginchan, chan->uniqueid);
02028                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02029                      if (option_verbose > 1)
02030                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02031                      ast_device_state_changed("Agent/%s", p->agent);
02032                      if (persistent_agents)
02033                         dump_agents();
02034                   } else {
02035                      logintime = time(NULL) - p->loginstart;
02036                      p->loginstart = 0;
02037 
02038                      agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
02039                      if (option_verbose > 1)
02040                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
02041                   }
02042                   AST_LIST_UNLOCK(&agents);
02043                   if (!res)
02044                      res = ast_safe_sleep(chan, 500);
02045                   ast_mutex_unlock(&p->lock);
02046                } else if (!res) {
02047                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
02048                      S_OR(p->moh, NULL), 
02049                      !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02050                   if (p->loginstart == 0)
02051                      time(&p->loginstart);
02052                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02053                            "Agent: %s\r\n"
02054                            "Channel: %s\r\n"
02055                            "Uniqueid: %s\r\n",
02056                            p->agent, chan->name, chan->uniqueid);
02057                   if (update_cdr && chan->cdr)
02058                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02059                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02060                   if (option_verbose > 1)
02061                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
02062                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02063                   /* Login this channel and wait for it to go away */
02064                   p->chan = chan;
02065                   if (p->ackcall > 1)
02066                      check_beep(p, 0);
02067                   else
02068                      check_availability(p, 0);
02069                   ast_mutex_unlock(&p->lock);
02070                   AST_LIST_UNLOCK(&agents);
02071                   ast_device_state_changed("Agent/%s", p->agent);
02072                   while (res >= 0) {
02073                      ast_mutex_lock(&p->lock);
02074                      if (p->deferlogoff && p->chan) {
02075                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
02076                         p->deferlogoff = 0;
02077                      }
02078                      if (p->chan != chan)
02079                         res = -1;
02080                      ast_mutex_unlock(&p->lock);
02081                      /* Yield here so other interested threads can kick in. */
02082                      sched_yield();
02083                      if (res)
02084                         break;
02085 
02086                      AST_LIST_LOCK(&agents);
02087                      ast_mutex_lock(&p->lock);
02088                      if (p->lastdisc.tv_sec) {
02089                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02090                            if (option_debug)
02091                               ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
02092                            p->lastdisc = ast_tv(0, 0);
02093                            ast_device_state_changed("Agent/%s", p->agent);
02094                            if (p->ackcall > 1)
02095                               check_beep(p, 0);
02096                            else
02097                               check_availability(p, 0);
02098                         }
02099                      }
02100                      ast_mutex_unlock(&p->lock);
02101                      AST_LIST_UNLOCK(&agents);
02102                      /* Synchronize channel ownership between call to agent and itself. */
02103                      ast_mutex_lock( &p->app_lock );
02104                      ast_mutex_lock(&p->lock);
02105                      p->owning_app = pthread_self();
02106                      ast_mutex_unlock(&p->lock);
02107                      if (p->ackcall > 1) 
02108                         res = agent_ack_sleep(p);
02109                      else
02110                         res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02111                      ast_mutex_unlock( &p->app_lock );
02112                      if ((p->ackcall > 1)  && (res == 1)) {
02113                         AST_LIST_LOCK(&agents);
02114                         ast_mutex_lock(&p->lock);
02115                         check_availability(p, 0);
02116                         ast_mutex_unlock(&p->lock);
02117                         AST_LIST_UNLOCK(&agents);
02118                         res = 0;
02119                      }
02120                      sched_yield();
02121                   }
02122                   ast_mutex_lock(&p->lock);
02123                   if (res && p->owner) 
02124                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
02125                   /* Log us off if appropriate */
02126                   if (p->chan == chan)
02127                      p->chan = NULL;
02128                   p->acknowledged = 0;
02129                   logintime = time(NULL) - p->loginstart;
02130                   p->loginstart = 0;
02131                   ast_mutex_unlock(&p->lock);
02132                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02133                            "Agent: %s\r\n"
02134                            "Logintime: %ld\r\n"
02135                            "Uniqueid: %s\r\n",
02136                            p->agent, logintime, chan->uniqueid);
02137                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02138                   if (option_verbose > 1)
02139                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
02140                   /* If there is no owner, go ahead and kill it now */
02141                   ast_device_state_changed("Agent/%s", p->agent);
02142                   if (p->dead && !p->owner) {
02143                      ast_mutex_destroy(&p->lock);
02144                      ast_mutex_destroy(&p->app_lock);
02145                      free(p);
02146                   }
02147                }
02148                else {
02149                   ast_mutex_unlock(&p->lock);
02150                   p = NULL;
02151                }
02152                res = -1;
02153             } else {
02154                ast_mutex_unlock(&p->lock);
02155                errmsg = "agent-alreadyon";
02156                p = NULL;
02157             }
02158             break;
02159          }
02160          ast_mutex_unlock(&p->lock);
02161       }
02162       if (!p)
02163          AST_LIST_UNLOCK(&agents);
02164 
02165       if (!res && (max_login_tries==0 || tries < max_login_tries))
02166          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02167    }
02168       
02169    if (!res)
02170       res = ast_safe_sleep(chan, 500);
02171 
02172    /* AgentLogin() exit */
02173    if (!callbackmode) {
02174       ast_module_user_remove(u);
02175       return -1;
02176    } else { /* AgentCallbackLogin() exit*/
02177       /* Set variables */
02178       if (login_state > 0) {
02179          pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
02180          if (login_state==1) {
02181             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
02182             pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
02183          } else 
02184             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
02185       } else {
02186          pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
02187       }
02188       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
02189          ast_module_user_remove(u);
02190          return 0;
02191       }
02192       /* Do we need to play agent-goodbye now that we will be hanging up? */
02193       if (play_announcement) {
02194          if (!res)
02195             res = ast_safe_sleep(chan, 1000);
02196          res = ast_streamfile(chan, agent_goodbye, chan->language);
02197          if (!res)
02198             res = ast_waitstream(chan, "");
02199          if (!res)
02200             res = ast_safe_sleep(chan, 1000);
02201       }
02202    }
02203 
02204    ast_module_user_remove(u);
02205    
02206    /* We should never get here if next priority exists when in callbackmode */
02207    return -1;
02208 }

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

Sets an agent as logged in by callback 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(), action_agent_logoff(), load_module().

Definition at line 2259 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, ast_device_state_changed(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_strlen_zero(), ast_true(), ast_verbose(), astman_get_header(), astman_send_ack(), astman_send_error(), callback_deprecated(), agent_pvt::chan, context, dump_agents(), EVENT_FLAG_AGENT, exten, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), option_verbose, agent_pvt::pending, s, VERBOSE_PREFIX_2, and agent_pvt::wrapuptime.

Referenced by load_module().

02260 {
02261    const char *agent = astman_get_header(m, "Agent");
02262    const char *exten = astman_get_header(m, "Exten");
02263    const char *context = astman_get_header(m, "Context");
02264    const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02265    const char *ackcall_s = astman_get_header(m, "AckCall");
02266    struct agent_pvt *p;
02267    int login_state = 0;
02268 
02269    callback_deprecated();
02270 
02271    if (ast_strlen_zero(agent)) {
02272       astman_send_error(s, m, "No agent specified");
02273       return 0;
02274    }
02275 
02276    if (ast_strlen_zero(exten)) {
02277       astman_send_error(s, m, "No extension specified");
02278       return 0;
02279    }
02280 
02281    AST_LIST_LOCK(&agents);
02282    AST_LIST_TRAVERSE(&agents, p, list) {
02283       if (strcmp(p->agent, agent) || p->pending) 
02284          continue;
02285       if (p->chan) {
02286          login_state = 2; /* already logged in (and on the phone)*/
02287          break;
02288       }
02289       ast_mutex_lock(&p->lock);
02290       login_state = 1; /* Successful Login */
02291       
02292       if (ast_strlen_zero(context))
02293          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02294       else
02295          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02296 
02297       if (!ast_strlen_zero(wrapuptime_s)) {
02298          p->wrapuptime = atoi(wrapuptime_s);
02299          if (p->wrapuptime < 0)
02300             p->wrapuptime = 0;
02301       }
02302 
02303       if (ast_true(ackcall_s))
02304          p->ackcall = 1;
02305       else
02306          p->ackcall = 0;
02307 
02308       if (p->loginstart == 0)
02309          time(&p->loginstart);
02310       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02311                "Agent: %s\r\n"
02312                "Loginchan: %s\r\n",
02313                p->agent, p->loginchan);
02314       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02315       if (option_verbose > 1)
02316          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02317       ast_device_state_changed("Agent/%s", p->agent);
02318       ast_mutex_unlock(&p->lock);
02319       if (persistent_agents)
02320          dump_agents();
02321    }
02322    AST_LIST_UNLOCK(&agents);
02323 
02324    if (login_state == 1)
02325       astman_send_ack(s, m, "Agent logged in");
02326    else if (login_state == 0)
02327       astman_send_error(s, m, "No such agent");
02328    else if (login_state == 2)
02329       astman_send_error(s, m, "Agent already logged in");
02330 
02331    return 0;
02332 }

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(), action_agent_callback_login(), load_module().

Definition at line 1576 of file chan_agent.c.

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

Referenced by load_module().

01577 {
01578    const char *agent = astman_get_header(m, "Agent");
01579    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01580    int soft;
01581    int ret; /* return value of agent_logoff */
01582 
01583    if (ast_strlen_zero(agent)) {
01584       astman_send_error(s, m, "No agent specified");
01585       return 0;
01586    }
01587 
01588    soft = ast_true(soft_s) ? 1 : 0;
01589    ret = agent_logoff(agent, soft);
01590    if (ret == 0)
01591       astman_send_ack(s, m, "Agent logged out");
01592    else
01593       astman_send_error(s, m, "No such agent");
01594 
01595    return 0;
01596 }

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(), action_agent_callback_login(), load_module().

Definition at line 1411 of file chan_agent.c.

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

Referenced by load_module().

01412 {
01413    const char *id = astman_get_header(m,"ActionID");
01414    char idText[256] = "";
01415    char chanbuf[256];
01416    struct agent_pvt *p;
01417    char *username = NULL;
01418    char *loginChan = NULL;
01419    char *talkingtoChan = NULL;
01420    char *status = NULL;
01421 
01422    if (!ast_strlen_zero(id))
01423       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01424    astman_send_ack(s, m, "Agents will follow");
01425    AST_LIST_LOCK(&agents);
01426    AST_LIST_TRAVERSE(&agents, p, list) {
01427          ast_mutex_lock(&p->lock);
01428 
01429       /* Status Values:
01430          AGENT_LOGGEDOFF - Agent isn't logged in
01431          AGENT_IDLE      - Agent is logged in, and waiting for call
01432          AGENT_ONCALL    - Agent is logged in, and on a call
01433          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01434 
01435       username = S_OR(p->name, "None");
01436 
01437       /* Set a default status. It 'should' get changed. */
01438       status = "AGENT_UNKNOWN";
01439 
01440       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01441          loginChan = p->loginchan;
01442          talkingtoChan = "n/a";
01443          status = "AGENT_IDLE";
01444          if (p->acknowledged) {
01445             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01446             loginChan = chanbuf;
01447          }
01448       } else if (p->chan) {
01449          loginChan = ast_strdupa(p->chan->name);
01450          if (p->owner && p->owner->_bridge) {
01451                talkingtoChan = p->chan->cid.cid_num;
01452                status = "AGENT_ONCALL";
01453          } else {
01454                talkingtoChan = "n/a";
01455                status = "AGENT_IDLE";
01456          }
01457       } else {
01458          loginChan = "n/a";
01459          talkingtoChan = "n/a";
01460          status = "AGENT_LOGGEDOFF";
01461       }
01462 
01463       astman_append(s, "Event: Agents\r\n"
01464          "Agent: %s\r\n"
01465          "Name: %s\r\n"
01466          "Status: %s\r\n"
01467          "LoggedInChan: %s\r\n"
01468          "LoggedInTime: %d\r\n"
01469          "TalkingTo: %s\r\n"
01470          "%s"
01471          "\r\n",
01472          p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
01473       ast_mutex_unlock(&p->lock);
01474    }
01475    AST_LIST_UNLOCK(&agents);
01476    astman_append(s, "Event: AgentsComplete\r\n"
01477       "%s"
01478       "\r\n",idText);
01479    return 0;
01480 }

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

Adds an agent to the global list of agents.

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

Definition at line 286 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, AST_APP_ARG, ast_calloc, AST_DECLARE_APP_ARGS, AST_LIST_INSERT_TAIL, AST_LIST_TRAVERSE, ast_log(), ast_mutex_init(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), agent_pvt::autologoff, agent_pvt::dead, agent_pvt::lastdisc, LOG_WARNING, agent_pvt::moh, agent_pvt::name, parse(), agent_pvt::password, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 855 of file chan_agent.c.

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

Referenced by __login_exec().

00856 {
00857    struct agent_pvt *p;
00858    int res=0;
00859    int to = 1000;
00860    struct ast_frame *f;
00861 
00862    /* Wait a second and look for something */
00863 
00864    p = (struct agent_pvt *) data;
00865    if (!p->chan) 
00866       return -1;
00867 
00868    for(;;) {
00869       to = ast_waitfor(p->chan, to);
00870       if (to < 0) 
00871          return -1;
00872       if (!to) 
00873          return 0;
00874       f = ast_read(p->chan);
00875       if (!f) 
00876          return -1;
00877       if (f->frametype == AST_FRAME_DTMF)
00878          res = f->subclass;
00879       else
00880          res = 0;
00881       ast_frfree(f);
00882       ast_mutex_lock(&p->lock);
00883       if (!p->app_sleep_cond) {
00884          ast_mutex_unlock(&p->lock);
00885          return 0;
00886       } else if (res == '#') {
00887          ast_mutex_unlock(&p->lock);
00888          return 1;
00889       }
00890       ast_mutex_unlock(&p->lock);
00891       res = 0;
00892    }
00893    return res;
00894 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 396 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00397 {
00398    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00399    return -1;
00400 }

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

Definition at line 896 of file chan_agent.c.

References ast_channel::_bridge, ast_log(), agent_pvt::chan, LOG_DEBUG, option_debug, and ast_channel::tech_pvt.

00897 {
00898    struct agent_pvt *p = bridge->tech_pvt;
00899    struct ast_channel *ret = NULL;
00900 
00901    if (p) {
00902       if (chan == p->chan)
00903          ret = bridge->_bridge;
00904       else if (chan == bridge->_bridge)
00905          ret = p->chan;
00906    }
00907 
00908    if (option_debug)
00909       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
00910    return ret;
00911 }

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

Definition at line 629 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_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_verbose(), ast_waitstream(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLEANUP, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::pending, agent_pvt::start, ast_channel::tech_pvt, and VERBOSE_PREFIX_3.

00630 {
00631    struct agent_pvt *p = ast->tech_pvt;
00632    int res = -1;
00633    int newstate=0;
00634    ast_mutex_lock(&p->lock);
00635    p->acknowledged = 0;
00636    if (!p->chan) {
00637       if (p->pending) {
00638          ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
00639          newstate = AST_STATE_DIALING;
00640          res = 0;
00641       } else {
00642          ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
00643          res = -1;
00644       }
00645       ast_mutex_unlock(&p->lock);
00646       if (newstate)
00647          ast_setstate(ast, newstate);
00648       return res;
00649    } else if (!ast_strlen_zero(p->loginchan)) {
00650       time(&p->start);
00651       /* Call on this agent */
00652       if (option_verbose > 2)
00653          ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
00654       ast_set_callerid(p->chan,
00655          ast->cid.cid_num, ast->cid.cid_name, NULL);
00656       ast_channel_inherit_variables(ast, p->chan);
00657       res = ast_call(p->chan, p->loginchan, 0);
00658       CLEANUP(ast,p);
00659       ast_mutex_unlock(&p->lock);
00660       return res;
00661    }
00662    ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
00663    if (option_debug > 2)
00664       ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
00665    res = ast_streamfile(p->chan, beep, p->chan->language);
00666    if (option_debug > 2)
00667       ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
00668    if (!res) {
00669       res = ast_waitstream(p->chan, "");
00670       if (option_debug > 2)
00671          ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
00672    }
00673    if (!res) {
00674       res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
00675       if (option_debug > 2)
00676          ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
00677       if (res)
00678          ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00679    } else {
00680       /* Agent hung-up */
00681       p->chan = NULL;
00682    }
00683 
00684    if (!res) {
00685       res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
00686       if (option_debug > 2)
00687          ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
00688       if (res)
00689          ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
00690    }
00691    if(!res) {
00692       /* Call is immediately up, or might need ack */
00693       if (p->ackcall > 1)
00694          newstate = AST_STATE_RINGING;
00695       else {
00696          newstate = AST_STATE_UP;
00697          if (recordagentcalls)
00698             agent_start_monitoring(ast, 0);
00699          p->acknowledged = 1;
00700       }
00701       res = 0;
00702    }
00703    CLEANUP(ast, p);
00704    ast_mutex_unlock(&p->lock);
00705    if (newstate)
00706       ast_setstate(ast, newstate);
00707    return res;
00708 }

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

References agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_free(), ast_mutex_destroy(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::dead, free, agent_pvt::lock, agent_pvt::owner, and ast_channel::tech_pvt.

Referenced by check_availability().

00377 {
00378    struct ast_channel *chan = p->owner;
00379    p->owner = NULL;
00380    chan->tech_pvt = NULL;
00381    p->app_sleep_cond = 1;
00382    /* Release ownership of the agent to other threads (presumably running the login app). */
00383    ast_mutex_unlock(&p->app_lock);
00384    if (chan)
00385       ast_channel_free(chan);
00386    if (p->dead) {
00387       ast_mutex_destroy(&p->lock);
00388       ast_mutex_destroy(&p->app_lock);
00389       free(p);
00390         }
00391    return 0;
00392 }

static int agent_cont_sleep ( void *  data  )  [static]

Definition at line 834 of file chan_agent.c.

References agent_pvt::app_sleep_cond, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, and option_debug.

Referenced by __login_exec().

00835 {
00836    struct agent_pvt *p;
00837    int res;
00838 
00839    p = (struct agent_pvt *)data;
00840 
00841    ast_mutex_lock(&p->lock);
00842    res = p->app_sleep_cond;
00843    if (p->lastdisc.tv_sec) {
00844       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00845          res = 1;
00846    }
00847    ast_mutex_unlock(&p->lock);
00848 
00849    if(option_debug > 4 && !res )
00850       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00851 
00852    return res;
00853 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

02479 {
02480    struct agent_pvt *p;
02481    char *s;
02482    ast_group_t groupmatch;
02483    int groupoff;
02484    int waitforagent=0;
02485    int res = AST_DEVICE_INVALID;
02486    
02487    s = data;
02488    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
02489       groupmatch = (1 << groupoff);
02490    else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02491       groupmatch = (1 << groupoff);
02492       waitforagent = 1;
02493    } else 
02494       groupmatch = 0;
02495 
02496    /* Check actual logged in agents first */
02497    AST_LIST_LOCK(&agents);
02498    AST_LIST_TRAVERSE(&agents, p, list) {
02499       ast_mutex_lock(&p->lock);
02500       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02501          if (p->owner) {
02502             if (res != AST_DEVICE_INUSE)
02503                res = AST_DEVICE_BUSY;
02504          } else {
02505             if (res == AST_DEVICE_BUSY)
02506                res = AST_DEVICE_INUSE;
02507             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02508                if (res == AST_DEVICE_INVALID)
02509                   res = AST_DEVICE_UNKNOWN;
02510             } else if (res == AST_DEVICE_INVALID)  
02511                res = AST_DEVICE_UNAVAILABLE;
02512          }
02513          if (!strcmp(data, p->agent)) {
02514             ast_mutex_unlock(&p->lock);
02515             break;
02516          }
02517       }
02518       ast_mutex_unlock(&p->lock);
02519    }
02520    AST_LIST_UNLOCK(&agents);
02521    return res;
02522 }

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

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

00612 {
00613    struct agent_pvt *p = ast->tech_pvt;
00614    ast_mutex_lock(&p->lock);
00615    ast_senddigit_begin(p->chan, digit);
00616    ast_mutex_unlock(&p->lock);
00617    return 0;
00618 }

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

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

00621 {
00622    struct agent_pvt *p = ast->tech_pvt;
00623    ast_mutex_lock(&p->lock);
00624    ast_senddigit_end(p->chan, digit, duration);
00625    ast_mutex_unlock(&p->lock);
00626    return 0;
00627 }

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

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

00585 {
00586    struct agent_pvt *p = newchan->tech_pvt;
00587    ast_mutex_lock(&p->lock);
00588    if (p->owner != oldchan) {
00589       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00590       ast_mutex_unlock(&p->lock);
00591       return -1;
00592    }
00593    p->owner = newchan;
00594    ast_mutex_unlock(&p->lock);
00595    return 0;
00596 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 723 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_lock, agent_pvt::app_sleep_cond, ast_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, ast_device_state_changed(), 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_softhangup(), AST_SOFTHANGUP_EXPLICIT, ast_state2str(), AST_STATE_RESERVED, AST_STATE_UP, ast_strlen_zero(), ast_tvadd(), agent_pvt::autologoff, agent_pvt::chan, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), free, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::moh, agent_pvt::name, option_debug, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, agent_pvt::start, ast_channel::tech_pvt, and agent_pvt::wrapuptime.

00724 {
00725    struct agent_pvt *p = ast->tech_pvt;
00726    int howlong = 0;
00727    const char *status;
00728    ast_mutex_lock(&p->lock);
00729    p->owner = NULL;
00730    ast->tech_pvt = NULL;
00731    p->app_sleep_cond = 1;
00732    p->acknowledged = 0;
00733 
00734    /* if they really are hung up then set start to 0 so the test
00735     * later if we're called on an already downed channel
00736     * doesn't cause an agent to be logged out like when
00737     * agent_request() is followed immediately by agent_hangup()
00738     * as in apps/app_chanisavail.c:chanavail_exec()
00739     */
00740 
00741    if (option_debug)
00742       ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
00743    if (p->start && (ast->_state != AST_STATE_UP)) {
00744       howlong = time(NULL) - p->start;
00745       p->start = 0;
00746    } else if (ast->_state == AST_STATE_RESERVED) 
00747       howlong = 0;
00748    else
00749       p->start = 0; 
00750    if (p->chan) {
00751       p->chan->_bridge = NULL;
00752       /* If they're dead, go ahead and hang up on the agent now */
00753       if (!ast_strlen_zero(p->loginchan)) {
00754          /* Store last disconnect time */
00755          if (p->wrapuptime)
00756             p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00757          else
00758             p->lastdisc = ast_tv(0,0);
00759          if (p->chan) {
00760             status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
00761             if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
00762                long logintime = time(NULL) - p->loginstart;
00763                p->loginstart = 0;
00764                ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
00765                agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
00766             }
00767             /* Recognize the hangup and pass it along immediately */
00768             ast_hangup(p->chan);
00769             p->chan = NULL;
00770          }
00771          ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
00772          if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
00773             long logintime = time(NULL) - p->loginstart;
00774             p->loginstart = 0;
00775             if (!p->deferlogoff)
00776                ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
00777             p->deferlogoff = 0;
00778             agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
00779             if (persistent_agents)
00780                dump_agents();
00781          }
00782       } else if (p->dead) {
00783          ast_channel_lock(p->chan);
00784          ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
00785          ast_channel_unlock(p->chan);
00786       } else if (p->loginstart) {
00787          ast_channel_lock(p->chan);
00788          ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
00789             S_OR(p->moh, NULL),
00790             !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
00791          ast_channel_unlock(p->chan);
00792       }
00793    }
00794    ast_mutex_unlock(&p->lock);
00795 
00796    /* Only register a device state change if the agent is still logged in */
00797    if (!p->loginstart) {
00798       p->loginchan[0] = '\0';
00799       p->logincallerid[0] = '\0';
00800       if (persistent_agents)
00801          dump_agents();
00802    } else {
00803       ast_device_state_changed("Agent/%s", p->agent);
00804    }
00805 
00806    if (p->pending) {
00807       AST_LIST_LOCK(&agents);
00808       AST_LIST_REMOVE(&agents, p, list);
00809       AST_LIST_UNLOCK(&agents);
00810    }
00811    if (p->abouttograb) {
00812       /* Let the "about to grab" thread know this isn't valid anymore, and let it
00813          kill it later */
00814       p->abouttograb = 0;
00815    } else if (p->dead) {
00816       ast_mutex_destroy(&p->lock);
00817       ast_mutex_destroy(&p->app_lock);
00818       free(p);
00819    } else {
00820       if (p->chan) {
00821          /* Not dead -- check availability now */
00822          ast_mutex_lock(&p->lock);
00823          /* Store last disconnect time */
00824          p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
00825          ast_mutex_unlock(&p->lock);
00826       }
00827       /* Release ownership of the agent to other threads (presumably running the login app). */
00828       if (ast_strlen_zero(p->loginchan))
00829          ast_mutex_unlock(&p->app_lock);
00830    }
00831    return 0;
00832 }

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

Definition at line 598 of file chan_agent.c.

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

00599 {
00600    struct agent_pvt *p = ast->tech_pvt;
00601    int res = -1;
00602    ast_mutex_lock(&p->lock);
00603    if (p->chan)
00604       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00605    else
00606       res = 0;
00607    ast_mutex_unlock(&p->lock);
00608    return res;
00609 }

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

Definition at line 1521 of file chan_agent.c.

References agent_pvt::agent, agent_logoff_maintenance(), AST_LIST_TRAVERSE, ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, agent_pvt::chan, agent_pvt::deferlogoff, agent_pvt::loginchan, agent_pvt::loginstart, and agent_pvt::owner.

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01522 {
01523    struct agent_pvt *p;
01524    long logintime;
01525    int ret = -1; /* Return -1 if no agent if found */
01526 
01527    AST_LIST_TRAVERSE(&agents, p, list) {
01528       if (!strcasecmp(p->agent, agent)) {
01529          ret = 0;
01530          if (p->owner || p->chan) {
01531             if (!soft) {
01532                if (p->owner)
01533                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01534                if (p->chan)
01535                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01536             } else
01537                p->deferlogoff = 1;
01538          } else {
01539             logintime = time(NULL) - p->loginstart;
01540             p->loginstart = 0;
01541             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01542          }
01543          break;
01544       }
01545    }
01546 
01547    return ret;
01548 }

static int agent_logoff_cmd ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 1550 of file chan_agent.c.

References agent_pvt::agent, agent_logoff(), ast_cli(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

01551 {
01552    int ret;
01553    char *agent;
01554 
01555    if (argc < 3 || argc > 4)
01556       return RESULT_SHOWUSAGE;
01557    if (argc == 4 && strcasecmp(argv[3], "soft"))
01558       return RESULT_SHOWUSAGE;
01559 
01560    agent = argv[2] + 6;
01561    ret = agent_logoff(agent, argc == 4);
01562    if (ret == 0)
01563       ast_cli(fd, "Logging out %s\n", agent);
01564 
01565    return RESULT_SUCCESS;
01566 }

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

Definition at line 1482 of file chan_agent.c.

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

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

01483 {
01484    char *tmp = NULL;
01485    char agent[AST_MAX_AGENT];
01486 
01487    if (!ast_strlen_zero(logcommand))
01488       tmp = logcommand;
01489    else
01490       tmp = ast_strdupa("");
01491 
01492    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01493 
01494    if (!ast_strlen_zero(uniqueid)) {
01495       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01496             "Agent: %s\r\n"
01497             "Reason: %s\r\n"
01498             "Loginchan: %s\r\n"
01499             "Logintime: %ld\r\n"
01500             "Uniqueid: %s\r\n", 
01501             p->agent, tmp, loginchan, logintime, uniqueid);
01502    } else {
01503       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01504             "Agent: %s\r\n"
01505             "Reason: %s\r\n"
01506             "Loginchan: %s\r\n"
01507             "Logintime: %ld\r\n",
01508             p->agent, tmp, loginchan, logintime);
01509    }
01510 
01511    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01512    set_agentbycallerid(p->logincallerid, NULL);
01513    p->loginchan[0] ='\0';
01514    p->logincallerid[0] = '\0';
01515    ast_device_state_changed("Agent/%s", p->agent);
01516    if (persistent_agents)
01517       dump_agents(); 
01518 
01519 }

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

Create new agent channel.

Definition at line 914 of file chan_agent.c.

References agent_pvt::agent, agent_tech, agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_channel_alloc(), ast_channel_free(), AST_CONTROL_UNHOLD, AST_FLAG_BLOCKING, AST_FORMAT_SLINEAR, ast_indicate(), ast_log(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_null_frame, ast_queue_frame(), ast_random(), ast_string_field_set, ast_strlen_zero(), ast_test_flag, ast_update_use_count(), agent_pvt::chan, ast_channel::context, CRASH, ast_channel::exten, language, agent_pvt::lock, LOG_ERROR, LOG_WARNING, agent_pvt::loginchan, ast_channel::nativeformats, agent_pvt::owner, agent_pvt::owning_app, 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().

00915 {
00916    struct ast_channel *tmp;
00917 #if 0
00918    if (!p->chan) {
00919       ast_log(LOG_WARNING, "No channel? :(\n");
00920       return NULL;
00921    }
00922 #endif   
00923    if (p->pending)
00924       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, ast_random() & 0xffff);
00925    else
00926       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
00927    if (!tmp) {
00928       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
00929       return NULL;
00930    }
00931 
00932    tmp->tech = &agent_tech;
00933    if (p->chan) {
00934       tmp->nativeformats = p->chan->nativeformats;
00935       tmp->writeformat = p->chan->writeformat;
00936       tmp->rawwriteformat = p->chan->writeformat;
00937       tmp->readformat = p->chan->readformat;
00938       tmp->rawreadformat = p->chan->readformat;
00939       ast_string_field_set(tmp, language, p->chan->language);
00940       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
00941       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
00942       /* XXX Is this really all we copy form the originating channel?? */
00943    } else {
00944       tmp->nativeformats = AST_FORMAT_SLINEAR;
00945       tmp->writeformat = AST_FORMAT_SLINEAR;
00946       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
00947       tmp->readformat = AST_FORMAT_SLINEAR;
00948       tmp->rawreadformat = AST_FORMAT_SLINEAR;
00949    }
00950    /* Safe, agentlock already held */
00951    tmp->tech_pvt = p;
00952    p->owner = tmp;
00953    /* XXX: this needs fixing */
00954 #if 0
00955    ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
00956 #endif
00957    ast_update_use_count();
00958    tmp->priority = 1;
00959    /* Wake up and wait for other applications (by definition the login app)
00960     * to release this channel). Takes ownership of the agent channel
00961     * to this thread only.
00962     * For signalling the other thread, ast_queue_frame is used until we
00963     * can safely use signals for this purpose. The pselect() needs to be
00964     * implemented in the kernel for this.
00965     */
00966    p->app_sleep_cond = 0;
00967    if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
00968       if (p->chan) {
00969          ast_queue_frame(p->chan, &ast_null_frame);
00970          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
00971          ast_mutex_lock(&p->app_lock);
00972          ast_mutex_lock(&p->lock);
00973       } else {
00974          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
00975          p->owner = NULL;
00976          tmp->tech_pvt = NULL;
00977          p->app_sleep_cond = 1;
00978          ast_channel_free( tmp );
00979          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
00980          ast_mutex_unlock(&p->app_lock);
00981          return NULL;
00982       }
00983    } else if (!ast_strlen_zero(p->loginchan)) {
00984       if (p->chan)
00985          ast_queue_frame(p->chan, &ast_null_frame);
00986       if (!p->chan) {
00987          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
00988          p->owner = NULL;
00989          tmp->tech_pvt = NULL;
00990          p->app_sleep_cond = 1;
00991          ast_channel_free( tmp );
00992          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
00993          return NULL;
00994       }  
00995    } 
00996    if (p->chan)
00997       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
00998    p->owning_app = pthread_self();
00999    /* After the above step, there should not be any blockers. */
01000    if (p->chan) {
01001       if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
01002          ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
01003          CRASH;
01004       }
01005    }
01006    return tmp;
01007 }

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

Definition at line 435 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, AST_CONTROL_ANSWER, ast_copy_flags, 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_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_verbose(), agent_pvt::chan, CHECK_FORMATS, CLEANUP, f, ast_channel::fdno, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_verbose, pbx_builtin_getvar_helper(), ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

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

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

Part of the Asterisk PBX interface.

Definition at line 1298 of file chan_agent.c.

References add_agent(), agent_pvt::agent, agent_new(), AST_CAUSE_BUSY, AST_CAUSE_UNREGISTERED, 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(), agent_pvt::chan, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::loginchan, option_debug, agent_pvt::owner, agent_pvt::pending, and s.

01299 {
01300    struct agent_pvt *p;
01301    struct ast_channel *chan = NULL;
01302    char *s;
01303    ast_group_t groupmatch;
01304    int groupoff;
01305    int waitforagent=0;
01306    int hasagent = 0;
01307    struct timeval tv;
01308 
01309    s = data;
01310    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01311       groupmatch = (1 << groupoff);
01312    } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01313       groupmatch = (1 << groupoff);
01314       waitforagent = 1;
01315    } else 
01316       groupmatch = 0;
01317 
01318    /* Check actual logged in agents first */
01319    AST_LIST_LOCK(&agents);
01320    AST_LIST_TRAVERSE(&agents, p, list) {
01321       ast_mutex_lock(&p->lock);
01322       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01323           ast_strlen_zero(p->loginchan)) {
01324          if (p->chan)
01325             hasagent++;
01326          tv = ast_tvnow();
01327          if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01328             p->lastdisc = ast_tv(0, 0);
01329             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01330             if (!p->owner && p->chan) {
01331                /* Fixed agent */
01332                chan = agent_new(p, AST_STATE_DOWN);
01333             }
01334             if (chan) {
01335                ast_mutex_unlock(&p->lock);
01336                break;
01337             }
01338          }
01339       }
01340       ast_mutex_unlock(&p->lock);
01341    }
01342    if (!p) {
01343       AST_LIST_TRAVERSE(&agents, p, list) {
01344          ast_mutex_lock(&p->lock);
01345          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01346             if (p->chan || !ast_strlen_zero(p->loginchan))
01347                hasagent++;
01348             tv = ast_tvnow();
01349 #if 0
01350             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
01351 #endif
01352             if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01353                p->lastdisc = ast_tv(0, 0);
01354                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01355                if (!p->owner && p->chan) {
01356                   /* Could still get a fixed agent */
01357                   chan = agent_new(p, AST_STATE_DOWN);
01358                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01359                   /* Adjustable agent */
01360                   p->chan = ast_request("Local", format, p->loginchan, cause);
01361                   if (p->chan)
01362                      chan = agent_new(p, AST_STATE_DOWN);
01363                }
01364                if (chan) {
01365                   ast_mutex_unlock(&p->lock);
01366                   break;
01367                }
01368             }
01369          }
01370          ast_mutex_unlock(&p->lock);
01371       }
01372    }
01373 
01374    if (!chan && waitforagent) {
01375       /* No agent available -- but we're requesting to wait for one.
01376          Allocate a place holder */
01377       if (hasagent) {
01378          if (option_debug)
01379             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01380          p = add_agent(data, 1);
01381          p->group = groupmatch;
01382          chan = agent_new(p, AST_STATE_DOWN);
01383          if (!chan) 
01384             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01385       } else
01386          ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01387    }
01388    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01389    AST_LIST_UNLOCK(&agents);
01390    return chan;
01391 }

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

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

00538 {
00539    struct agent_pvt *p = ast->tech_pvt;
00540    int res = -1;
00541    ast_mutex_lock(&p->lock);
00542    if (p->chan) 
00543       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00544    ast_mutex_unlock(&p->lock);
00545    return res;
00546 }

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

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

00549 {
00550    struct agent_pvt *p = ast->tech_pvt;
00551    int res = -1;
00552    ast_mutex_lock(&p->lock);
00553    if (p->chan) 
00554       res = ast_sendtext(p->chan, text);
00555    ast_mutex_unlock(&p->lock);
00556    return res;
00557 }

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

Definition at line 430 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00431 {
00432    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00433 }

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

Definition at line 559 of file chan_agent.c.

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

00560 {
00561    struct agent_pvt *p = ast->tech_pvt;
00562    int res = -1;
00563    CHECK_FORMATS(ast, p);
00564    ast_mutex_lock(&p->lock);
00565    if (!p->chan) 
00566       res = 0;
00567    else {
00568       if ((f->frametype != AST_FRAME_VOICE) ||
00569           (f->frametype != AST_FRAME_VIDEO) ||
00570           (f->subclass == p->chan->writeformat)) {
00571          res = ast_write(p->chan, f);
00572       } else {
00573          ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00574             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00575             ast->name, p->chan->name);
00576          res = 0;
00577       }
00578    }
00579    CLEANUP(ast, p);
00580    ast_mutex_unlock(&p->lock);
00581    return res;
00582 }

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(), callback_login_exec(), load_module().

Todo:
XXX Needs to check option priorityjump etc etc

Definition at line 2342 of file chan_agent.c.

References __agent_start_monitoring(), agent_pvt::agent, ast_exists_extension(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, ast_verbose(), ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), and VERBOSE_PREFIX_3.

Referenced by load_module().

02343 {
02344    int exitifnoagentid = 0;
02345    int nowarnings = 0;
02346    int changeoutgoing = 0;
02347    int res = 0;
02348    char agent[AST_MAX_AGENT];
02349 
02350    if (data) {
02351       if (strchr(data, 'd'))
02352          exitifnoagentid = 1;
02353       if (strchr(data, 'n'))
02354          nowarnings = 1;
02355       if (strchr(data, 'c'))
02356          changeoutgoing = 1;
02357    }
02358    if (chan->cid.cid_num) {
02359       const char *tmp;
02360       char agentvar[AST_MAX_BUF];
02361       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02362       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02363          struct agent_pvt *p;
02364          ast_copy_string(agent, tmp, sizeof(agent));
02365          AST_LIST_LOCK(&agents);
02366          AST_LIST_TRAVERSE(&agents, p, list) {
02367             if (!strcasecmp(p->agent, tmp)) {
02368                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02369                __agent_start_monitoring(chan, p, 1);
02370                break;
02371             }
02372          }
02373          AST_LIST_UNLOCK(&agents);
02374          
02375       } else {
02376          res = -1;
02377          if (!nowarnings)
02378             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);
02379       }
02380    } else {
02381       res = -1;
02382       if (!nowarnings)
02383          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");
02384    }
02385    /* check if there is n + 101 priority */
02386    /*! \todo XXX Needs to check option priorityjump etc etc */
02387    if (res) {
02388       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02389          chan->priority+=100;
02390          if (option_verbose > 2)
02391             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02392       } else if (exitifnoagentid)
02393          return res;
02394    }
02395    return 0;
02396 }

static int agents_show ( int  fd,
int  argc,
char **  argv 
) [static]

Show agents in cli.

< Number of agents configured

< Number of online agents

< Number of offline agents

Definition at line 1619 of file chan_agent.c.

References agent_pvt::acknowledged, agent_pvt::agent, 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, agent_pvt::group, agent_pvt::lastdisc, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, agent_pvt::pending, powerof(), RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

01620 {
01621    struct agent_pvt *p;
01622    char username[AST_MAX_BUF];
01623    char location[AST_MAX_BUF] = "";
01624    char talkingto[AST_MAX_BUF] = "";
01625    char moh[AST_MAX_BUF];
01626    int count_agents = 0;      /*!< Number of agents configured */
01627    int online_agents = 0;     /*!< Number of online agents */
01628    int offline_agents = 0;    /*!< Number of offline agents */
01629    if (argc != 2)
01630       return RESULT_SHOWUSAGE;
01631    AST_LIST_LOCK(&agents);
01632    AST_LIST_TRAVERSE(&agents, p, list) {
01633       ast_mutex_lock(&p->lock);
01634       if (p->pending) {
01635          if (p->group)
01636             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
01637          else
01638             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01639       } else {
01640          if (!ast_strlen_zero(p->name))
01641             snprintf(username, sizeof(username), "(%s) ", p->name);
01642          else
01643             username[0] = '\0';
01644          if (p->chan) {
01645             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01646             if (p->owner && ast_bridged_channel(p->owner))
01647                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01648              else 
01649                strcpy(talkingto, " is idle");
01650             online_agents++;
01651          } else if (!ast_strlen_zero(p->loginchan)) {
01652             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01653                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01654             else 
01655                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01656             talkingto[0] = '\0';
01657             online_agents++;
01658             if (p->acknowledged)
01659                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01660          } else {
01661             strcpy(location, "not logged in");
01662             talkingto[0] = '\0';
01663             offline_agents++;
01664          }
01665          if (!ast_strlen_zero(p->moh))
01666             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01667          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
01668             username, location, talkingto, moh);
01669          count_agents++;
01670       }
01671       ast_mutex_unlock(&p->lock);
01672    }
01673    AST_LIST_UNLOCK(&agents);
01674    if ( !count_agents ) 
01675       ast_cli(fd, "No Agents are configured in %s\n",config);
01676    else 
01677       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01678    ast_cli(fd, "\n");
01679                    
01680    return RESULT_SUCCESS;
01681 }

static int agents_show_online ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 1684 of file chan_agent.c.

References agent_pvt::acknowledged, agent_pvt::agent, 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, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::moh, agent_pvt::name, agent_pvt::owner, RESULT_SHOWUSAGE, RESULT_SUCCESS, and username.

01685 {
01686    struct agent_pvt *p;
01687    char username[AST_MAX_BUF];
01688    char location[AST_MAX_BUF] = "";
01689    char talkingto[AST_MAX_BUF] = "";
01690    char moh[AST_MAX_BUF];
01691    int count_agents = 0;           /* Number of agents configured */
01692    int online_agents = 0;          /* Number of online agents */
01693    int agent_status = 0;           /* 0 means offline, 1 means online */
01694    if (argc != 3)
01695       return RESULT_SHOWUSAGE;
01696    AST_LIST_LOCK(&agents);
01697    AST_LIST_TRAVERSE(&agents, p, list) {
01698       agent_status = 0;       /* reset it to offline */
01699       ast_mutex_lock(&p->lock);
01700       if (!ast_strlen_zero(p->name))
01701          snprintf(username, sizeof(username), "(%s) ", p->name);
01702       else
01703          username[0] = '\0';
01704       if (p->chan) {
01705          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01706          if (p->owner && ast_bridged_channel(p->owner)) 
01707             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01708          else 
01709             strcpy(talkingto, " is idle");
01710          agent_status = 1;
01711          online_agents++;
01712       } else if (!ast_strlen_zero(p->loginchan)) {
01713          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01714          talkingto[0] = '\0';
01715          agent_status = 1;
01716          online_agents++;
01717          if (p->acknowledged)
01718             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01719       }
01720       if (!ast_strlen_zero(p->moh))
01721          snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01722       if (agent_status)
01723          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01724       count_agents++;
01725       ast_mutex_unlock(&p->lock);
01726    }
01727    AST_LIST_UNLOCK(&agents);
01728    if (!count_agents) 
01729       ast_cli(fd, "No Agents are configured in %s\n", config);
01730    else
01731       ast_cli(fd, "%d agents online\n", online_agents);
01732    ast_cli(fd, "\n");
01733    return RESULT_SUCCESS;
01734 }

static int allow_multiple_login ( char *  chan,
char *  context 
) [static]

Definition at line 1278 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

01279 {
01280    struct agent_pvt *p;
01281    char loginchan[80];
01282 
01283    if(multiplelogin)
01284       return 1;
01285    if(!chan) 
01286       return 0;
01287 
01288    snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01289    
01290    AST_LIST_TRAVERSE(&agents, p, list) {
01291       if(!strcasecmp(chan, p->loginchan))
01292          return 0;
01293    }
01294    return -1;
01295 }

static AST_LIST_HEAD_STATIC ( agents  ,
agent_pvt   
) [static]

Holds the list of agents (loaded form agents.conf).

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT  ,
"Agent Proxy Channel"  ,
load = load_module,
unload = unload_module,
reload = reload 
)

static void callback_deprecated ( void   )  [static]

Definition at line 2223 of file chan_agent.c.

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02224 {
02225    static int depwarning = 0;
02226 
02227    if (!depwarning) {
02228       depwarning = 1;
02229 
02230       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02231       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02232       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02233    }
02234 }

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

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

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

Definition at line 2244 of file chan_agent.c.

References __login_exec(), callback_deprecated(), and ast_module_user::chan.

Referenced by load_module().

02245 {
02246    callback_deprecated();
02247 
02248    return __login_exec(chan, data, 1);
02249 }

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

Definition at line 1164 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_FLAG_ZOMBIE, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), 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, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

01165 {
01166    struct ast_channel *chan=NULL, *parent=NULL;
01167    struct agent_pvt *p;
01168    int res;
01169 
01170    if (option_debug)
01171       ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
01172    if (needlock)
01173       AST_LIST_LOCK(&agents);
01174    AST_LIST_TRAVERSE(&agents, p, list) {
01175       if (p == newlyavailable) {
01176          continue;
01177       }
01178       ast_mutex_lock(&p->lock);
01179       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01180          if (option_debug)
01181             ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01182          /* We found a pending call, time to merge */
01183          chan = agent_new(newlyavailable, AST_STATE_DOWN);
01184          parent = p->owner;
01185          p->abouttograb = 1;
01186          ast_mutex_unlock(&p->lock);
01187          break;
01188       }
01189       ast_mutex_unlock(&p->lock);
01190    }
01191    if (needlock)
01192       AST_LIST_UNLOCK(&agents);
01193    if (parent && chan)  {
01194       if (newlyavailable->ackcall > 1) {
01195          /* Don't do beep here */
01196          res = 0;
01197       } else {
01198          if (option_debug > 2)
01199             ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01200          res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01201          if (option_debug > 2)
01202             ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01203          if (!res) {
01204             res = ast_waitstream(newlyavailable->chan, "");
01205             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01206          }
01207       }
01208       if (!res) {
01209          /* Note -- parent may have disappeared */
01210          if (p->abouttograb) {
01211             newlyavailable->acknowledged = 1;
01212             /* Safe -- agent lock already held */
01213             ast_setstate(parent, AST_STATE_UP);
01214             ast_setstate(chan, AST_STATE_UP);
01215             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01216             /* Go ahead and mark the channel as a zombie so that masquerade will
01217                destroy it for us, and we need not call ast_hangup */
01218             ast_mutex_lock(&parent->lock);
01219             ast_set_flag(chan, AST_FLAG_ZOMBIE);
01220             ast_channel_masquerade(parent, chan);
01221             ast_mutex_unlock(&parent->lock);
01222             p->abouttograb = 0;
01223          } else {
01224             if (option_debug)
01225                ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
01226             agent_cleanup(newlyavailable);
01227          }
01228       } else {
01229          if (option_debug)
01230             ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
01231          agent_cleanup(newlyavailable);
01232       }
01233    }
01234    return 0;
01235 }

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

Definition at line 1237 of file chan_agent.c.

References agent_pvt::abouttograb, agent_pvt::agent, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_streamfile(), ast_waitstream(), agent_pvt::chan, agent_pvt::group, agent_pvt::lock, LOG_DEBUG, option_debug, agent_pvt::owner, and agent_pvt::pending.

Referenced by __login_exec().

01238 {
01239    struct agent_pvt *p;
01240    int res=0;
01241 
01242    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01243    if (needlock)
01244       AST_LIST_LOCK(&agents);
01245    AST_LIST_TRAVERSE(&agents, p, list) {
01246       if (p == newlyavailable) {
01247          continue;
01248       }
01249       ast_mutex_lock(&p->lock);
01250       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01251          if (option_debug)
01252             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01253          ast_mutex_unlock(&p->lock);
01254          break;
01255       }
01256       ast_mutex_unlock(&p->lock);
01257    }
01258    if (needlock)
01259       AST_LIST_UNLOCK(&agents);
01260    if (p) {
01261       ast_mutex_unlock(&newlyavailable->lock);
01262       if (option_debug > 2)
01263          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01264       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01265       if (option_debug > 2)
01266          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01267       if (!res) {
01268          res = ast_waitstream(newlyavailable->chan, "");
01269          if (option_debug)
01270             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01271       }
01272       ast_mutex_lock(&newlyavailable->lock);
01273    }
01274    return res;
01275 }

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

Definition at line 1598 of file chan_agent.c.

References agent_pvt::agent, AST_LIST_TRAVERSE, AST_MAX_AGENT, ast_strdup, len, and agent_pvt::name.

01599 {
01600    if (pos == 2) {
01601       struct agent_pvt *p;
01602       char name[AST_MAX_AGENT];
01603       int which = 0, len = strlen(word);
01604 
01605       AST_LIST_TRAVERSE(&agents, p, list) {
01606          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01607          if (!strncasecmp(word, name, len) && ++which > state)
01608             return ast_strdup(name);
01609       }
01610    } else if (pos == 3 && state == 0) 
01611       return ast_strdup("soft");
01612    
01613    return NULL;
01614 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2401 of file chan_agent.c.

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

Referenced by __login_exec(), action_agent_callback_login(), agent_hangup(), and agent_logoff_maintenance().

02402 {
02403    struct agent_pvt *cur_agent = NULL;
02404    char buf[256];
02405 
02406    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02407       if (cur_agent->chan)
02408          continue;
02409 
02410       if (!ast_strlen_zero(cur_agent->loginchan)) {
02411          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02412          if (ast_db_put(pa_family, cur_agent->agent, buf))
02413             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02414          else if (option_debug)
02415             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02416       } else {
02417          /* Delete -  no agent or there is an error */
02418          ast_db_del(pa_family, cur_agent->agent);
02419       }
02420    }
02421 }

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

Definition at line 2524 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02525 {
02526    struct agent_pvt *cur;
02527 
02528    AST_LIST_TRAVERSE(&agents, cur, list) {
02529       if (!strcmp(cur->agent, agentid))
02530          break;   
02531    }
02532 
02533    return cur; 
02534 }

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

Definition at line 2536 of file chan_agent.c.

References agent_pvt::agent, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), find_agent(), LOG_WARNING, and parse().

02537 {
02538    char *parse;    
02539    AST_DECLARE_APP_ARGS(args,
02540       AST_APP_ARG(agentid);
02541       AST_APP_ARG(item);
02542    );
02543    char *tmp;
02544    struct agent_pvt *agent;
02545 
02546    buf[0] = '\0';
02547 
02548    if (ast_strlen_zero(data)) {
02549       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02550       return -1;
02551    }
02552 
02553    parse = ast_strdupa(data);
02554 
02555    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02556    if (!args.item)
02557       args.item = "status";
02558 
02559    if (!(agent = find_agent(args.agentid))) {
02560       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02561       return -1;
02562    }
02563 
02564    if (!strcasecmp(args.item, "status")) {
02565       char *status = "LOGGEDOUT";
02566       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02567          status = "LOGGEDIN"; 
02568       ast_copy_string(buf, status, len);
02569    } else if (!strcasecmp(args.item, "password")) 
02570       ast_copy_string(buf, agent->password, len);
02571    else if (!strcasecmp(args.item, "name"))
02572       ast_copy_string(buf, agent->name, len);
02573    else if (!strcasecmp(args.item, "mohclass"))
02574       ast_copy_string(buf, agent->moh, len);
02575    else if (!strcasecmp(args.item, "channel")) {
02576       if (agent->chan) {
02577          ast_copy_string(buf, agent->chan->name, len);
02578          tmp = strrchr(buf, '-');
02579          if (tmp)
02580             *tmp = '\0';
02581       } 
02582    } else if (!strcasecmp(args.item, "exten"))
02583       ast_copy_string(buf, agent->loginchan, len); 
02584 
02585    return 0;
02586 }

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

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

02612 {
02613    /* Make sure we can register our agent channel type */
02614    if (ast_channel_register(&agent_tech)) {
02615       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02616       return -1;
02617    }
02618    /* Read in the config */
02619    if (!read_agent_config())
02620       return AST_MODULE_LOAD_DECLINE;
02621    if (persistent_agents)
02622       reload_agents();
02623    /* Dialplan applications */
02624    ast_register_application(app, login_exec, synopsis, descrip);
02625    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02626    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02627 
02628    /* Manager commands */
02629    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02630    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02631    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02632 
02633    /* CLI Commands */
02634    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02635 
02636    /* Dialplan Functions */
02637    ast_custom_function_register(&agent_function);
02638 
02639    return 0;
02640 }

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

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

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

Definition at line 2218 of file chan_agent.c.

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02219 {
02220    return __login_exec(chan, data, 0);
02221 }

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

Definition at line 1393 of file chan_agent.c.

01394 {
01395    int x = ffs(d);
01396 
01397    if (x)
01398       return x - 1;
01399 
01400    return 0;
01401 }

static int read_agent_config ( void   )  [static]

Read configuration data. The file named agents.conf.

Returns:
Always 0, or so it seems.

Definition at line 1015 of file chan_agent.c.

References add_agent(), agent_pvt::app_lock, ast_category_browse(), ast_config_destroy(), ast_config_load(), 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, agent_pvt::dead, free, agent_pvt::lock, LOG_NOTICE, ast_variable::name, ast_variable::next, agent_pvt::owner, secret, and ast_variable::value.

Referenced by load_module(), and reload().

01016 {
01017    struct ast_config *cfg;
01018    struct ast_config *ucfg;
01019    struct ast_variable *v;
01020    struct agent_pvt *p;
01021    const char *general_val;
01022    const char *catname;
01023    const char *hasagent;
01024    int genhasagent;
01025 
01026    group = 0;
01027    autologoff = 0;
01028    wrapuptime = 0;
01029    ackcall = 0;
01030    endcall = 1;
01031    cfg = ast_config_load(config);
01032    if (!cfg) {
01033       ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
01034       return 0;
01035    }
01036    AST_LIST_LOCK(&agents);
01037    AST_LIST_TRAVERSE(&agents, p, list) {
01038       p->dead = 1;
01039    }
01040    strcpy(moh, "default");
01041    /* set the default recording values */
01042    recordagentcalls = 0;
01043    strcpy(recordformat, "wav");
01044    strcpy(recordformatext, "wav");
01045    urlprefix[0] = '\0';
01046    savecallsin[0] = '\0';
01047 
01048    /* Read in [general] section for persistence */
01049    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
01050       persistent_agents = ast_true(general_val);
01051    multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
01052 
01053    /* Read in the [agents] section */
01054    v = ast_variable_browse(cfg, "agents");
01055    while(v) {
01056       /* Create the interface list */
01057       if (!strcasecmp(v->name, "agent")) {
01058          add_agent(v->value, 0);
01059       } else if (!strcasecmp(v->name, "group")) {
01060          group = ast_get_group(v->value);
01061       } else if (!strcasecmp(v->name, "autologoff")) {
01062          autologoff = atoi(v->value);
01063          if (autologoff < 0)
01064             autologoff = 0;
01065       } else if (!strcasecmp(v->name, "ackcall")) {
01066          if (!strcasecmp(v->value, "always"))
01067             ackcall = 2;
01068          else if (ast_true(v->value))
01069             ackcall = 1;
01070          else
01071             ackcall = 0;
01072       } else if (!strcasecmp(v->name, "endcall")) {
01073          endcall = ast_true(v->value);
01074       } else if (!strcasecmp(v->name, "wrapuptime")) {
01075          wrapuptime = atoi(v->value);
01076          if (wrapuptime < 0)
01077             wrapuptime = 0;
01078       } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
01079          maxlogintries = atoi(v->value);
01080          if (maxlogintries < 0)
01081             maxlogintries = 0;
01082       } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
01083          strcpy(agentgoodbye,v->value);
01084       } else if (!strcasecmp(v->name, "musiconhold")) {
01085          ast_copy_string(moh, v->value, sizeof(moh));
01086       } else if (!strcasecmp(v->name, "updatecdr")) {
01087          if (ast_true(v->value))
01088             updatecdr = 1;
01089          else
01090             updatecdr = 0;
01091       } else if (!strcasecmp(v->name, "autologoffunavail")) {
01092          if (ast_true(v->value))
01093             autologoffunavail = 1;
01094          else
01095             autologoffunavail = 0;
01096       } else if (!strcasecmp(v->name, "recordagentcalls")) {
01097          recordagentcalls = ast_true(v->value);
01098       } else if (!strcasecmp(v->name, "recordformat")) {
01099          ast_copy_string(recordformat, v->value, sizeof(recordformat));
01100          if (!strcasecmp(v->value, "wav49"))
01101             strcpy(recordformatext, "WAV");
01102          else
01103             ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
01104       } else if (!strcasecmp(v->name, "urlprefix")) {
01105          ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
01106          if (urlprefix[strlen(urlprefix) - 1] != '/')
01107             strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
01108       } else if (!strcasecmp(v->name, "savecallsin")) {
01109          if (v->value[0] == '/')
01110             ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
01111          else
01112             snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
01113          if (savecallsin[strlen(savecallsin) - 1] != '/')
01114             strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
01115       } else if (!strcasecmp(v->name, "custom_beep")) {
01116          ast_copy_string(beep, v->value, sizeof(beep));
01117       }
01118       v = v->next;
01119    }
01120    if ((ucfg = ast_config_load("users.conf"))) {
01121       genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
01122       catname = ast_category_browse(ucfg, NULL);
01123       while(catname) {
01124          if (strcasecmp(catname, "general")) {
01125             hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
01126             if (ast_true(hasagent) || (!hasagent && genhasagent)) {
01127                char tmp[256];
01128                const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
01129                const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
01130                if (!fullname)
01131                   fullname = "";
01132                if (!secret)
01133                   secret = "";
01134                snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
01135                add_agent(tmp, 0);
01136             }
01137          }
01138          catname = ast_category_browse(ucfg, catname);
01139       }
01140       ast_config_destroy(ucfg);
01141    }
01142    AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
01143       if (p->dead) {
01144          AST_LIST_REMOVE_CURRENT(&agents, list);
01145          /* Destroy if  appropriate */
01146          if (!p->owner) {
01147             if (!p->chan) {
01148                ast_mutex_destroy(&p->lock);
01149                ast_mutex_destroy(&p->app_lock);
01150                free(p);
01151             } else {
01152                /* Cause them to hang up */
01153                ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01154             }
01155          }
01156       }
01157    }
01158    AST_LIST_TRAVERSE_SAFE_END
01159    AST_LIST_UNLOCK(&agents);
01160    ast_config_destroy(cfg);
01161    return 1;
01162 }

static int reload ( void   )  [static]

Definition at line 2642 of file chan_agent.c.

References read_agent_config(), and reload_agents().

Referenced by moh_cli(), reload(), and rpt_do_reload().

02643 {
02644    read_agent_config();
02645    if (persistent_agents)
02646       reload_agents();
02647    return 0;
02648 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

Definition at line 2426 of file chan_agent.c.

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

Referenced by load_module(), and reload().

02427 {
02428    char *agent_num;
02429    struct ast_db_entry *db_tree;
02430    struct ast_db_entry *entry;
02431    struct agent_pvt *cur_agent;
02432    char agent_data[256];
02433    char *parse;
02434    char *agent_chan;
02435    char *agent_callerid;
02436 
02437    db_tree = ast_db_gettree(pa_family, NULL);
02438 
02439    AST_LIST_LOCK(&agents);
02440    for (entry = db_tree; entry; entry = entry->next) {
02441       agent_num = entry->key + strlen(pa_family) + 2;
02442       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02443          ast_mutex_lock(&cur_agent->lock);
02444          if (strcmp(agent_num, cur_agent->agent) == 0)
02445             break;
02446          ast_mutex_unlock(&cur_agent->lock);
02447       }
02448       if (!cur_agent) {
02449          ast_db_del(pa_family, agent_num);
02450          continue;
02451       } else
02452          ast_mutex_unlock(&cur_agent->lock);
02453       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02454          if (option_debug)
02455             ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02456          parse = agent_data;
02457          agent_chan = strsep(&parse, ";");
02458          agent_callerid = strsep(&parse, ";");
02459          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02460          if (agent_callerid) {
02461             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02462             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02463          } else
02464             cur_agent->logincallerid[0] = '\0';
02465          if (cur_agent->loginstart == 0)
02466             time(&cur_agent->loginstart);
02467          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02468       }
02469    }
02470    AST_LIST_UNLOCK(&agents);
02471    if (db_tree) {
02472       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02473       ast_db_freetree(db_tree);
02474    }
02475 }

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

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

Referenced by __login_exec(), agent_logoff_maintenance(), and reload_agents().

00712 {
00713    char buf[AST_MAX_BUF];
00714 
00715    /* if there is no Caller ID, nothing to do */
00716    if (ast_strlen_zero(callerid))
00717       return;
00718 
00719    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00720    pbx_builtin_setvar_helper(NULL, buf, agent);
00721 }

static int unload_module ( void   )  [static]

Definition at line 2650 of file chan_agent.c.

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

Referenced by load_module().

02651 {
02652    struct agent_pvt *p;
02653    /* First, take us out of the channel loop */
02654    ast_channel_unregister(&agent_tech);
02655    /* Unregister dialplan functions */
02656    ast_custom_function_unregister(&agent_function);   
02657    /* Unregister CLI commands */
02658    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02659    /* Unregister dialplan applications */
02660    ast_unregister_application(app);
02661    ast_unregister_application(app2);
02662    ast_unregister_application(app3);
02663    /* Unregister manager command */
02664    ast_manager_unregister("Agents");
02665    ast_manager_unregister("AgentLogoff");
02666    ast_manager_unregister("AgentCallbackLogin");
02667    /* Unregister channel */
02668    AST_LIST_LOCK(&agents);
02669    /* Hangup all interfaces if they have an owner */
02670    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02671       if (p->owner)
02672          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02673       free(p);
02674    }
02675    AST_LIST_UNLOCK(&agents);
02676    AST_LIST_HEAD_DESTROY(&agents);
02677    return 0;
02678 }


Variable Documentation

int ackcall [static]

Definition at line 156 of file chan_agent.c.

struct ast_custom_function agent_function

Definition at line 2588 of file chan_agent.c.

Referenced by load_module(), and unload_module().

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

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

Definition at line 79 of file chan_agent.c.

Referenced by action_originate(), add_extensions(), answer_exec_enable(), ast_pbx_run_app(), async_wait(), check_app_args(), check_pval_item(), conf_run(), exec_exec(), execif_exec(), feature_exec_app(), forward_message(), handle_context_add_extension(), handle_context_add_extension_deprecated(), handle_exec(), load_module(), page_exec(), pbx_builtin_execiftime(), pbx_exec(), pbx_extension_helper(), realtime_exec(), try_calling(), tryexec_exec(), and unload_module().

const char app2[] = "AgentCallbackLogin" [static]

Definition at line 80 of file chan_agent.c.

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

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

Definition at line 81 of file chan_agent.c.

Referenced by load_module(), and unload_module().

int autologoff [static]

Definition at line 154 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 159 of file chan_agent.c.

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

Definition at line 170 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]

Definition at line 1761 of file chan_agent.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_show_agents_deprecated [static]

Initial value:

 {
   { "show", "agents", NULL },
   agents_show, NULL,
   NULL, NULL }

Definition at line 1751 of file chan_agent.c.

struct ast_cli_entry cli_show_agents_online_deprecated [static]

Initial value:

 {
   { "show", "agents", "online" },
   agents_show_online, NULL,
   NULL, NULL }

Definition at line 1756 of file chan_agent.c.

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

Definition at line 77 of file chan_agent.c.

Referenced by app_exec(), ast_bridge_call(), ast_category_append(), ast_category_browse(), ast_category_exist(), ast_category_get(), ast_category_root(), ast_channel_bridge(), ast_config_new(), ast_feature_interpret(), ast_generic_bridge(), ast_readconfig(), ast_variable_browse(), ast_variable_retrieve(), builtin_atxfer(), category_get(), cdr_pgsql_connect(), database_first_connect(), do_reload(), load_module(), load_odbc_config(), misdn_cfg_init(), my_load_module(), park_exec(), parse_config(), pbx_load_module(), read_config_maps(), reload(), reload_config(), set_config_flags(), and unload_module().

const char descrip[] [static]

Definition at line 87 of file chan_agent.c.

Referenced by aji_handle_presence(), and load_module().

const char descrip2[] [static]

Definition at line 96 of file chan_agent.c.

Referenced by load_module().

const char descrip3[] [static]

Definition at line 104 of file chan_agent.c.

int endcall [static]

Definition at line 157 of file chan_agent.c.

ast_group_t group [static]

Definition at line 153 of file chan_agent.c.

Referenced by ast_app_group_set_channel(), ast_get_group(), ast_makesocket(), common_exec(), group_count_function_read(), group_match_count_function_read(), main(), misdn_check_l2l1(), and misdn_request().

const char mandescr_agent_callback_login[] [static]

Definition at line 132 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 126 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 122 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 161 of file chan_agent.c.

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

Definition at line 141 of file chan_agent.c.

Referenced by ast_moh_destroy(), ast_moh_destroy_one(), get_mohbyname(), init_classes(), moh_generate(), moh_register(), moh_release(), mohalloc(), and monmp3thread().

int multiplelogin = 1 [static]

Definition at line 158 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 147 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 150 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 164 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 165 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 166 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

Definition at line 168 of file chan_agent.c.

char show_agents_online_usage[] [static]

Initial value:

"Usage: agent show online\n"
"  Provides a list of all online agents.\n"

Definition at line 1742 of file chan_agent.c.

char show_agents_usage[] [static]

Initial value:

 
"Usage: agent show\n"
"       Provides summary information on agents.\n"

Definition at line 1738 of file chan_agent.c.

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

Definition at line 83 of file chan_agent.c.

Referenced by load_module().

const char synopsis2[] = "Call agent callback login" [static]

Definition at line 84 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 85 of file chan_agent.c.

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

Definition at line 76 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 169 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 167 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 155 of file chan_agent.c.


Generated on Fri Aug 24 02:23:50 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1