Mon Nov 24 15:34:27 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"

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_devicestate_cb (const char *dev, int state, void *data)
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 *text)
static int agent_set_base_channel (struct ast_channel *chan, struct ast_channel *base)
static int agent_start_monitoring (struct ast_channel *ast, int needlock)
static int agent_write (struct ast_channel *ast, struct ast_frame *f)
static int agentmonitoroutgoing_exec (struct ast_channel *chan, void *data)
 Called by the AgentMonitorOutgoing application (from the dial plan).
static int agents_show (int fd, int argc, char **argv)
static int agents_show_online (int fd, int argc, char **argv)
static int allow_multiple_login (char *chan, char *context)
static AST_LIST_HEAD_STATIC (agents, agent_pvt)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT,"Agent Proxy Channel",.load=load_module,.unload=unload_module,.reload=reload,)
static void callback_deprecated (void)
static int callback_exec (struct ast_channel *chan, void *data)
static int check_availability (struct agent_pvt *newlyavailable, int needlock)
static int check_beep (struct agent_pvt *newlyavailable, int needlock)
static char * complete_agent_logoff_cmd (const char *line, const char *word, int pos, int state)
static void dump_agents (void)
 Dump AgentCallbackLogin agents to the ASTdb database for persistence.
static struct agent_pvtfind_agent (char *agentid)
static int function_agent (struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
static int load_module (void)
 Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other things it registers applications, cli commands and reads the cofiguration file.
static int login_exec (struct ast_channel *chan, void *data)
static force_inline int powerof (unsigned int d)
static int read_agent_config (void)
static int reload (void)
static void reload_agents (void)
 Reload the persistent agents from astdb.
static void set_agentbycallerid (const char *callerid, const char *agent)
 store/clear the global variable that stores agentid based on the callerid
static int unload_module (void)

Variables

static int ackcall
ast_custom_function agent_function
static char agent_logoff_usage []
static struct ast_channel_tech agent_tech
 Channel interface description for PBX integration.
static char agentgoodbye [AST_MAX_FILENAME_LEN] = "vm-goodbye"
static const char app [] = "AgentLogin"
static const char app2 [] = "AgentCallbackLogin"
static const char app3 [] = "AgentMonitorOutgoing"
static int autologoff
static int autologoffunavail = 0
static char beep [AST_MAX_BUF] = "beep"
static struct ast_cli_entry cli_agents []
static struct ast_cli_entry cli_show_agents_deprecated
static struct ast_cli_entry cli_show_agents_online_deprecated
static const char config [] = "agents.conf"
static const char descrip []
static const char descrip2 []
static const char descrip3 []
static int endcall
static ast_group_t group
static const char mandescr_agent_callback_login []
static const char mandescr_agent_logoff []
static const char mandescr_agents []
static int maxlogintries = 3
static char moh [80] = "default"
static int multiplelogin = 1
static const char pa_family [] = "Agents"
static int persistent_agents = 0
static int recordagentcalls = 0
static char recordformat [AST_MAX_BUF] = ""
static char recordformatext [AST_MAX_BUF] = ""
static char savecallsin [AST_MAX_BUF] = ""
static char show_agents_online_usage []
static char show_agents_usage []
static const char synopsis [] = "Call agent login"
static const char synopsis2 [] = "Call agent callback login"
static const char synopsis3 [] = "Record agent's outgoing call"
static const char tdesc [] = "Call Agent Proxy Channel"
static int updatecdr = 0
static char urlprefix [AST_MAX_BUF] = ""
static int wrapuptime


Detailed Description

Implementation of Agents (proxy channel).

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

Definition in file chan_agent.c.


Define Documentation

#define AST_MAX_AGENT   80

Agent ID or Password max length

Definition at line 146 of file chan_agent.c.

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

#define AST_MAX_BUF   256

Definition at line 147 of file chan_agent.c.

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

#define AST_MAX_FILENAME_LEN   256

Definition at line 148 of file chan_agent.c.

Referenced by __login_exec(), and ael2_semantic_check().

#define CHECK_FORMATS ( ast,
 ) 

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

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

#define GETAGENTBYCALLERID   "AGENTBYCALLERID"

Definition at line 175 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 151 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 450 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().

00451 {
00452    char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
00453    char filename[AST_MAX_BUF];
00454    int res = -1;
00455    if (!p)
00456       return -1;
00457    if (!ast->monitor) {
00458       snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
00459       /* substitute . for - */
00460       if ((pointer = strchr(filename, '.')))
00461          *pointer = '-';
00462       snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
00463       ast_monitor_start(ast, recordformat, tmp, needlock);
00464       ast_monitor_setjoinfiles(ast, 1);
00465       snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
00466 #if 0
00467       ast_verbose("name is %s, link is %s\n",tmp, tmp2);
00468 #endif
00469       if (!ast->cdr)
00470          ast->cdr = ast_cdr_alloc();
00471       ast_cdr_setuserfield(ast, tmp2);
00472       res = 0;
00473    } else
00474       ast_log(LOG_ERROR, "Recording already started on that call.\n");
00475    return res;
00476 }

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 1918 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_channel_lock, ast_channel_unlock, AST_CONTROL_HOLD, AST_DECLARE_APP_ARGS, ast_device_state_changed(), AST_DIGIT_ANY, ast_exists_extension(), ast_getformatname(), ast_indicate_data(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), AST_MAX_AGENT, AST_MAX_BUF, AST_MAX_FILENAME_LEN, ast_module_user_add, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_queue_log(), ast_safe_sleep(), ast_safe_sleep_conditional(), ast_set_read_format(), ast_set_write_format(), ast_softhangup(), AST_SOFTHANGUP_EXPLICIT, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_true(), ast_verbose(), ast_waitstream(), agent_pvt::autologoff, ast_channel::cdr, agent_pvt::chan, ast_cdr::channel, check_availability(), check_beep(), ast_channel::cid, ast_callerid::cid_num, context, agent_pvt::dead, agent_pvt::deferlogoff, dump_agents(), EVENT_FLAG_AGENT, free, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, agent_pvt::logincallerid, agent_pvt::loginchan, agent_pvt::loginstart, manager_event(), agent_pvt::moh, option_debug, option_verbose, agent_pvt::owner, agent_pvt::owning_app, parse(), agent_pvt::password, pbx_builtin_getvar_helper(), agent_pvt::pending, S_OR, set_agentbycallerid(), strsep(), VERBOSE_PREFIX_2, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

Referenced by callback_exec(), and login_exec().

01919 {
01920    int res=0;
01921    int tries = 0;
01922    int max_login_tries = maxlogintries;
01923    struct agent_pvt *p;
01924    struct ast_module_user *u;
01925    int login_state = 0;
01926    char user[AST_MAX_AGENT] = "";
01927    char pass[AST_MAX_AGENT];
01928    char agent[AST_MAX_AGENT] = "";
01929    char xpass[AST_MAX_AGENT] = "";
01930    char *errmsg;
01931    char *parse;
01932    AST_DECLARE_APP_ARGS(args,
01933               AST_APP_ARG(agent_id);
01934               AST_APP_ARG(options);
01935               AST_APP_ARG(extension);
01936       );
01937    const char *tmpoptions = NULL;
01938    char *context = NULL;
01939    int play_announcement = 1;
01940    char agent_goodbye[AST_MAX_FILENAME_LEN];
01941    int update_cdr = updatecdr;
01942    char *filename = "agent-loginok";
01943    char tmpchan[AST_MAX_BUF] = "";
01944 
01945    u = ast_module_user_add(chan);
01946 
01947    parse = ast_strdupa(data);
01948 
01949    AST_STANDARD_APP_ARGS(args, parse);
01950 
01951    ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
01952 
01953    ast_channel_lock(chan);
01954    /* Set Channel Specific Login Overrides */
01955    if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
01956       max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
01957       if (max_login_tries < 0)
01958          max_login_tries = 0;
01959       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
01960       if (option_verbose > 2)
01961          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);
01962    }
01963    if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
01964       if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
01965          update_cdr = 1;
01966       else
01967          update_cdr = 0;
01968       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
01969       if (option_verbose > 2)
01970          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
01971    }
01972    if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
01973       strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
01974       tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
01975       if (option_verbose > 2)
01976          ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
01977    }
01978    ast_channel_unlock(chan);
01979    /* End Channel Specific Login Overrides */
01980    
01981    if (callbackmode && args.extension) {
01982       parse = args.extension;
01983       args.extension = strsep(&parse, "@");
01984       context = parse;
01985    }
01986 
01987    if (!ast_strlen_zero(args.options)) {
01988       if (strchr(args.options, 's')) {
01989          play_announcement = 0;
01990       }
01991    }
01992 
01993    if (chan->_state != AST_STATE_UP)
01994       res = ast_answer(chan);
01995    if (!res) {
01996       if (!ast_strlen_zero(args.agent_id))
01997          ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
01998       else
01999          res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
02000    }
02001    while (!res && (max_login_tries==0 || tries < max_login_tries)) {
02002       tries++;
02003       /* Check for password */
02004       AST_LIST_LOCK(&agents);
02005       AST_LIST_TRAVERSE(&agents, p, list) {
02006          if (!strcmp(p->agent, user) && !p->pending)
02007             ast_copy_string(xpass, p->password, sizeof(xpass));
02008       }
02009       AST_LIST_UNLOCK(&agents);
02010       if (!res) {
02011          if (!ast_strlen_zero(xpass))
02012             res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
02013          else
02014             pass[0] = '\0';
02015       }
02016       errmsg = "agent-incorrect";
02017 
02018 #if 0
02019       ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
02020 #endif      
02021 
02022       /* Check again for accuracy */
02023       AST_LIST_LOCK(&agents);
02024       AST_LIST_TRAVERSE(&agents, p, list) {
02025          int unlock_channel = 1;
02026          ast_channel_lock(chan);
02027          ast_mutex_lock(&p->lock);
02028          if (!strcmp(p->agent, user) &&
02029              !strcmp(p->password, pass) && !p->pending) {
02030             login_state = 1; /* Successful Login */
02031 
02032             /* Ensure we can't be gotten until we're done */
02033             gettimeofday(&p->lastdisc, NULL);
02034             p->lastdisc.tv_sec++;
02035 
02036             /* Set Channel Specific Agent Overrides */
02037             if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
02038                if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
02039                   p->ackcall = 2;
02040                else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
02041                   p->ackcall = 1;
02042                else
02043                   p->ackcall = 0;
02044                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
02045                if (option_verbose > 2)
02046                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
02047             } else {
02048                p->ackcall = ackcall;
02049             }
02050             if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
02051                p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
02052                if (p->autologoff < 0)
02053                   p->autologoff = 0;
02054                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
02055                if (option_verbose > 2)
02056                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
02057             } else {
02058                p->autologoff = autologoff;
02059             }
02060             if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
02061                p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
02062                if (p->wrapuptime < 0)
02063                   p->wrapuptime = 0;
02064                tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
02065                if (option_verbose > 2)
02066                   ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
02067             } else {
02068                p->wrapuptime = wrapuptime;
02069             }
02070             ast_channel_unlock(chan);
02071             unlock_channel = 0;
02072             /* End Channel Specific Agent Overrides */
02073             if (!p->chan) {
02074                char last_loginchan[80] = "";
02075                long logintime;
02076                snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
02077 
02078                if (callbackmode) {
02079                   int pos = 0;
02080                   /* Retrieve login chan */
02081                   for (;;) {
02082                      if (!ast_strlen_zero(args.extension)) {
02083                         ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
02084                         res = 0;
02085                      } else
02086                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
02087                      if (ast_strlen_zero(tmpchan) )
02088                         break;
02089                      if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
02090                         if(!allow_multiple_login(tmpchan,context) ) {
02091                            args.extension = NULL;
02092                            pos = 0;
02093                         } else
02094                            break;
02095                      }
02096                      if (args.extension) {
02097                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
02098                         args.extension = NULL;
02099                         pos = 0;
02100                      } else {
02101                         ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
02102                         res = ast_streamfile(chan, "invalid", chan->language);
02103                         if (!res)
02104                            res = ast_waitstream(chan, AST_DIGIT_ANY);
02105                         if (res > 0) {
02106                            tmpchan[0] = res;
02107                            tmpchan[1] = '\0';
02108                            pos = 1;
02109                         } else {
02110                            tmpchan[0] = '\0';
02111                            pos = 0;
02112                         }
02113                      }
02114                   }
02115                   args.extension = tmpchan;
02116                   if (!res) {
02117                      set_agentbycallerid(p->logincallerid, NULL);
02118                      if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
02119                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
02120                      else {
02121                         ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
02122                         ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
02123                      }
02124                      p->acknowledged = 0;
02125                      if (ast_strlen_zero(p->loginchan)) {
02126                         login_state = 2;
02127                         filename = "agent-loggedoff";
02128                      } else {
02129                         if (chan->cid.cid_num) {
02130                            ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
02131                            set_agentbycallerid(p->logincallerid, p->agent);
02132                         } else
02133                            p->logincallerid[0] = '\0';
02134                      }
02135 
02136                      if(update_cdr && chan->cdr)
02137                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02138 
02139                   }
02140                } else {
02141                   p->loginchan[0] = '\0';
02142                   p->logincallerid[0] = '\0';
02143                   p->acknowledged = 0;
02144                }
02145                ast_mutex_unlock(&p->lock);
02146                AST_LIST_UNLOCK(&agents);
02147                if( !res && play_announcement==1 )
02148                   res = ast_streamfile(chan, filename, chan->language);
02149                if (!res)
02150                   ast_waitstream(chan, "");
02151                AST_LIST_LOCK(&agents);
02152                ast_mutex_lock(&p->lock);
02153                if (!res) {
02154                   res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
02155                   if (res)
02156                      ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
02157                }
02158                if (!res) {
02159                   res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
02160                   if (res)
02161                      ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
02162                }
02163                /* Check once more just in case */
02164                if (p->chan)
02165                   res = -1;
02166                if (callbackmode && !res) {
02167                   /* Just say goodbye and be done with it */
02168                   if (!ast_strlen_zero(p->loginchan)) {
02169                      if (p->loginstart == 0)
02170                         time(&p->loginstart);
02171                      manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02172                               "Agent: %s\r\n"
02173                               "Loginchan: %s\r\n"
02174                               "Uniqueid: %s\r\n",
02175                               p->agent, p->loginchan, chan->uniqueid);
02176                      ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02177                      if (option_verbose > 1)
02178                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02179                      ast_device_state_changed("Agent/%s", p->agent);
02180                      if (persistent_agents)
02181                         dump_agents();
02182                   } else {
02183                      logintime = time(NULL) - p->loginstart;
02184                      p->loginstart = 0;
02185 
02186                      agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
02187                      if (option_verbose > 1)
02188                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
02189                   }
02190                   AST_LIST_UNLOCK(&agents);
02191                   if (!res)
02192                      res = ast_safe_sleep(chan, 500);
02193                   ast_mutex_unlock(&p->lock);
02194                } else if (!res) {
02195                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
02196                      S_OR(p->moh, NULL), 
02197                      !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
02198                   if (p->loginstart == 0)
02199                      time(&p->loginstart);
02200                   manager_event(EVENT_FLAG_AGENT, "Agentlogin",
02201                            "Agent: %s\r\n"
02202                            "Channel: %s\r\n"
02203                            "Uniqueid: %s\r\n",
02204                            p->agent, chan->name, chan->uniqueid);
02205                   if (update_cdr && chan->cdr)
02206                      snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02207                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
02208                   if (option_verbose > 1)
02209                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
02210                             ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
02211                   /* Login this channel and wait for it to go away */
02212                   p->chan = chan;
02213                   if (p->ackcall > 1)
02214                      check_beep(p, 0);
02215                   else
02216                      check_availability(p, 0);
02217                   ast_mutex_unlock(&p->lock);
02218                   AST_LIST_UNLOCK(&agents);
02219                   ast_device_state_changed("Agent/%s", p->agent);
02220                   while (res >= 0) {
02221                      ast_mutex_lock(&p->lock);
02222                      if (p->deferlogoff && p->chan) {
02223                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
02224                         p->deferlogoff = 0;
02225                      }
02226                      if (p->chan != chan)
02227                         res = -1;
02228                      ast_mutex_unlock(&p->lock);
02229                      /* Yield here so other interested threads can kick in. */
02230                      sched_yield();
02231                      if (res)
02232                         break;
02233 
02234                      AST_LIST_LOCK(&agents);
02235                      ast_mutex_lock(&p->lock);
02236                      if (p->lastdisc.tv_sec) {
02237                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
02238                            if (option_debug)
02239                               ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
02240                            p->lastdisc = ast_tv(0, 0);
02241                            ast_device_state_changed("Agent/%s", p->agent);
02242                            if (p->ackcall > 1)
02243                               check_beep(p, 0);
02244                            else
02245                               check_availability(p, 0);
02246                         }
02247                      }
02248                      ast_mutex_unlock(&p->lock);
02249                      AST_LIST_UNLOCK(&agents);
02250                      /* Synchronize channel ownership between call to agent and itself. */
02251                      ast_mutex_lock( &p->app_lock );
02252                      ast_mutex_lock(&p->lock);
02253                      p->owning_app = pthread_self();
02254                      ast_mutex_unlock(&p->lock);
02255                      if (p->ackcall > 1) 
02256                         res = agent_ack_sleep(p);
02257                      else
02258                         res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
02259                      ast_mutex_unlock( &p->app_lock );
02260                      if ((p->ackcall > 1)  && (res == 1)) {
02261                         AST_LIST_LOCK(&agents);
02262                         ast_mutex_lock(&p->lock);
02263                         check_availability(p, 0);
02264                         ast_mutex_unlock(&p->lock);
02265                         AST_LIST_UNLOCK(&agents);
02266                         res = 0;
02267                      }
02268                      sched_yield();
02269                   }
02270                   ast_mutex_lock(&p->lock);
02271                   if (res && p->owner) 
02272                      ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
02273                   /* Log us off if appropriate */
02274                   if (p->chan == chan) {
02275                      p->chan = NULL;
02276                      p->inherited_devicestate = -1;
02277                   }
02278                   p->acknowledged = 0;
02279                   logintime = time(NULL) - p->loginstart;
02280                   p->loginstart = 0;
02281                   ast_mutex_unlock(&p->lock);
02282                   manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
02283                            "Agent: %s\r\n"
02284                            "Logintime: %ld\r\n"
02285                            "Uniqueid: %s\r\n",
02286                            p->agent, logintime, chan->uniqueid);
02287                   ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
02288                   if (option_verbose > 1)
02289                      ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
02290                   /* If there is no owner, go ahead and kill it now */
02291                   ast_device_state_changed("Agent/%s", p->agent);
02292                   if (p->dead && !p->owner) {
02293                      ast_mutex_destroy(&p->lock);
02294                      ast_mutex_destroy(&p->app_lock);
02295                      free(p);
02296                   }
02297                }
02298                else {
02299                   ast_mutex_unlock(&p->lock);
02300                   p = NULL;
02301                }
02302                res = -1;
02303             } else {
02304                ast_mutex_unlock(&p->lock);
02305                errmsg = "agent-alreadyon";
02306                p = NULL;
02307             }
02308             break;
02309          }
02310          ast_mutex_unlock(&p->lock);
02311          if (unlock_channel) {
02312             ast_channel_unlock(chan);
02313          }
02314       }
02315       if (!p)
02316          AST_LIST_UNLOCK(&agents);
02317 
02318       if (!res && (max_login_tries==0 || tries < max_login_tries))
02319          res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
02320    }
02321       
02322    if (!res)
02323       res = ast_safe_sleep(chan, 500);
02324 
02325    /* AgentLogin() exit */
02326    if (!callbackmode) {
02327       ast_module_user_remove(u);
02328       return -1;
02329    } else { /* AgentCallbackLogin() exit*/
02330       /* Set variables */
02331       if (login_state > 0) {
02332          pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
02333          if (login_state==1) {
02334             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
02335             pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
02336          } else 
02337             pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
02338       } else {
02339          pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
02340       }
02341       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
02342          ast_module_user_remove(u);
02343          return 0;
02344       }
02345       /* Do we need to play agent-goodbye now that we will be hanging up? */
02346       if (play_announcement) {
02347          if (!res)
02348             res = ast_safe_sleep(chan, 1000);
02349          res = ast_streamfile(chan, agent_goodbye, chan->language);
02350          if (!res)
02351             res = ast_waitstream(chan, "");
02352          if (!res)
02353             res = ast_safe_sleep(chan, 1000);
02354       }
02355    }
02356 
02357    ast_module_user_remove(u);
02358    
02359    /* We should never get here if next priority exists when in callbackmode */
02360    return -1;
02361 }

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

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

Referenced by load_module().

02413 {
02414    const char *agent = astman_get_header(m, "Agent");
02415    const char *exten = astman_get_header(m, "Exten");
02416    const char *context = astman_get_header(m, "Context");
02417    const char *wrapuptime_s = astman_get_header(m, "WrapupTime");
02418    const char *ackcall_s = astman_get_header(m, "AckCall");
02419    struct agent_pvt *p;
02420    int login_state = 0;
02421 
02422    callback_deprecated();
02423 
02424    if (ast_strlen_zero(agent)) {
02425       astman_send_error(s, m, "No agent specified");
02426       return 0;
02427    }
02428 
02429    if (ast_strlen_zero(exten)) {
02430       astman_send_error(s, m, "No extension specified");
02431       return 0;
02432    }
02433 
02434    AST_LIST_LOCK(&agents);
02435    AST_LIST_TRAVERSE(&agents, p, list) {
02436       if (strcmp(p->agent, agent) || p->pending) 
02437          continue;
02438       if (p->chan) {
02439          login_state = 2; /* already logged in (and on the phone)*/
02440          break;
02441       }
02442       ast_mutex_lock(&p->lock);
02443       login_state = 1; /* Successful Login */
02444       
02445       if (ast_strlen_zero(context))
02446          ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
02447       else
02448          snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
02449 
02450       if (!ast_strlen_zero(wrapuptime_s)) {
02451          p->wrapuptime = atoi(wrapuptime_s);
02452          if (p->wrapuptime < 0)
02453             p->wrapuptime = 0;
02454       }
02455 
02456       if (strcasecmp(ackcall_s, "always"))
02457          p->ackcall = 2;
02458       else if (ast_true(ackcall_s))
02459          p->ackcall = 1;
02460       else
02461          p->ackcall = 0;
02462 
02463       if (p->loginstart == 0)
02464          time(&p->loginstart);
02465       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
02466                "Agent: %s\r\n"
02467                "Loginchan: %s\r\n",
02468                p->agent, p->loginchan);
02469       ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
02470       if (option_verbose > 1)
02471          ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
02472       ast_device_state_changed("Agent/%s", p->agent);
02473       ast_mutex_unlock(&p->lock);
02474       if (persistent_agents)
02475          dump_agents();
02476    }
02477    AST_LIST_UNLOCK(&agents);
02478 
02479    if (login_state == 1)
02480       astman_send_ack(s, m, "Agent logged in");
02481    else if (login_state == 0)
02482       astman_send_error(s, m, "No such agent");
02483    else if (login_state == 2)
02484       astman_send_error(s, m, "Agent already logged in");
02485 
02486    return 0;
02487 }

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

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

Referenced by load_module().

01707 {
01708    const char *agent = astman_get_header(m, "Agent");
01709    const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
01710    int soft;
01711    int ret; /* return value of agent_logoff */
01712 
01713    if (ast_strlen_zero(agent)) {
01714       astman_send_error(s, m, "No agent specified");
01715       return 0;
01716    }
01717 
01718    soft = ast_true(soft_s) ? 1 : 0;
01719    ret = agent_logoff(agent, soft);
01720    if (ret == 0)
01721       astman_send_ack(s, m, "Agent logged out");
01722    else
01723       astman_send_error(s, m, "No such agent");
01724 
01725    return 0;
01726 }

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

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

Referenced by load_module().

01520 {
01521    const char *id = astman_get_header(m,"ActionID");
01522    char idText[256] = "";
01523    char chanbuf[256];
01524    struct agent_pvt *p;
01525    char *username = NULL;
01526    char *loginChan = NULL;
01527    char *talkingtoChan = NULL;
01528    char *status = NULL;
01529 
01530    if (!ast_strlen_zero(id))
01531       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
01532    astman_send_ack(s, m, "Agents will follow");
01533    AST_LIST_LOCK(&agents);
01534    AST_LIST_TRAVERSE(&agents, p, list) {
01535          ast_mutex_lock(&p->lock);
01536 
01537       /* Status Values:
01538          AGENT_LOGGEDOFF - Agent isn't logged in
01539          AGENT_IDLE      - Agent is logged in, and waiting for call
01540          AGENT_ONCALL    - Agent is logged in, and on a call
01541          AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
01542 
01543       username = S_OR(p->name, "None");
01544 
01545       /* Set a default status. It 'should' get changed. */
01546       status = "AGENT_UNKNOWN";
01547 
01548       if (!ast_strlen_zero(p->loginchan) && !p->chan) {
01549          loginChan = p->loginchan;
01550          talkingtoChan = "n/a";
01551          status = "AGENT_IDLE";
01552          if (p->acknowledged) {
01553             snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
01554             loginChan = chanbuf;
01555          }
01556       } else if (p->chan) {
01557          loginChan = ast_strdupa(p->chan->name);
01558          if (p->owner && p->owner->_bridge) {
01559             if (ast_bridged_channel(p->owner)) {
01560                talkingtoChan = ast_strdupa(S_OR(ast_bridged_channel(p->owner)->cid.cid_num, ""));
01561             } else {
01562                talkingtoChan = "n/a";
01563             }
01564                status = "AGENT_ONCALL";
01565          } else {
01566                talkingtoChan = "n/a";
01567                status = "AGENT_IDLE";
01568          }
01569       } else {
01570          loginChan = "n/a";
01571          talkingtoChan = "n/a";
01572          status = "AGENT_LOGGEDOFF";
01573       }
01574 
01575       astman_append(s, "Event: Agents\r\n"
01576          "Agent: %s\r\n"
01577          "Name: %s\r\n"
01578          "Status: %s\r\n"
01579          "LoggedInChan: %s\r\n"
01580          "LoggedInTime: %d\r\n"
01581          "TalkingTo: %s\r\n"
01582          "%s"
01583          "\r\n",
01584          p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
01585       ast_mutex_unlock(&p->lock);
01586    }
01587    AST_LIST_UNLOCK(&agents);
01588    astman_append(s, "Event: AgentsComplete\r\n"
01589       "%s"
01590       "\r\n",idText);
01591    return 0;
01592 }

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

Adds an agent to the global list of agents.

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

Definition at line 333 of file chan_agent.c.

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

Referenced by agent_request(), and read_agent_config().

00334 {
00335    char *parse;
00336    AST_DECLARE_APP_ARGS(args,
00337       AST_APP_ARG(agt);
00338       AST_APP_ARG(password);
00339       AST_APP_ARG(name);
00340    );
00341    char *password = NULL;
00342    char *name = NULL;
00343    char *agt = NULL;
00344    struct agent_pvt *p;
00345 
00346    parse = ast_strdupa(agent);
00347 
00348    /* Extract username (agt), password and name from agent (args). */
00349    AST_NONSTANDARD_APP_ARGS(args, parse, ',');
00350 
00351    if(args.argc == 0) {
00352       ast_log(LOG_WARNING, "A blank agent line!\n");
00353       return NULL;
00354    }
00355 
00356    if(ast_strlen_zero(args.agt) ) {
00357       ast_log(LOG_WARNING, "An agent line with no agentid!\n");
00358       return NULL;
00359    } else
00360       agt = args.agt;
00361 
00362    if(!ast_strlen_zero(args.password)) {
00363       password = args.password;
00364       while (*password && *password < 33) password++;
00365    }
00366    if(!ast_strlen_zero(args.name)) {
00367       name = args.name;
00368       while (*name && *name < 33) name++;
00369    }
00370    
00371    /* Are we searching for the agent here ? To see if it exists already ? */
00372    AST_LIST_TRAVERSE(&agents, p, list) {
00373       if (!pending && !strcmp(p->agent, agt))
00374          break;
00375    }
00376    if (!p) {
00377       // Build the agent.
00378       if (!(p = ast_calloc(1, sizeof(*p))))
00379          return NULL;
00380       ast_copy_string(p->agent, agt, sizeof(p->agent));
00381       ast_mutex_init(&p->lock);
00382       ast_mutex_init(&p->app_lock);
00383       p->owning_app = (pthread_t) -1;
00384       p->app_sleep_cond = 1;
00385       p->group = group;
00386       p->pending = pending;
00387       p->inherited_devicestate = -1;
00388       AST_LIST_INSERT_TAIL(&agents, p, list);
00389    }
00390    
00391    ast_copy_string(p->password, password ? password : "", sizeof(p->password));
00392    ast_copy_string(p->name, name ? name : "", sizeof(p->name));
00393    ast_copy_string(p->moh, moh, sizeof(p->moh));
00394    p->ackcall = ackcall;
00395    p->autologoff = autologoff;
00396 
00397    /* If someone reduces the wrapuptime and reloads, we want it
00398     * to change the wrapuptime immediately on all calls */
00399    if (p->wrapuptime > wrapuptime) {
00400       struct timeval now = ast_tvnow();
00401       /* XXX check what is this exactly */
00402 
00403       /* We won't be pedantic and check the tv_usec val */
00404       if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
00405          p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
00406          p->lastdisc.tv_usec = now.tv_usec;
00407       }
00408    }
00409    p->wrapuptime = wrapuptime;
00410 
00411    if (pending)
00412       p->dead = 1;
00413    else
00414       p->dead = 0;
00415    return p;
00416 }

static int agent_ack_sleep ( void *  data  )  [static]

Definition at line 963 of file chan_agent.c.

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

Referenced by __login_exec().

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

static int agent_answer ( struct ast_channel ast  )  [static]

Definition at line 444 of file chan_agent.c.

References ast_log(), and LOG_WARNING.

00445 {
00446    ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
00447    return -1;
00448 }

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

Definition at line 1004 of file chan_agent.c.

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

01005 {
01006    struct agent_pvt *p = bridge->tech_pvt;
01007    struct ast_channel *ret = NULL;
01008 
01009    if (p) {
01010       if (chan == p->chan)
01011          ret = bridge->_bridge;
01012       else if (chan == bridge->_bridge)
01013          ret = p->chan;
01014    }
01015 
01016    if (option_debug)
01017       ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
01018    return ret;
01019 }

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

Definition at line 699 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_device_state_changed(), ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_callerid(), ast_set_read_format(), ast_set_write_format(), ast_setstate(), AST_STATE_DIALING, AST_STATE_RINGING, AST_STATE_UP, ast_streamfile(), ast_strlen_zero(), ast_verbose(), ast_waitstream(), agent_pvt::chan, ast_channel::cid, ast_callerid::cid_name, ast_callerid::cid_num, CLEANUP, agent_pvt::inherited_devicestate, 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.

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

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

00425 {
00426    struct ast_channel *chan = p->owner;
00427    p->owner = NULL;
00428    chan->tech_pvt = NULL;
00429    p->app_sleep_cond = 1;
00430    /* Release ownership of the agent to other threads (presumably running the login app). */
00431    ast_mutex_unlock(&p->app_lock);
00432    if (chan)
00433       ast_channel_free(chan);
00434    if (p->dead) {
00435       ast_mutex_destroy(&p->lock);
00436       ast_mutex_destroy(&p->app_lock);
00437       free(p);
00438         }
00439    return 0;
00440 }

static int agent_cont_sleep ( void *  data  )  [static]

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

00943 {
00944    struct agent_pvt *p;
00945    int res;
00946 
00947    p = (struct agent_pvt *)data;
00948 
00949    ast_mutex_lock(&p->lock);
00950    res = p->app_sleep_cond;
00951    if (p->lastdisc.tv_sec) {
00952       if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
00953          res = 1;
00954    }
00955    ast_mutex_unlock(&p->lock);
00956 
00957    if(option_debug > 4 && !res )
00958       ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
00959 
00960    return res;
00961 }

static int agent_devicestate ( void *  data  )  [static]

Part of PBX channel interface.

Definition at line 2633 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::inherited_devicestate, agent_pvt::lock, agent_pvt::loginchan, agent_pvt::owner, agent_pvt::pending, and s.

02634 {
02635    struct agent_pvt *p;
02636    char *s;
02637    ast_group_t groupmatch;
02638    int groupoff;
02639    int waitforagent=0;
02640    int res = AST_DEVICE_INVALID;
02641    
02642    s = data;
02643    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
02644       groupmatch = (1 << groupoff);
02645    else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
02646       groupmatch = (1 << groupoff);
02647       waitforagent = 1;
02648    } else 
02649       groupmatch = 0;
02650 
02651    /* Check actual logged in agents first */
02652    AST_LIST_LOCK(&agents);
02653    AST_LIST_TRAVERSE(&agents, p, list) {
02654       ast_mutex_lock(&p->lock);
02655       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
02656          if (p->owner) {
02657             if (res != AST_DEVICE_INUSE)
02658                res = AST_DEVICE_BUSY;
02659          } else if (p->inherited_devicestate > -1) {
02660             res = p->inherited_devicestate;
02661          } else {
02662             if (res == AST_DEVICE_BUSY)
02663                res = AST_DEVICE_INUSE;
02664             if (p->chan || !ast_strlen_zero(p->loginchan)) {
02665                if (res == AST_DEVICE_INVALID)
02666                   res = AST_DEVICE_UNKNOWN;
02667             } else if (res == AST_DEVICE_INVALID)  
02668                res = AST_DEVICE_UNAVAILABLE;
02669          }
02670          if (!strcmp(data, p->agent)) {
02671             ast_mutex_unlock(&p->lock);
02672             break;
02673          }
02674       }
02675       ast_mutex_unlock(&p->lock);
02676    }
02677    AST_LIST_UNLOCK(&agents);
02678    return res;
02679 }

static int agent_devicestate_cb ( const char *  dev,
int  state,
void *  data 
) [static]

Definition at line 286 of file chan_agent.c.

References agent_pvt::agent, AST_CHANNEL_NAME, ast_device_state_changed(), AST_LIST_TRAVERSE, AST_LIST_TRYLOCK, AST_LIST_UNLOCK, ast_mutex_lock(), ast_mutex_unlock(), agent_pvt::chan, agent_pvt::inherited_devicestate, and agent_pvt::lock.

Referenced by load_module(), and unload_module().

00287 {
00288    int res, i;
00289    struct agent_pvt *p;
00290    char basename[AST_CHANNEL_NAME], *tmp;
00291 
00292    /* Skip Agent status */
00293    if (!strncasecmp(dev, "Agent/", 6)) {
00294       return 0;
00295    }
00296 
00297    /* Try to be safe, but don't deadlock */
00298    for (i = 0; i < 10; i++) {
00299       if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
00300          break;
00301       }
00302    }
00303    if (res) {
00304       return -1;
00305    }
00306 
00307    AST_LIST_TRAVERSE(&agents, p, list) {
00308       ast_mutex_lock(&p->lock);
00309       if (p->chan) {
00310          ast_copy_string(basename, p->chan->name, sizeof(basename));
00311          if ((tmp = strrchr(basename, '-'))) {
00312             *tmp = '\0';
00313          }
00314          if (strcasecmp(p->chan->name, dev) == 0 || strcasecmp(basename, dev) == 0) {
00315             p->inherited_devicestate = state;
00316             ast_device_state_changed("Agent/%s", p->agent);
00317          }
00318       }
00319       ast_mutex_unlock(&p->lock);
00320    }
00321    AST_LIST_UNLOCK(&agents);
00322    return 0;
00323 }

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

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

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

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

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

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

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

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

00651 {
00652    struct agent_pvt *p = newchan->tech_pvt;
00653    ast_mutex_lock(&p->lock);
00654    if (p->owner != oldchan) {
00655       ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
00656       ast_mutex_unlock(&p->lock);
00657       return -1;
00658    }
00659    p->owner = newchan;
00660    ast_mutex_unlock(&p->lock);
00661    return 0;
00662 }

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

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

Definition at line 796 of file chan_agent.c.

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

00797 {
00798    struct agent_pvt *p = NULL;
00799    struct ast_channel *base = chan;
00800 
00801    /* chan is locked by the calling function */
00802    if (!chan || !chan->tech_pvt) {
00803       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);
00804       return NULL;
00805    }
00806    p = chan->tech_pvt;
00807    if (p->chan) 
00808       base = p->chan;
00809    return base;
00810 }

static int agent_hangup ( struct ast_channel ast  )  [static]

Definition at line 829 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::inherited_devicestate, 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.

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

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

Definition at line 664 of file chan_agent.c.

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

00665 {
00666    struct agent_pvt *p = ast->tech_pvt;
00667    int res = -1;
00668    ast_mutex_lock(&p->lock);
00669    if (p->chan && !ast_check_hangup(p->chan))
00670       res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
00671    else
00672       res = 0;
00673    ast_mutex_unlock(&p->lock);
00674    return res;
00675 }

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

Definition at line 1634 of file chan_agent.c.

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

Referenced by action_agent_logoff(), and agent_logoff_cmd().

01635 {
01636    struct agent_pvt *p;
01637    long logintime;
01638    int ret = -1; /* Return -1 if no agent if found */
01639 
01640    AST_LIST_LOCK(&agents);
01641    AST_LIST_TRAVERSE(&agents, p, list) {
01642       if (!strcasecmp(p->agent, agent)) {
01643          ret = 0;
01644          if (p->owner || p->chan) {
01645             if (!soft) {
01646                ast_mutex_lock(&p->lock);
01647 
01648                while (p->owner && ast_channel_trylock(p->owner)) {
01649                   DEADLOCK_AVOIDANCE(&p->lock);
01650                }
01651                if (p->owner) {
01652                   ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
01653                   ast_channel_unlock(p->owner);
01654                }
01655 
01656                while (p->chan && ast_channel_trylock(p->chan)) {
01657                   DEADLOCK_AVOIDANCE(&p->lock);
01658                }
01659                if (p->chan) {
01660                   ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
01661                   ast_channel_unlock(p->chan);
01662                }
01663 
01664                ast_mutex_unlock(&p->lock);
01665             } else
01666                p->deferlogoff = 1;
01667          } else {
01668             logintime = time(NULL) - p->loginstart;
01669             p->loginstart = 0;
01670             agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
01671          }
01672          break;
01673       }
01674    }
01675    AST_LIST_UNLOCK(&agents);
01676 
01677    return ret;
01678 }

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

Definition at line 1680 of file chan_agent.c.

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

01681 {
01682    int ret;
01683    char *agent;
01684 
01685    if (argc < 3 || argc > 4)
01686       return RESULT_SHOWUSAGE;
01687    if (argc == 4 && strcasecmp(argv[3], "soft"))
01688       return RESULT_SHOWUSAGE;
01689 
01690    agent = argv[2] + 6;
01691    ret = agent_logoff(agent, argc == 4);
01692    if (ret == 0)
01693       ast_cli(fd, "Logging out %s\n", agent);
01694 
01695    return RESULT_SUCCESS;
01696 }

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

Definition at line 1594 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::inherited_devicestate, agent_pvt::logincallerid, agent_pvt::loginchan, manager_event(), and set_agentbycallerid().

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

01595 {
01596    char *tmp = NULL;
01597    char agent[AST_MAX_AGENT];
01598 
01599    if (!ast_strlen_zero(logcommand))
01600       tmp = logcommand;
01601    else
01602       tmp = ast_strdupa("");
01603 
01604    snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
01605 
01606    if (!ast_strlen_zero(uniqueid)) {
01607       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01608             "Agent: %s\r\n"
01609             "Reason: %s\r\n"
01610             "Loginchan: %s\r\n"
01611             "Logintime: %ld\r\n"
01612             "Uniqueid: %s\r\n", 
01613             p->agent, tmp, loginchan, logintime, uniqueid);
01614    } else {
01615       manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
01616             "Agent: %s\r\n"
01617             "Reason: %s\r\n"
01618             "Loginchan: %s\r\n"
01619             "Logintime: %ld\r\n",
01620             p->agent, tmp, loginchan, logintime);
01621    }
01622 
01623    ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
01624    set_agentbycallerid(p->logincallerid, NULL);
01625    p->loginchan[0] ='\0';
01626    p->logincallerid[0] = '\0';
01627    p->inherited_devicestate = -1;
01628    ast_device_state_changed("Agent/%s", p->agent);
01629    if (persistent_agents)
01630       dump_agents(); 
01631 
01632 }

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

Create new agent channel.

Definition at line 1022 of file chan_agent.c.

References agent_pvt::agent, agent_tech, agent_pvt::app_lock, agent_pvt::app_sleep_cond, ast_assert, 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, 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().

01023 {
01024    struct ast_channel *tmp;
01025 #if 0
01026    if (!p->chan) {
01027       ast_log(LOG_WARNING, "No channel? :(\n");
01028       return NULL;
01029    }
01030 #endif   
01031    if (p->pending)
01032       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);
01033    else
01034       tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
01035    if (!tmp) {
01036       ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
01037       return NULL;
01038    }
01039 
01040    tmp->tech = &agent_tech;
01041    if (p->chan) {
01042       tmp->nativeformats = p->chan->nativeformats;
01043       tmp->writeformat = p->chan->writeformat;
01044       tmp->rawwriteformat = p->chan->writeformat;
01045       tmp->readformat = p->chan->readformat;
01046       tmp->rawreadformat = p->chan->readformat;
01047       ast_string_field_set(tmp, language, p->chan->language);
01048       ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
01049       ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
01050       /* XXX Is this really all we copy form the originating channel?? */
01051    } else {
01052       tmp->nativeformats = AST_FORMAT_SLINEAR;
01053       tmp->writeformat = AST_FORMAT_SLINEAR;
01054       tmp->rawwriteformat = AST_FORMAT_SLINEAR;
01055       tmp->readformat = AST_FORMAT_SLINEAR;
01056       tmp->rawreadformat = AST_FORMAT_SLINEAR;
01057    }
01058    /* Safe, agentlock already held */
01059    tmp->tech_pvt = p;
01060    p->owner = tmp;
01061    /* XXX: this needs fixing */
01062 #if 0
01063    ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
01064 #endif
01065    ast_update_use_count();
01066    tmp->priority = 1;
01067    /* Wake up and wait for other applications (by definition the login app)
01068     * to release this channel). Takes ownership of the agent channel
01069     * to this thread only.
01070     * For signalling the other thread, ast_queue_frame is used until we
01071     * can safely use signals for this purpose. The pselect() needs to be
01072     * implemented in the kernel for this.
01073     */
01074    p->app_sleep_cond = 0;
01075    if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
01076       if (p->chan) {
01077          ast_queue_frame(p->chan, &ast_null_frame);
01078          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01079          ast_mutex_lock(&p->app_lock);
01080          ast_mutex_lock(&p->lock);
01081       } else {
01082          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01083          p->owner = NULL;
01084          tmp->tech_pvt = NULL;
01085          p->app_sleep_cond = 1;
01086          ast_channel_free( tmp );
01087          ast_mutex_unlock(&p->lock);   /* For other thread to read the condition. */
01088          ast_mutex_unlock(&p->app_lock);
01089          return NULL;
01090       }
01091    } else if (!ast_strlen_zero(p->loginchan)) {
01092       if (p->chan)
01093          ast_queue_frame(p->chan, &ast_null_frame);
01094       if (!p->chan) {
01095          ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
01096          p->owner = NULL;
01097          tmp->tech_pvt = NULL;
01098          p->app_sleep_cond = 1;
01099          ast_channel_free( tmp );
01100          ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
01101          return NULL;
01102       }  
01103    } 
01104    if (p->chan)
01105       ast_indicate(p->chan, AST_CONTROL_UNHOLD);
01106    p->owning_app = pthread_self();
01107    /* After the above step, there should not be any blockers. */
01108    if (p->chan) {
01109       if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
01110          ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
01111          ast_assert(ast_test_flag(p->chan, AST_FLAG_BLOCKING) == 0);
01112       }
01113    }
01114    return tmp;
01115 }

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

Definition at line 483 of file chan_agent.c.

References ast_channel::_bridge, ast_channel::_state, agent_pvt::ackcall, agent_pvt::acknowledged, agent_pvt::agent, agent_logoff_maintenance(), agent_start_monitoring(), AST_AGENT_FD, AST_CONTROL_ANSWER, ast_copy_flags, ast_device_state_changed(), AST_FLAG_EXCEPTION, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_hangup(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_null_frame, ast_read(), AST_STATE_UP, ast_strlen_zero(), AST_TIMING_FD, ast_tvadd(), ast_verbose(), agent_pvt::autologoff, agent_pvt::chan, CHECK_FORMATS, CLEANUP, dump_agents(), f, ast_channel::fdno, agent_pvt::inherited_devicestate, agent_pvt::lastdisc, agent_pvt::lock, LOG_DEBUG, LOG_NOTICE, agent_pvt::loginchan, agent_pvt::loginstart, agent_pvt::name, option_verbose, agent_pvt::owner, pbx_builtin_getvar_helper(), agent_pvt::start, ast_channel::tech, ast_channel::tech_pvt, ast_channel_tech::type, VERBOSE_PREFIX_3, and agent_pvt::wrapuptime.

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

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

Part of the Asterisk PBX interface.

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

01407 {
01408    struct agent_pvt *p;
01409    struct ast_channel *chan = NULL;
01410    char *s;
01411    ast_group_t groupmatch;
01412    int groupoff;
01413    int waitforagent=0;
01414    int hasagent = 0;
01415    struct timeval tv;
01416 
01417    s = data;
01418    if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01419       groupmatch = (1 << groupoff);
01420    } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
01421       groupmatch = (1 << groupoff);
01422       waitforagent = 1;
01423    } else 
01424       groupmatch = 0;
01425 
01426    /* Check actual logged in agents first */
01427    AST_LIST_LOCK(&agents);
01428    AST_LIST_TRAVERSE(&agents, p, list) {
01429       ast_mutex_lock(&p->lock);
01430       if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
01431           ast_strlen_zero(p->loginchan)) {
01432          if (p->chan)
01433             hasagent++;
01434          tv = ast_tvnow();
01435          if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01436             p->lastdisc = ast_tv(0, 0);
01437             /* Agent must be registered, but not have any active call, and not be in a waiting state */
01438             if (!p->owner && p->chan) {
01439                /* Fixed agent */
01440                chan = agent_new(p, AST_STATE_DOWN);
01441             }
01442             if (chan) {
01443                ast_mutex_unlock(&p->lock);
01444                break;
01445             }
01446          }
01447       }
01448       ast_mutex_unlock(&p->lock);
01449    }
01450    if (!p) {
01451       AST_LIST_TRAVERSE(&agents, p, list) {
01452          ast_mutex_lock(&p->lock);
01453          if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
01454             if (p->chan || !ast_strlen_zero(p->loginchan))
01455                hasagent++;
01456             tv = ast_tvnow();
01457 #if 0
01458             ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
01459 #endif
01460             if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
01461                p->lastdisc = ast_tv(0, 0);
01462                /* Agent must be registered, but not have any active call, and not be in a waiting state */
01463                if (!p->owner && p->chan) {
01464                   /* Could still get a fixed agent */
01465                   chan = agent_new(p, AST_STATE_DOWN);
01466                } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
01467                   /* Adjustable agent */
01468                   p->chan = ast_request("Local", format, p->loginchan, cause);
01469                   if (p->chan)
01470                      chan = agent_new(p, AST_STATE_DOWN);
01471                }
01472                if (chan) {
01473                   ast_mutex_unlock(&p->lock);
01474                   break;
01475                }
01476             }
01477          }
01478          ast_mutex_unlock(&p->lock);
01479       }
01480    }
01481 
01482    if (!chan && waitforagent) {
01483       /* No agent available -- but we're requesting to wait for one.
01484          Allocate a place holder */
01485       if (hasagent) {
01486          if (option_debug)
01487             ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
01488          p = add_agent(data, 1);
01489          p->group = groupmatch;
01490          chan = agent_new(p, AST_STATE_DOWN);
01491          if (!chan) 
01492             ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
01493       } else
01494          ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
01495    }
01496    *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
01497    AST_LIST_UNLOCK(&agents);
01498    return chan;
01499 }

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

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

00604 {
00605    struct agent_pvt *p = ast->tech_pvt;
00606    int res = -1;
00607    ast_mutex_lock(&p->lock);
00608    if (p->chan) 
00609       res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
00610    ast_mutex_unlock(&p->lock);
00611    return res;
00612 }

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

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

00615 {
00616    struct agent_pvt *p = ast->tech_pvt;
00617    int res = -1;
00618    ast_mutex_lock(&p->lock);
00619    if (p->chan) 
00620       res = ast_sendtext(p->chan, text);
00621    ast_mutex_unlock(&p->lock);
00622    return res;
00623 }

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

Definition at line 812 of file chan_agent.c.

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

00813 {
00814    struct agent_pvt *p = NULL;
00815    
00816    if (!chan || !base) {
00817       ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
00818       return -1;
00819    }
00820    p = chan->tech_pvt;
00821    if (!p) {
00822       ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
00823       return -1;
00824    }
00825    p->chan = base;
00826    return 0;
00827 }

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

Definition at line 478 of file chan_agent.c.

References __agent_start_monitoring(), and ast_channel::tech_pvt.

Referenced by agent_call(), and agent_read().

00479 {
00480    return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
00481 }

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

Definition at line 625 of file chan_agent.c.

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

00626 {
00627    struct agent_pvt *p = ast->tech_pvt;
00628    int res = -1;
00629    CHECK_FORMATS(ast, p);
00630    ast_mutex_lock(&p->lock);
00631    if (!p->chan) 
00632       res = 0;
00633    else {
00634       if ((f->frametype != AST_FRAME_VOICE) ||
00635           (f->frametype != AST_FRAME_VIDEO) ||
00636           (f->subclass == p->chan->writeformat)) {
00637          res = ast_write(p->chan, f);
00638       } else {
00639          ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
00640             f->frametype == AST_FRAME_VOICE ? "audio" : "video",
00641             ast->name, p->chan->name);
00642          res = 0;
00643       }
00644    }
00645    CLEANUP(ast, p);
00646    ast_mutex_unlock(&p->lock);
00647    return res;
00648 }

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

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

Referenced by load_module().

02498 {
02499    int exitifnoagentid = 0;
02500    int nowarnings = 0;
02501    int changeoutgoing = 0;
02502    int res = 0;
02503    char agent[AST_MAX_AGENT];
02504 
02505    if (data) {
02506       if (strchr(data, 'd'))
02507          exitifnoagentid = 1;
02508       if (strchr(data, 'n'))
02509          nowarnings = 1;
02510       if (strchr(data, 'c'))
02511          changeoutgoing = 1;
02512    }
02513    if (chan->cid.cid_num) {
02514       const char *tmp;
02515       char agentvar[AST_MAX_BUF];
02516       snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
02517       if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
02518          struct agent_pvt *p;
02519          ast_copy_string(agent, tmp, sizeof(agent));
02520          AST_LIST_LOCK(&agents);
02521          AST_LIST_TRAVERSE(&agents, p, list) {
02522             if (!strcasecmp(p->agent, tmp)) {
02523                if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
02524                __agent_start_monitoring(chan, p, 1);
02525                break;
02526             }
02527          }
02528          AST_LIST_UNLOCK(&agents);
02529          
02530       } else {
02531          res = -1;
02532          if (!nowarnings)
02533             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);
02534       }
02535    } else {
02536       res = -1;
02537       if (!nowarnings)
02538          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");
02539    }
02540    /* check if there is n + 101 priority */
02541    /*! \todo XXX Needs to check option priorityjump etc etc */
02542    if (res) {
02543       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
02544          chan->priority+=100;
02545          if (option_verbose > 2)
02546             ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
02547       } else if (exitifnoagentid)
02548          return res;
02549    }
02550    return 0;
02551 }

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

01756 {
01757    struct agent_pvt *p;
01758    char username[AST_MAX_BUF];
01759    char location[AST_MAX_BUF] = "";
01760    char talkingto[AST_MAX_BUF] = "";
01761    char moh[AST_MAX_BUF];
01762    int count_agents = 0;      /*!< Number of agents configured */
01763    int online_agents = 0;     /*!< Number of online agents */
01764    int offline_agents = 0;    /*!< Number of offline agents */
01765    if (argc != 2)
01766       return RESULT_SHOWUSAGE;
01767    AST_LIST_LOCK(&agents);
01768    AST_LIST_TRAVERSE(&agents, p, list) {
01769       ast_mutex_lock(&p->lock);
01770       if (p->pending) {
01771          if (p->group)
01772             ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
01773          else
01774             ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
01775       } else {
01776          if (!ast_strlen_zero(p->name))
01777             snprintf(username, sizeof(username), "(%s) ", p->name);
01778          else
01779             username[0] = '\0';
01780          if (p->chan) {
01781             snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
01782             if (p->owner && ast_bridged_channel(p->owner))
01783                snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
01784              else 
01785                strcpy(talkingto, " is idle");
01786             online_agents++;
01787          } else if (!ast_strlen_zero(p->loginchan)) {
01788             if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
01789                snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
01790             else 
01791                snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
01792             talkingto[0] = '\0';
01793             online_agents++;
01794             if (p->acknowledged)
01795                strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
01796          } else {
01797             strcpy(location, "not logged in");
01798             talkingto[0] = '\0';
01799             offline_agents++;
01800          }
01801          if (!ast_strlen_zero(p->moh))
01802             snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
01803          ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
01804             username, location, talkingto, moh);
01805          count_agents++;
01806       }
01807       ast_mutex_unlock(&p->lock);
01808    }
01809    AST_LIST_UNLOCK(&agents);
01810    if ( !count_agents ) 
01811       ast_cli(fd, "No Agents are configured in %s\n",config);
01812    else 
01813       ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
01814    ast_cli(fd, "\n");
01815                    
01816    return RESULT_SUCCESS;
01817 }

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

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

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

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

Definition at line 1386 of file chan_agent.c.

References AST_LIST_TRAVERSE, agent_pvt::loginchan, and S_OR.

Referenced by __login_exec().

01387 {
01388    struct agent_pvt *p;
01389    char loginchan[80];
01390 
01391    if(multiplelogin)
01392       return 1;
01393    if(!chan) 
01394       return 0;
01395 
01396    snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
01397    
01398    AST_LIST_TRAVERSE(&agents, p, list) {
01399       if(!strcasecmp(chan, p->loginchan))
01400          return 0;
01401    }
01402    return -1;
01403 }

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

References ast_log(), depwarning, and LOG_WARNING.

Referenced by action_agent_callback_login(), and callback_exec().

02377 {
02378    static int depwarning = 0;
02379 
02380    if (!depwarning) {
02381       depwarning = 1;
02382 
02383       ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
02384       ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
02385       ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
02386    }
02387 }

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

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

Referenced by load_module().

02398 {
02399    callback_deprecated();
02400 
02401    return __login_exec(chan, data, 1);
02402 }

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

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

01273 {
01274    struct ast_channel *chan=NULL, *parent=NULL;
01275    struct agent_pvt *p;
01276    int res;
01277 
01278    if (option_debug)
01279       ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
01280    if (needlock)
01281       AST_LIST_LOCK(&agents);
01282    AST_LIST_TRAVERSE(&agents, p, list) {
01283       if (p == newlyavailable) {
01284          continue;
01285       }
01286       ast_mutex_lock(&p->lock);
01287       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01288          if (option_debug)
01289             ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01290          /* We found a pending call, time to merge */
01291          chan = agent_new(newlyavailable, AST_STATE_DOWN);
01292          parent = p->owner;
01293          p->abouttograb = 1;
01294          ast_mutex_unlock(&p->lock);
01295          break;
01296       }
01297       ast_mutex_unlock(&p->lock);
01298    }
01299    if (needlock)
01300       AST_LIST_UNLOCK(&agents);
01301    if (parent && chan)  {
01302       if (newlyavailable->ackcall > 1) {
01303          /* Don't do beep here */
01304          res = 0;
01305       } else {
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             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01314          }
01315       }
01316       if (!res) {
01317          /* Note -- parent may have disappeared */
01318          if (p->abouttograb) {
01319             newlyavailable->acknowledged = 1;
01320             /* Safe -- agent lock already held */
01321             ast_setstate(parent, AST_STATE_UP);
01322             ast_setstate(chan, AST_STATE_UP);
01323             ast_copy_string(parent->context, chan->context, sizeof(parent->context));
01324             /* Go ahead and mark the channel as a zombie so that masquerade will
01325                destroy it for us, and we need not call ast_hangup */
01326             ast_mutex_lock(&parent->lock);
01327             ast_set_flag(chan, AST_FLAG_ZOMBIE);
01328             ast_channel_masquerade(parent, chan);
01329             ast_mutex_unlock(&parent->lock);
01330             p->abouttograb = 0;
01331          } else {
01332             if (option_debug)
01333                ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
01334             agent_cleanup(newlyavailable);
01335          }
01336       } else {
01337          if (option_debug)
01338             ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
01339          agent_cleanup(newlyavailable);
01340       }
01341    }
01342    return 0;
01343 }

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

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

01346 {
01347    struct agent_pvt *p;
01348    int res=0;
01349 
01350    ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
01351    if (needlock)
01352       AST_LIST_LOCK(&agents);
01353    AST_LIST_TRAVERSE(&agents, p, list) {
01354       if (p == newlyavailable) {
01355          continue;
01356       }
01357       ast_mutex_lock(&p->lock);
01358       if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
01359          if (option_debug)
01360             ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
01361          ast_mutex_unlock(&p->lock);
01362          break;
01363       }
01364       ast_mutex_unlock(&p->lock);
01365    }
01366    if (needlock)
01367       AST_LIST_UNLOCK(&agents);
01368    if (p) {
01369       ast_mutex_unlock(&newlyavailable->lock);
01370       if (option_debug > 2)
01371          ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
01372       res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
01373       if (option_debug > 2)
01374          ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
01375       if (!res) {
01376          res = ast_waitstream(newlyavailable->chan, "");
01377          if (option_debug)
01378             ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
01379       }
01380       ast_mutex_lock(&newlyavailable->lock);
01381    }
01382    return res;
01383 }

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

Definition at line 1728 of file chan_agent.c.

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

01729 {
01730    char *ret = NULL;
01731 
01732    if (pos == 2) {
01733       struct agent_pvt *p;
01734       char name[AST_MAX_AGENT];
01735       int which = 0, len = strlen(word);
01736 
01737       AST_LIST_LOCK(&agents);
01738       AST_LIST_TRAVERSE(&agents, p, list) {
01739          snprintf(name, sizeof(name), "Agent/%s", p->agent);
01740          if (!strncasecmp(word, name, len) && ++which > state) {
01741             ret = ast_strdup(name);
01742             break;
01743          }
01744       }
01745       AST_LIST_UNLOCK(&agents);
01746    } else if (pos == 3 && state == 0) 
01747       return ast_strdup("soft");
01748    
01749    return ret;
01750 }

static void dump_agents ( void   )  [static]

Dump AgentCallbackLogin agents to the ASTdb database for persistence.

Definition at line 2556 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(), agent_logoff_maintenance(), and agent_read().

02557 {
02558    struct agent_pvt *cur_agent = NULL;
02559    char buf[256];
02560 
02561    AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02562       if (cur_agent->chan)
02563          continue;
02564 
02565       if (!ast_strlen_zero(cur_agent->loginchan)) {
02566          snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
02567          if (ast_db_put(pa_family, cur_agent->agent, buf))
02568             ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
02569          else if (option_debug)
02570             ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
02571       } else {
02572          /* Delete -  no agent or there is an error */
02573          ast_db_del(pa_family, cur_agent->agent);
02574       }
02575    }
02576 }

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

Note:
This function expects the agent list to be locked

Definition at line 2684 of file chan_agent.c.

References agent_pvt::agent, and AST_LIST_TRAVERSE.

Referenced by function_agent().

02685 {
02686    struct agent_pvt *cur;
02687 
02688    AST_LIST_TRAVERSE(&agents, cur, list) {
02689       if (!strcmp(cur->agent, agentid))
02690          break;   
02691    }
02692 
02693    return cur; 
02694 }

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

Definition at line 2696 of file chan_agent.c.

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

02697 {
02698    char *parse;    
02699    AST_DECLARE_APP_ARGS(args,
02700       AST_APP_ARG(agentid);
02701       AST_APP_ARG(item);
02702    );
02703    char *tmp;
02704    struct agent_pvt *agent;
02705 
02706    buf[0] = '\0';
02707 
02708    if (ast_strlen_zero(data)) {
02709       ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
02710       return -1;
02711    }
02712 
02713    parse = ast_strdupa(data);
02714 
02715    AST_NONSTANDARD_APP_ARGS(args, parse, ':');
02716    if (!args.item)
02717       args.item = "status";
02718 
02719    AST_LIST_LOCK(&agents);
02720 
02721    if (!(agent = find_agent(args.agentid))) {
02722       AST_LIST_UNLOCK(&agents);
02723       ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
02724       return -1;
02725    }
02726 
02727    if (!strcasecmp(args.item, "status")) {
02728       char *status = "LOGGEDOUT";
02729       if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
02730          status = "LOGGEDIN"; 
02731       ast_copy_string(buf, status, len);
02732    } else if (!strcasecmp(args.item, "password")) 
02733       ast_copy_string(buf, agent->password, len);
02734    else if (!strcasecmp(args.item, "name"))
02735       ast_copy_string(buf, agent->name, len);
02736    else if (!strcasecmp(args.item, "mohclass"))
02737       ast_copy_string(buf, agent->moh, len);
02738    else if (!strcasecmp(args.item, "channel")) {
02739       if (agent->chan) {
02740          ast_copy_string(buf, agent->chan->name, len);
02741          tmp = strrchr(buf, '-');
02742          if (tmp)
02743             *tmp = '\0';
02744       } 
02745    } else if (!strcasecmp(args.item, "exten"))
02746       ast_copy_string(buf, agent->loginchan, len); 
02747 
02748    AST_LIST_UNLOCK(&agents);
02749 
02750    return 0;
02751 }

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

References action_agent_callback_login(), action_agent_logoff(), action_agents(), agent_devicestate_cb(), agent_function, agent_tech, agentmonitoroutgoing_exec(), ast_channel_register(), ast_cli_register_multiple(), ast_custom_function_register(), ast_devstate_add(), 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().

02777 {
02778    /* Make sure we can register our agent channel type */
02779    if (ast_channel_register(&agent_tech)) {
02780       ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
02781       return -1;
02782    }
02783    /* Read in the config */
02784    if (!read_agent_config())
02785       return AST_MODULE_LOAD_DECLINE;
02786    if (persistent_agents)
02787       reload_agents();
02788    /* Dialplan applications */
02789    ast_register_application(app, login_exec, synopsis, descrip);
02790    ast_register_application(app2, callback_exec, synopsis2, descrip2);
02791    ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
02792 
02793    /* Manager commands */
02794    ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
02795    ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
02796    ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
02797 
02798    /* CLI Commands */
02799    ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02800 
02801    /* Dialplan Functions */
02802    ast_custom_function_register(&agent_function);
02803 
02804    ast_devstate_add(agent_devicestate_cb, NULL);
02805 
02806    return 0;
02807 }

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

References __login_exec(), and ast_module_user::chan.

Referenced by load_module().

02372 {
02373    return __login_exec(chan, data, 0);
02374 }

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

Definition at line 1501 of file chan_agent.c.

01502 {
01503    int x = ffs(d);
01504 
01505    if (x)
01506       return x - 1;
01507 
01508    return 0;
01509 }

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

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

static int reload ( void   )  [static]

Definition at line 2809 of file chan_agent.c.

References read_agent_config(), and reload_agents().

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

02810 {
02811    read_agent_config();
02812    if (persistent_agents)
02813       reload_agents();
02814    return 0;
02815 }

static void reload_agents ( void   )  [static]

Reload the persistent agents from astdb.

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

02582 {
02583    char *agent_num;
02584    struct ast_db_entry *db_tree;
02585    struct ast_db_entry *entry;
02586    struct agent_pvt *cur_agent;
02587    char agent_data[256];
02588    char *parse;
02589    char *agent_chan;
02590    char *agent_callerid;
02591 
02592    db_tree = ast_db_gettree(pa_family, NULL);
02593 
02594    AST_LIST_LOCK(&agents);
02595    for (entry = db_tree; entry; entry = entry->next) {
02596       agent_num = entry->key + strlen(pa_family) + 2;
02597       AST_LIST_TRAVERSE(&agents, cur_agent, list) {
02598          ast_mutex_lock(&cur_agent->lock);
02599          if (strcmp(agent_num, cur_agent->agent) == 0)
02600             break;
02601          ast_mutex_unlock(&cur_agent->lock);
02602       }
02603       if (!cur_agent) {
02604          ast_db_del(pa_family, agent_num);
02605          continue;
02606       } else
02607          ast_mutex_unlock(&cur_agent->lock);
02608       if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
02609          if (option_debug)
02610             ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
02611          parse = agent_data;
02612          agent_chan = strsep(&parse, ";");
02613          agent_callerid = strsep(&parse, ";");
02614          ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
02615          if (agent_callerid) {
02616             ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
02617             set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
02618          } else
02619             cur_agent->logincallerid[0] = '\0';
02620          if (cur_agent->loginstart == 0)
02621             time(&cur_agent->loginstart);
02622          ast_device_state_changed("Agent/%s", cur_agent->agent);  
02623       }
02624    }
02625    AST_LIST_UNLOCK(&agents);
02626    if (db_tree) {
02627       ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
02628       ast_db_freetree(db_tree);
02629    }
02630 }

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

00784 {
00785    char buf[AST_MAX_BUF];
00786 
00787    /* if there is no Caller ID, nothing to do */
00788    if (ast_strlen_zero(callerid))
00789       return;
00790 
00791    snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
00792    pbx_builtin_setvar_helper(NULL, buf, agent);
00793 }

static int unload_module ( void   )  [static]

Definition at line 2817 of file chan_agent.c.

References agent_devicestate_cb(), agent_function, agent_tech, ast_channel_unregister(), ast_cli_unregister_multiple(), ast_custom_function_unregister(), ast_devstate_del(), 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().

02818 {
02819    struct agent_pvt *p;
02820    /* First, take us out of the channel loop */
02821    ast_channel_unregister(&agent_tech);
02822    /* Delete devicestate subscription */
02823    ast_devstate_del(agent_devicestate_cb, NULL);
02824    /* Unregister dialplan functions */
02825    ast_custom_function_unregister(&agent_function);   
02826    /* Unregister CLI commands */
02827    ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
02828    /* Unregister dialplan applications */
02829    ast_unregister_application(app);
02830    ast_unregister_application(app2);
02831    ast_unregister_application(app3);
02832    /* Unregister manager command */
02833    ast_manager_unregister("Agents");
02834    ast_manager_unregister("AgentLogoff");
02835    ast_manager_unregister("AgentCallbackLogin");
02836    /* Unregister channel */
02837    AST_LIST_LOCK(&agents);
02838    /* Hangup all interfaces if they have an owner */
02839    while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
02840       if (p->owner)
02841          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
02842       free(p);
02843    }
02844    AST_LIST_UNLOCK(&agents);
02845    return 0;
02846 }


Variable Documentation

int ackcall [static]

Definition at line 159 of file chan_agent.c.

struct ast_custom_function agent_function

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

struct ast_channel_tech agent_tech [static]

Channel interface description for PBX integration.

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

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

Definition at line 82 of file chan_agent.c.

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

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

Definition at line 83 of file chan_agent.c.

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

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

Definition at line 84 of file chan_agent.c.

Referenced by load_module(), and unload_module().

int autologoff [static]

Definition at line 157 of file chan_agent.c.

int autologoffunavail = 0 [static]

Definition at line 162 of file chan_agent.c.

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

Definition at line 173 of file chan_agent.c.

struct ast_cli_entry cli_agents[] [static]

Definition at line 1897 of file chan_agent.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_show_agents_deprecated [static]

Initial value:

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

Definition at line 1887 of file chan_agent.c.

struct ast_cli_entry cli_show_agents_online_deprecated [static]

Initial value:

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

Definition at line 1892 of file chan_agent.c.

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

Definition at line 80 of file chan_agent.c.

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

const char descrip[] [static]

Definition at line 90 of file chan_agent.c.

Referenced by aji_handle_presence(), and load_module().

const char descrip2[] [static]

Definition at line 99 of file chan_agent.c.

Referenced by load_module().

const char descrip3[] [static]

Definition at line 107 of file chan_agent.c.

int endcall [static]

Definition at line 160 of file chan_agent.c.

ast_group_t group [static]

Definition at line 156 of file chan_agent.c.

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

const char mandescr_agent_callback_login[] [static]

Definition at line 135 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 129 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 125 of file chan_agent.c.

int maxlogintries = 3 [static]

Definition at line 164 of file chan_agent.c.

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

Definition at line 144 of file chan_agent.c.

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

int multiplelogin = 1 [static]

Definition at line 161 of file chan_agent.c.

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

Persistent Agents astdb family

Definition at line 150 of file chan_agent.c.

int persistent_agents = 0 [static]

queues.conf [general] option

Definition at line 153 of file chan_agent.c.

int recordagentcalls = 0 [static]

Definition at line 167 of file chan_agent.c.

char recordformat[AST_MAX_BUF] = "" [static]

Definition at line 168 of file chan_agent.c.

char recordformatext[AST_MAX_BUF] = "" [static]

Definition at line 169 of file chan_agent.c.

char savecallsin[AST_MAX_BUF] = "" [static]

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

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

Definition at line 86 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 87 of file chan_agent.c.

Referenced by load_module().

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

Definition at line 88 of file chan_agent.c.

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

Definition at line 79 of file chan_agent.c.

int updatecdr = 0 [static]

Definition at line 172 of file chan_agent.c.

char urlprefix[AST_MAX_BUF] = "" [static]

Definition at line 170 of file chan_agent.c.

Referenced by start_monitor_exec().

int wrapuptime [static]

Definition at line 158 of file chan_agent.c.


Generated on Mon Nov 24 15:34:27 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7