Mon May 14 04:45:23 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 ? 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 ? 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 1779 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_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, 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().

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

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

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

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

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

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

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

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, option_debug, and agent_pvt::wrapuptime.

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) > p->wrapuptime) 
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 2470 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.

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

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_tvnow();
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 1518 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().

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

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

Definition at line 1547 of file chan_agent.c.

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

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

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

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

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

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       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
00997    p->owning_app = pthread_self();
00998    /* After the above step, there should not be any blockers. */
00999    if (p->chan) {
01000       if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
01001          ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
01002          CRASH;
01003       }
01004    }
01005    return tmp;
01006 }

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

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

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

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

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

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

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

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

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

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

Definition at line 1277 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

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

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

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02216 {
02217    static int depwarning = 0;
02218 
02219    if (!depwarning) {
02220       depwarning = 1;
02221 
02222       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02223       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02224       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02225    }
02226 }

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

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

Referenced by load_module().

02237 {
02238    callback_deprecated();
02239 
02240    return __login_exec(chan, data, 1);
02241 }

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

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

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

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

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

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

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

Definition at line 1595 of file chan_agent.c.

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

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

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

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

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

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

Definition at line 2516 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02517 {
02518    struct agent_pvt *cur;
02519 
02520    AST_LIST_TRAVERSE(&agents, cur, list) {
02521       if (!strcmp(cur->agent, agentid))
02522          break;   
02523    }
02524 
02525    return cur; 
02526 }

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

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

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

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

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

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

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02211 {
02212    return __login_exec(chan, data, 0);
02213 }

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

Definition at line 1390 of file chan_agent.c.

01391 {
01392    int x = ffs(d);
01393 
01394    if (x)
01395       return x - 1;
01396 
01397    return 0;
01398 }

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

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

static int reload ( void   )  [static]

Definition at line 2634 of file chan_agent.c.

References read_agent_config(), and reload_agents().

Referenced by reload(), and rpt_do_reload().

02635 {
02636    read_agent_config();
02637    if (persistent_agents)
02638       reload_agents();
02639    return 0;
02640 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

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

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

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

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


Variable Documentation

int ackcall [static]

Definition at line 156 of file chan_agent.c.

struct ast_custom_function agent_function

Definition at line 2580 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 1743 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 1758 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 1748 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 1753 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_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(), 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 1739 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 1735 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 Mon May 14 04:45:24 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1