Sat Apr 12 07:12:35 2008

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 struct ast_channelagent_get_base_channel (struct ast_channel *chan)
 return the channel or base channel if one exists. This function assumes the channel it is called on is already locked
static int agent_hangup (struct ast_channel *ast)
static int agent_indicate (struct ast_channel *ast, int condition, const void *data, size_t datalen)
static int agent_logoff (const char *agent, int soft)
static 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 *dest, const char *text, int ispdu)
static int agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, void *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static 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
struct 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

#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 406 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().

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

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 1826 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_module_user_remove, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, ast_channel::exten, 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, ast_channel::nativeformats, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), agent_pvt::pending, ast_channel::priority, ast_channel::readformat, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, agent_pvt::wrapuptime, and ast_channel::writeformat.

Referenced by callback_exec(), and login_exec().

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

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

Referenced by load_module().

02304 {
02305    const char *agent = astman_get_header(m, "Agent");
02306    const char *exten = astman_get_header(m, "Exten");
02307    const char *context = astman_get_header(m, "Context");
02308    const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02309    const char *ackcall_s = astman_get_header(m, "AckCall");
02310    struct agent_pvt *p;
02311    int login_state = 0;
02312 
02313    callback_deprecated();
02314 
02315    if (ast_strlen_zero(agent)) {
02316       astman_send_error(s, m, "No agent specified");
02317       return 0;
02318    }
02319 
02320    if (ast_strlen_zero(exten)) {
02321       astman_send_error(s, m, "No extension specified");
02322       return 0;
02323    }
02324 
02325    AST_LIST_LOCK(&agents);
02326    AST_LIST_TRAVERSE(&agents, p, list) {
02327       if (strcmp(p->agent, agent) || p->pending) 
02328          continue;
02329       if (p->chan) {
02330          login_state = 2; /* already logged in (and on the phone)*/
02331          break;
02332       }
02333       ast_mutex_lock(&p->lock);
02334       login_state = 1; /* Successful Login */
02335       
02336       if (ast_strlen_zero(context))
02337          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02338       else
02339          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02340 
02341       if (!ast_strlen_zero(wrapuptime_s)) {
02342          p->wrapuptime = atoi(wrapuptime_s);
02343          if (p->wrapuptime < 0)
02344             p->wrapuptime = 0;
02345       }
02346 
02347       if (ast_true(ackcall_s))
02348          p->ackcall = 1;
02349       else
02350          p->ackcall = 0;
02351 
02352       if (p->loginstart == 0)
02353          time(&p->loginstart);
02354       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02355                "Agent: %s\r\n"
02356                "Loginchan: %s\r\n",
02357                p->agent, p->loginchan);
02358       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02359       if (option_verbose > 1)
02360          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02361       ast_device_state_changed("Agent/%s", p->agent);
02362       ast_mutex_unlock(&p->lock);
02363       if (persistent_agents)
02364          dump_agents();
02365    }
02366    AST_LIST_UNLOCK(&agents);
02367 
02368    if (login_state == 1)
02369       astman_send_ack(s, m, "Agent logged in");
02370    else if (login_state == 0)
02371       astman_send_error(s, m, "No such agent");
02372    else if (login_state == 2)
02373       astman_send_error(s, m, "Agent already logged in");
02374 
02375    return 0;
02376 }

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

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

Referenced by load_module().

01621 {
01622    const char *agent = astman_get_header(m, "Agent");
01623    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01624    int soft;
01625    int ret; /* return value of agent_logoff */
01626 
01627    if (ast_strlen_zero(agent)) {
01628       astman_send_error(s, m, "No agent specified");
01629       return 0;
01630    }
01631 
01632    soft = ast_true(soft_s) ? 1 : 0;
01633    ret = agent_logoff(agent, soft);
01634    if (ret == 0)
01635       astman_send_ack(s, m, "Agent logged out");
01636    else
01637       astman_send_error(s, m, "No such agent");
01638 
01639    return 0;
01640 }

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 1455 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_OR, and username.

Referenced by load_module().

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

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

Adds an agent to the global list of agents.

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

Definition at line 290 of file chan_agent.c.

References agent_pvt::ackcall, agent_pvt::agent, agent_pvt::app_lock, agent_pvt::app_sleep_cond, 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::group, agent_pvt::lastdisc, agent_pvt::lock, LOG_WARNING, agent_pvt::moh, agent_pvt::name, agent_pvt::owning_app, parse(), agent_pvt::password, agent_pvt::pending, and agent_pvt::wrapuptime.

Referenced by agent_request(), and read_agent_config().

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

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 899 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, ast_frame::frametype, agent_pvt::lock, and ast_frame::subclass.

Referenced by __login_exec().

00900 {
00901    struct agent_pvt *p;
00902    int res=0;
00903    int to = 1000;
00904    struct ast_frame *f;
00905 
00906    /* Wait a second and look for something */
00907 
00908    p = (struct agent_pvt *) data;
00909    if (!p->chan) 
00910       return -1;
00911 
00912    for(;;) {
00913       to = ast_waitfor(p->chan, to);
00914       if (to < 0) 
00915          return -1;
00916       if (!to) 
00917          return 0;
00918       f = ast_read(p->chan);
00919       if (!f) 
00920          return -1;
00921       if (f->frametype == AST_FRAME_DTMF)
00922          res = f->subclass;
00923       else
00924          res = 0;
00925       ast_frfree(f);
00926       ast_mutex_lock(&p->lock);
00927       if (!p->app_sleep_cond) {
00928          ast_mutex_unlock(&p->lock);
00929          return 0;
00930       } else if (res == '#') {
00931          ast_mutex_unlock(&p->lock);
00932          return 1;
00933       }
00934       ast_mutex_unlock(&p->lock);
00935       res = 0;
00936    }
00937    return res;
00938 }

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 400 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00401 {
00402    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00403    return -1;
00404 }

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

Definition at line 940 of file chan_agent.c.

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

00941 {
00942    struct agent_pvt *p = bridge->tech_pvt;
00943    struct ast_channel *ret = NULL;
00944 
00945    if (p) {
00946       if (chan == p->chan)
00947          ret = bridge->_bridge;
00948       else if (chan == bridge->_bridge)
00949          ret = p->chan;
00950    }
00951 
00952    if (option_debug)
00953       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
00954    return ret;
00955 }

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

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

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

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

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

static int agent_cont_sleep ( void *  data  )  [static]

Definition at line 878 of file chan_agent.c.

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

Referenced by __login_exec().

00879 {
00880    struct agent_pvt *p;
00881    int res;
00882 
00883    p = (struct agent_pvt *)data;
00884 
00885    ast_mutex_lock(&p->lock);
00886    res = p->app_sleep_cond;
00887    if (p->lastdisc.tv_sec) {
00888       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00889          res = 1;
00890    }
00891    ast_mutex_unlock(&p->lock);
00892 
00893    if(option_debug > 4 && !res )
00894       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00895 
00896    return res;
00897 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

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

02523 {
02524    struct agent_pvt *p;
02525    char *s;
02526    ast_group_t groupmatch;
02527    int groupoff;
02528    int waitforagent=0;
02529    int res = AST_DEVICE_INVALID;
02530    
02531    s = data;
02532    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
02533       groupmatch = (1 << groupoff);
02534    else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02535       groupmatch = (1 << groupoff);
02536       waitforagent = 1;
02537    } else 
02538       groupmatch = 0;
02539 
02540    /* Check actual logged in agents first */
02541    AST_LIST_LOCK(&agents);
02542    AST_LIST_TRAVERSE(&agents, p, list) {
02543       ast_mutex_lock(&p->lock);
02544       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02545          if (p->owner) {
02546             if (res != AST_DEVICE_INUSE)
02547                res = AST_DEVICE_BUSY;
02548          } else {
02549             if (res == AST_DEVICE_BUSY)
02550                res = AST_DEVICE_INUSE;
02551             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02552                if (res == AST_DEVICE_INVALID)
02553                   res = AST_DEVICE_UNKNOWN;
02554             } else if (res == AST_DEVICE_INVALID)  
02555                res = AST_DEVICE_UNAVAILABLE;
02556          }
02557          if (!strcmp(data, p->agent)) {
02558             ast_mutex_unlock(&p->lock);
02559             break;
02560          }
02561       }
02562       ast_mutex_unlock(&p->lock);
02563    }
02564    AST_LIST_UNLOCK(&agents);
02565    return res;
02566 }

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

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

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

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

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

00631 {
00632    struct agent_pvt *p = ast->tech_pvt;
00633    ast_mutex_lock(&p->lock);
00634    ast_senddigit_end(p->chan, digit, duration);
00635    ast_mutex_unlock(&p->lock);
00636    return 0;
00637 }

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

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

00595 {
00596    struct agent_pvt *p = newchan->tech_pvt;
00597    ast_mutex_lock(&p->lock);
00598    if (p->owner != oldchan) {
00599       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00600       ast_mutex_unlock(&p->lock);
00601       return -1;
00602    }
00603    p->owner = newchan;
00604    ast_mutex_unlock(&p->lock);
00605    return 0;
00606 }

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

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

Definition at line 734 of file chan_agent.c.

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

00735 {
00736    struct agent_pvt *p = NULL;
00737    struct ast_channel *base = chan;
00738 
00739    /* chan is locked by the calling function */
00740    if (!chan || !chan->tech_pvt) {
00741       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);
00742       return NULL;
00743    }
00744    p = chan->tech_pvt;
00745    if (p->chan) 
00746       base = p->chan;
00747    return base;
00748 }

static int agent_hangup ( struct ast_channel ast  )  [static]

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

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

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

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

00609 {
00610    struct agent_pvt *p = ast->tech_pvt;
00611    int res = -1;
00612    ast_mutex_lock(&p->lock);
00613    if (p->chan)
00614       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00615    else
00616       res = 0;
00617    ast_mutex_unlock(&p->lock);
00618    return res;
00619 }

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

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

01566 {
01567    struct agent_pvt *p;
01568    long logintime;
01569    int ret = -1; /* Return -1 if no agent if found */
01570 
01571    AST_LIST_TRAVERSE(&agents, p, list) {
01572       if (!strcasecmp(p->agent, agent)) {
01573          ret = 0;
01574          if (p->owner || p->chan) {
01575             if (!soft) {
01576                if (p->owner)
01577                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01578                if (p->chan)
01579                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01580             } else
01581                p->deferlogoff = 1;
01582          } else {
01583             logintime = time(NULL) - p->loginstart;
01584             p->loginstart = 0;
01585             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01586          }
01587          break;
01588       }
01589    }
01590 
01591    return ret;
01592 }

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

Definition at line 1594 of file chan_agent.c.

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

01595 {
01596    int ret;
01597    char *agent;
01598 
01599    if (argc < 3 || argc > 4)
01600       return RESULT_SHOWUSAGE;
01601    if (argc == 4 && strcasecmp(argv[3], "soft"))
01602       return RESULT_SHOWUSAGE;
01603 
01604    agent = argv[2] + 6;
01605    ret = agent_logoff(agent, argc == 4);
01606    if (ret == 0)
01607       ast_cli(fd, "Logging out %s\n", agent);
01608 
01609    return RESULT_SUCCESS;
01610 }

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

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

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

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

Create new agent channel.

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

00959 {
00960    struct ast_channel *tmp;
00961 #if 0
00962    if (!p->chan) {
00963       ast_log(LOG_WARNING, "No channel? :(\n");
00964       return NULL;
00965    }
00966 #endif   
00967    if (p->pending)
00968       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);
00969    else
00970       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
00971    if (!tmp) {
00972       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
00973       return NULL;
00974    }
00975 
00976    tmp->tech = &agent_tech;
00977    if (p->chan) {
00978       tmp->nativeformats = p->chan->nativeformats;
00979       tmp->writeformat = p->chan->writeformat;
00980       tmp->rawwriteformat = p->chan->writeformat;
00981       tmp->readformat = p->chan->readformat;
00982       tmp->rawreadformat = p->chan->readformat;
00983       ast_string_field_set(tmp, language, p->chan->language);
00984       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
00985       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
00986       /* XXX Is this really all we copy form the originating channel?? */
00987    } else {
00988       tmp->nativeformats = AST_FORMAT_SLINEAR;
00989       tmp->writeformat = AST_FORMAT_SLINEAR;
00990       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
00991       tmp->readformat = AST_FORMAT_SLINEAR;
00992       tmp->rawreadformat = AST_FORMAT_SLINEAR;
00993    }
00994    /* Safe, agentlock already held */
00995    tmp->tech_pvt = p;
00996    p->owner = tmp;
00997    /* XXX: this needs fixing */
00998 #if 0
00999    ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
01000 #endif
01001    ast_update_use_count();
01002    tmp->priority = 1;
01003    /* Wake up and wait for other applications (by definition the login app)
01004     * to release this channel). Takes ownership of the agent channel
01005     * to this thread only.
01006     * For signalling the other thread, ast_queue_frame is used until we
01007     * can safely use signals for this purpose. The pselect() needs to be
01008     * implemented in the kernel for this.
01009     */
01010    p->app_sleep_cond = 0;
01011    if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
01012       if (p->chan) {
01013          ast_queue_frame(p->chan, &ast_null_frame);
01014          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01015          ast_mutex_lock(&p->app_lock);
01016          ast_mutex_lock(&p->lock);
01017       } else {
01018          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01019          p->owner = NULL;
01020          tmp->tech_pvt = NULL;
01021          p->app_sleep_cond = 1;
01022          ast_channel_free( tmp );
01023          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01024          ast_mutex_unlock(&p->app_lock);
01025          return NULL;
01026       }
01027    } else if (!ast_strlen_zero(p->loginchan)) {
01028       if (p->chan)
01029          ast_queue_frame(p->chan, &ast_null_frame);
01030       if (!p->chan) {
01031          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01032          p->owner = NULL;
01033          tmp->tech_pvt = NULL;
01034          p->app_sleep_cond = 1;
01035          ast_channel_free( tmp );
01036          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
01037          return NULL;
01038       }  
01039    } 
01040    if (p->chan)
01041       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01042    p->owning_app = pthread_self();
01043    /* After the above step, there should not be any blockers. */
01044    if (p->chan) {
01045       if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
01046          ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
01047          CRASH;
01048       }
01049    }
01050    return tmp;
01051 }

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

Definition at line 439 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, ast_frame::frametype, 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_frame::subclass, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

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

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

Part of the Asterisk PBX interface.

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

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

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

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

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

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

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

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

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

Definition at line 750 of file chan_agent.c.

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

00751 {
00752    struct agent_pvt *p = NULL;
00753    
00754    if (!chan || !base) {
00755       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00756       return -1;
00757    }
00758    p = chan->tech_pvt;
00759    if (!p) {
00760       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00761       return -1;
00762    }
00763    p->chan = base;
00764    return 0;
00765 }

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

Definition at line 434 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00435 {
00436    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00437 }

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

Definition at line 569 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, ast_frame::frametype, agent_pvt::lock, LOG_DEBUG, ast_frame::subclass, ast_channel::tech_pvt, and ast_channel::writeformat.

00570 {
00571    struct agent_pvt *p = ast->tech_pvt;
00572    int res = -1;
00573    CHECK_FORMATS(ast, p);
00574    ast_mutex_lock(&p->lock);
00575    if (!p->chan) 
00576       res = 0;
00577    else {
00578       if ((f->frametype != AST_FRAME_VOICE) ||
00579           (f->frametype != AST_FRAME_VIDEO) ||
00580           (f->subclass == p->chan->writeformat)) {
00581          res = ast_write(p->chan, f);
00582       } else {
00583          ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00584             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00585             ast->name, p->chan->name);
00586          res = 0;
00587       }
00588    }
00589    CLEANUP(ast, p);
00590    ast_mutex_unlock(&p->lock);
00591    return res;
00592 }

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 2386 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, ast_cdr::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_channel::exten, GETAGENTBYCALLERID, LOG_WARNING, option_verbose, pbx_builtin_getvar_helper(), ast_channel::priority, and VERBOSE_PREFIX_3.

Referenced by load_module().

02387 {
02388    int exitifnoagentid = 0;
02389    int nowarnings = 0;
02390    int changeoutgoing = 0;
02391    int res = 0;
02392    char agent[AST_MAX_AGENT];
02393 
02394    if (data) {
02395       if (strchr(data, 'd'))
02396          exitifnoagentid = 1;
02397       if (strchr(data, 'n'))
02398          nowarnings = 1;
02399       if (strchr(data, 'c'))
02400          changeoutgoing = 1;
02401    }
02402    if (chan->cid.cid_num) {
02403       const char *tmp;
02404       char agentvar[AST_MAX_BUF];
02405       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02406       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02407          struct agent_pvt *p;
02408          ast_copy_string(agent, tmp, sizeof(agent));
02409          AST_LIST_LOCK(&agents);
02410          AST_LIST_TRAVERSE(&agents, p, list) {
02411             if (!strcasecmp(p->agent, tmp)) {
02412                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02413                __agent_start_monitoring(chan, p, 1);
02414                break;
02415             }
02416          }
02417          AST_LIST_UNLOCK(&agents);
02418          
02419       } else {
02420          res = -1;
02421          if (!nowarnings)
02422             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);
02423       }
02424    } else {
02425       res = -1;
02426       if (!nowarnings)
02427          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");
02428    }
02429    /* check if there is n + 101 priority */
02430    /*! \todo XXX Needs to check option priorityjump etc etc */
02431    if (res) {
02432       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02433          chan->priority+=100;
02434          if (option_verbose > 2)
02435             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02436       } else if (exitifnoagentid)
02437          return res;
02438    }
02439    return 0;
02440 }

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

01664 {
01665    struct agent_pvt *p;
01666    char username[AST_MAX_BUF];
01667    char location[AST_MAX_BUF] = "";
01668    char talkingto[AST_MAX_BUF] = "";
01669    char moh[AST_MAX_BUF];
01670    int count_agents = 0;      /*!< Number of agents configured */
01671    int online_agents = 0;     /*!< Number of online agents */
01672    int offline_agents = 0;    /*!< Number of offline agents */
01673    if (argc != 2)
01674       return RESULT_SHOWUSAGE;
01675    AST_LIST_LOCK(&agents);
01676    AST_LIST_TRAVERSE(&agents, p, list) {
01677       ast_mutex_lock(&p->lock);
01678       if (p->pending) {
01679          if (p->group)
01680             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
01681          else
01682             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01683       } else {
01684          if (!ast_strlen_zero(p->name))
01685             snprintf(username, sizeof(username), "(%s) ", p->name);
01686          else
01687             username[0] = '\0';
01688          if (p->chan) {
01689             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01690             if (p->owner && ast_bridged_channel(p->owner))
01691                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01692              else 
01693                strcpy(talkingto, " is idle");
01694             online_agents++;
01695          } else if (!ast_strlen_zero(p->loginchan)) {
01696             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01697                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01698             else 
01699                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01700             talkingto[0] = '\0';
01701             online_agents++;
01702             if (p->acknowledged)
01703                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01704          } else {
01705             strcpy(location, "not logged in");
01706             talkingto[0] = '\0';
01707             offline_agents++;
01708          }
01709          if (!ast_strlen_zero(p->moh))
01710             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01711          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
01712             username, location, talkingto, moh);
01713          count_agents++;
01714       }
01715       ast_mutex_unlock(&p->lock);
01716    }
01717    AST_LIST_UNLOCK(&agents);
01718    if ( !count_agents ) 
01719       ast_cli(fd, "No Agents are configured in %s\n",config);
01720    else 
01721       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01722    ast_cli(fd, "\n");
01723                    
01724    return RESULT_SUCCESS;
01725 }

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

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

01729 {
01730    struct agent_pvt *p;
01731    char username[AST_MAX_BUF];
01732    char location[AST_MAX_BUF] = "";
01733    char talkingto[AST_MAX_BUF] = "";
01734    char moh[AST_MAX_BUF];
01735    int count_agents = 0;           /* Number of agents configured */
01736    int online_agents = 0;          /* Number of online agents */
01737    int agent_status = 0;           /* 0 means offline, 1 means online */
01738    if (argc != 3)
01739       return RESULT_SHOWUSAGE;
01740    AST_LIST_LOCK(&agents);
01741    AST_LIST_TRAVERSE(&agents, p, list) {
01742       agent_status = 0;       /* reset it to offline */
01743       ast_mutex_lock(&p->lock);
01744       if (!ast_strlen_zero(p->name))
01745          snprintf(username, sizeof(username), "(%s) ", p->name);
01746       else
01747          username[0] = '\0';
01748       if (p->chan) {
01749          snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01750          if (p->owner && ast_bridged_channel(p->owner)) 
01751             snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01752          else 
01753             strcpy(talkingto, " is idle");
01754          agent_status = 1;
01755          online_agents++;
01756       } else if (!ast_strlen_zero(p->loginchan)) {
01757          snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01758          talkingto[0] = '\0';
01759          agent_status = 1;
01760          online_agents++;
01761          if (p->acknowledged)
01762             strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01763       }
01764       if (!ast_strlen_zero(p->moh))
01765          snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01766       if (agent_status)
01767          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
01768       count_agents++;
01769       ast_mutex_unlock(&p->lock);
01770    }
01771    AST_LIST_UNLOCK(&agents);
01772    if (!count_agents) 
01773       ast_cli(fd, "No Agents are configured in %s\n", config);
01774    else
01775       ast_cli(fd, "%d agents online\n", online_agents);
01776    ast_cli(fd, "\n");
01777    return RESULT_SUCCESS;
01778 }

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

Definition at line 1322 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

01323 {
01324    struct agent_pvt *p;
01325    char loginchan[80];
01326 
01327    if(multiplelogin)
01328       return 1;
01329    if(!chan) 
01330       return 0;
01331 
01332    snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01333    
01334    AST_LIST_TRAVERSE(&agents, p, list) {
01335       if(!strcasecmp(chan, p->loginchan))
01336          return 0;
01337    }
01338    return -1;
01339 }

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

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02268 {
02269    static int depwarning = 0;
02270 
02271    if (!depwarning) {
02272       depwarning = 1;
02273 
02274       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02275       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02276       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02277    }
02278 }

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

References __login_exec(), and callback_deprecated().

Referenced by load_module().

02289 {
02290    callback_deprecated();
02291 
02292    return __login_exec(chan, data, 1);
02293 }

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

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

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

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

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

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

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

Definition at line 1642 of file chan_agent.c.

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

01643 {
01644    if (pos == 2) {
01645       struct agent_pvt *p;
01646       char name[AST_MAX_AGENT];
01647       int which = 0, len = strlen(word);
01648 
01649       AST_LIST_TRAVERSE(&agents, p, list) {
01650          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01651          if (!strncasecmp(word, name, len) && ++which > state)
01652             return ast_strdup(name);
01653       }
01654    } else if (pos == 3 && state == 0) 
01655       return ast_strdup("soft");
01656    
01657    return NULL;
01658 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

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

02446 {
02447    struct agent_pvt *cur_agent = NULL;
02448    char buf[256];
02449 
02450    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02451       if (cur_agent->chan)
02452          continue;
02453 
02454       if (!ast_strlen_zero(cur_agent->loginchan)) {
02455          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02456          if (ast_db_put(pa_family, cur_agent->agent, buf))
02457             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02458          else if (option_debug)
02459             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02460       } else {
02461          /* Delete -  no agent or there is an error */
02462          ast_db_del(pa_family, cur_agent->agent);
02463       }
02464    }
02465 }

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

Definition at line 2568 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02569 {
02570    struct agent_pvt *cur;
02571 
02572    AST_LIST_TRAVERSE(&agents, cur, list) {
02573       if (!strcmp(cur->agent, agentid))
02574          break;   
02575    }
02576 
02577    return cur; 
02578 }

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

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

02581 {
02582    char *parse;    
02583    AST_DECLARE_APP_ARGS(args,
02584       AST_APP_ARG(agentid);
02585       AST_APP_ARG(item);
02586    );
02587    char *tmp;
02588    struct agent_pvt *agent;
02589 
02590    buf[0] = '\0';
02591 
02592    if (ast_strlen_zero(data)) {
02593       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02594       return -1;
02595    }
02596 
02597    parse = ast_strdupa(data);
02598 
02599    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02600    if (!args.item)
02601       args.item = "status";
02602 
02603    if (!(agent = find_agent(args.agentid))) {
02604       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02605       return -1;
02606    }
02607 
02608    if (!strcasecmp(args.item, "status")) {
02609       char *status = "LOGGEDOUT";
02610       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02611          status = "LOGGEDIN"; 
02612       ast_copy_string(buf, status, len);
02613    } else if (!strcasecmp(args.item, "password")) 
02614       ast_copy_string(buf, agent->password, len);
02615    else if (!strcasecmp(args.item, "name"))
02616       ast_copy_string(buf, agent->name, len);
02617    else if (!strcasecmp(args.item, "mohclass"))
02618       ast_copy_string(buf, agent->moh, len);
02619    else if (!strcasecmp(args.item, "channel")) {
02620       if (agent->chan) {
02621          ast_copy_string(buf, agent->chan->name, len);
02622          tmp = strrchr(buf, '-');
02623          if (tmp)
02624             *tmp = '\0';
02625       } 
02626    } else if (!strcasecmp(args.item, "exten"))
02627       ast_copy_string(buf, agent->loginchan, len); 
02628 
02629    return 0;
02630 }

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

02656 {
02657    /* Make sure we can register our agent channel type */
02658    if (ast_channel_register(&agent_tech)) {
02659       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02660       return -1;
02661    }
02662    /* Read in the config */
02663    if (!read_agent_config())
02664       return AST_MODULE_LOAD_DECLINE;
02665    if (persistent_agents)
02666       reload_agents();
02667    /* Dialplan applications */
02668    ast_register_application(app, login_exec, synopsis, descrip);
02669    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02670    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02671 
02672    /* Manager commands */
02673    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02674    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02675    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02676 
02677    /* CLI Commands */
02678    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02679 
02680    /* Dialplan Functions */
02681    ast_custom_function_register(&agent_function);
02682 
02683    return 0;
02684 }

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

References __login_exec().

Referenced by load_module().

02263 {
02264    return __login_exec(chan, data, 0);
02265 }

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

Definition at line 1437 of file chan_agent.c.

01438 {
01439    int x = ffs(d);
01440 
01441    if (x)
01442       return x - 1;
01443 
01444    return 0;
01445 }

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

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

static int reload ( void   )  [static]

Definition at line 2686 of file chan_agent.c.

References read_agent_config(), and reload_agents().

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

02687 {
02688    read_agent_config();
02689    if (persistent_agents)
02690       reload_agents();
02691    return 0;
02692 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

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

02471 {
02472    char *agent_num;
02473    struct ast_db_entry *db_tree;
02474    struct ast_db_entry *entry;
02475    struct agent_pvt *cur_agent;
02476    char agent_data[256];
02477    char *parse;
02478    char *agent_chan;
02479    char *agent_callerid;
02480 
02481    db_tree = ast_db_gettree(pa_family, NULL);
02482 
02483    AST_LIST_LOCK(&agents);
02484    for (entry = db_tree; entry; entry = entry->next) {
02485       agent_num = entry->key + strlen(pa_family) + 2;
02486       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02487          ast_mutex_lock(&cur_agent->lock);
02488          if (strcmp(agent_num, cur_agent->agent) == 0)
02489             break;
02490          ast_mutex_unlock(&cur_agent->lock);
02491       }
02492       if (!cur_agent) {
02493          ast_db_del(pa_family, agent_num);
02494          continue;
02495       } else
02496          ast_mutex_unlock(&cur_agent->lock);
02497       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02498          if (option_debug)
02499             ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02500          parse = agent_data;
02501          agent_chan = strsep(&parse, ";");
02502          agent_callerid = strsep(&parse, ";");
02503          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02504          if (agent_callerid) {
02505             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02506             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02507          } else
02508             cur_agent->logincallerid[0] = '\0';
02509          if (cur_agent->loginstart == 0)
02510             time(&cur_agent->loginstart);
02511          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02512       }
02513    }
02514    AST_LIST_UNLOCK(&agents);
02515    if (db_tree) {
02516       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02517       ast_db_freetree(db_tree);
02518    }
02519 }

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

00722 {
00723    char buf[AST_MAX_BUF];
00724 
00725    /* if there is no Caller ID, nothing to do */
00726    if (ast_strlen_zero(callerid))
00727       return;
00728 
00729    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00730    pbx_builtin_setvar_helper(NULL, buf, agent);
00731 }

static int unload_module ( void   )  [static]

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

02695 {
02696    struct agent_pvt *p;
02697    /* First, take us out of the channel loop */
02698    ast_channel_unregister(&agent_tech);
02699    /* Unregister dialplan functions */
02700    ast_custom_function_unregister(&agent_function);   
02701    /* Unregister CLI commands */
02702    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02703    /* Unregister dialplan applications */
02704    ast_unregister_application(app);
02705    ast_unregister_application(app2);
02706    ast_unregister_application(app3);
02707    /* Unregister manager command */
02708    ast_manager_unregister("Agents");
02709    ast_manager_unregister("AgentLogoff");
02710    ast_manager_unregister("AgentCallbackLogin");
02711    /* Unregister channel */
02712    AST_LIST_LOCK(&agents);
02713    /* Hangup all interfaces if they have an owner */
02714    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02715       if (p->owner)
02716          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02717       free(p);
02718    }
02719    AST_LIST_UNLOCK(&agents);
02720    AST_LIST_HEAD_DESTROY(&agents);
02721    return 0;
02722 }


Variable Documentation

int ackcall [static]

Definition at line 156 of file chan_agent.c.

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

Definition at line 258 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]

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

Referenced by load_module(), and unload_module().

Initial value:

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

Definition at line 1795 of file chan_agent.c.

Initial value:

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

Definition at line 1800 of file chan_agent.c.

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

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.

Referenced by load_module().

int endcall [static]

Definition at line 157 of file chan_agent.c.

ast_group_t group [static]

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]

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 1786 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 1782 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.

Referenced by load_module().

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 Sat Apr 12 07:12:35 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5